Completed
Pull Request — develop (#29)
by
unknown
03:34 queued 01:33
created

BaseRepository::skipCache()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 6
rs 9.4285
cc 1
eloc 3
nc 1
nop 0
1
<?php
2
3
/*
4
 * NOTICE OF LICENSE
5
 *
6
 * Part of the Rinvex Repository Package.
7
 *
8
 * This source file is subject to The MIT License (MIT)
9
 * that is bundled with this package in the LICENSE file.
10
 *
11
 * Package: Rinvex Repository Package
12
 * License: The MIT License (MIT)
13
 * Link:    https://rinvex.com
14
 */
15
16
namespace Rinvex\Repository\Repositories;
17
18
use Closure;
19
use Illuminate\Contracts\Container\Container;
20
use Rinvex\Repository\Contracts\RepositoryContract;
21
22
abstract class BaseRepository implements RepositoryContract
23
{
24
    /**
25
     * The IoC container instance.
26
     *
27
     * @var \Illuminate\Contracts\Container\Container
28
     */
29
    protected $container;
30
31
    /**
32
     * The repository model.
33
     *
34
     * @var object
35
     */
36
    protected $model;
37
38
    /**
39
     * The repository identifier.
40
     *
41
     * @var string
42
     */
43
    protected $repositoryId;
44
45
    /**
46
     * Indicate if the repository cache is enabled.
47
     *
48
     * @var bool
49
     */
50
    protected $cacheEnabled = true;
51
52
    /**
53
     * Indicate if the repository cache clear is enabled.
54
     *
55
     * @var bool
56
     */
57
    protected $cacheClearEnabled = true;
58
59
    /**
60
     * The repository cache lifetime.
61
     *
62
     * @var float|int
63
     */
64
    protected $cacheLifetime;
65
66
    /**
67
     * The repository cache driver.
68
     *
69
     * @var string
70
     */
71
    protected $cacheDriver;
72
73
    /**
74
     * Execute given callback and cache result set.
75
     *
76
     * @param string   $class
77
     * @param string   $method
78
     * @param array    $args
79
     * @param \Closure $closure
80
     *
81
     * @return mixed
82
     */
83
    protected function executeCallback($class, $method, $args, Closure $closure)
84
    {
85
        $driver   = $this->getCacheDriver();
86
        $lifetime = $this->getCacheLifetime();
87
        $hash     = md5(json_encode($args + [$driver, $lifetime, $this->model->toSql()]));
88
        $cacheKey = $class.'@'.$method.'.'.$hash;
89
90
        if ($driver) {
91
            // Switch cache driver on runtime
92
            $this->getContainer('cache')->setDefaultDriver($driver);
93
        }
94
95
        if ($this->isCacheable()) {
96
            if (method_exists($this->getContainer('cache')->getStore(), 'tags')) {
97
                return $lifetime === -1
98
                    ? $this->getContainer('cache')->tags($this->getRepositoryId())->rememberForever($cacheKey, $closure)
99
                    : $this->getContainer('cache')->tags($this->getRepositoryId())->remember($cacheKey, $lifetime, $closure);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 125 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
100
            }
101
102
            // Store cache keys by mimicking cache tags
103
            $this->storeCacheKeys($class, $method, $hash);
104
105
            return $lifetime === -1
106
                ? $this->getContainer('cache')->rememberForever($cacheKey, $closure)
107
                : $this->getContainer('cache')->remember($cacheKey, $lifetime, $closure);
108
        }
109
110
        return call_user_func($closure);
111
    }
112
113
    /**
114
     * Set the IoC container instance.
115
     *
116
     * @param \Illuminate\Contracts\Container\Container $container
117
     *
118
     * @return $this
119
     */
120
    public function setContainer(Container $container)
121
    {
122
        $this->container = $container;
123
124
        return $this;
125
    }
126
127
    /**
128
     * Get the IoC container instance or any of it's services.
129
     *
130
     * @param string|null $service
131
     *
132
     * @return mixed
133
     */
134
    public function getContainer($service = null)
135
    {
136
        return is_null($service) ? ($this->container ?: app()) : ($this->container[$service] ?: app($service));
137
    }
138
139
    /**
140
     * Set the repository identifier.
141
     *
142
     * @param string $repositoryId
143
     *
144
     * @return $this
145
     */
146
    public function setRepositoryId($repositoryId)
147
    {
148
        $this->repositoryId = $repositoryId;
149
150
        return $this;
151
    }
152
153
    /**
154
     * Get the repository identifier.
155
     *
156
     * @return string
157
     */
158
    public function getRepositoryId()
159
    {
160
        return $this->repositoryId ?: get_called_class();
161
    }
162
163
    /**
164
     * Set the repository cache lifetime.
165
     *
166
     * @param int $cacheLifetime
167
     *
168
     * @return $this
169
     */
170
    public function setCacheLifetime($cacheLifetime)
171
    {
172
        $this->cacheLifetime = $cacheLifetime;
173
174
        return $this;
175
    }
176
177
    /**
178
     * Get the repository cache lifetime.
179
     *
180
     * @return int
181
     */
182
    public function getCacheLifetime()
183
    {
184
        return ! is_null($this->cacheLifetime)
185
            ? $this->cacheLifetime
186
            : $this->getContainer('config')->get('rinvex.repository.cache.lifetime');
187
    }
188
189
    /**
190
     * Convenience method. Alias to setCacheLifetime(0).
191
     *
192
     * @return $this
193
     */
194
    public function skipCache()
195
    {
196
        $this->setCacheLifetime(0);
197
198
        return $this;
199
    }
200
201
    /**
202
     * Set the repository cache driver.
203
     *
204
     * @param string $cacheDriver
205
     *
206
     * @return $this
207
     */
208
    public function setCacheDriver($cacheDriver)
209
    {
210
        $this->cacheDriver = $cacheDriver;
211
212
        return $this;
213
    }
214
215
    /**
216
     * Get the repository cache driver.
217
     *
218
     * @return string
219
     */
220
    public function getCacheDriver()
221
    {
222
        return $this->cacheDriver;
223
    }
224
225
    /**
226
     * Enable repository cache.
227
     *
228
     * @param bool $status
229
     *
230
     * @return $this
231
     */
232
    public function enableCache($status = true)
233
    {
234
        $this->cacheEnabled = $status;
235
236
        return $this;
237
    }
238
239
    /**
240
     * Determine if repository cache is enabled.
241
     *
242
     * @return bool
243
     */
244
    public function isCacheEnabled()
245
    {
246
        return $this->cacheEnabled;
247
    }
248
249
    /**
250
     * Enable repository cache clear.
251
     *
252
     * @param bool $status
253
     *
254
     * @return $this
255
     */
256
    public function enableCacheClear($status = true)
257
    {
258
        $this->cacheClearEnabled = $status;
259
260
        return $this;
261
    }
262
263
    /**
264
     * Determine if repository cache clear is enabled.
265
     *
266
     * @return bool
267
     */
268
    public function isCacheClearEnabled()
269
    {
270
        return $this->cacheClearEnabled;
271
    }
272
273
    /**
274
     * Forget the repository cache.
275
     *
276
     * @return $this
277
     */
278
    public function forgetCache()
279
    {
280
        if ($this->isCacheEnabled() && $this->getCacheLifetime()) {
281
            if (method_exists($this->getContainer('cache')->getStore(), 'tags')) {
282
                $this->getContainer('cache')->tags($this->getRepositoryId())->flush();
283
            } else {
284
                // Flush cache keys by mimicking cache tags
285
                foreach ($this->flushCacheKeys() as $cacheKey) {
286
                    $this->getContainer('cache')->forget($cacheKey);
287
                }
288
            }
289
290
            $this->getContainer('events')->fire($this->getRepositoryId().'.entity.cache.flushed', [$this]);
291
        }
292
293
        return $this;
294
    }
295
296
    /**
297
     * Set the relationships that should be eager loaded.
298
     *
299
     * @param mixed $relations
300
     *
301
     * @return $this
302
     */
303
    public function with($relations)
304
    {
305
        $this->model = $this->model->with($relations);
306
307
        return $this;
308
    }
309
310
    /**
311
     * Add an "order by" clause to the repository.
312
     *
313
     * @param string $column
314
     * @param string $direction
315
     *
316
     * @return $this
317
     */
318
    public function orderBy($column, $direction = 'asc')
319
    {
320
        $this->model = $this->model->orderBy($column, $direction);
321
322
        return $this;
323
    }
324
325
    /**
326
     * Register a new global scope.
327
     *
328
     * @param \Illuminate\Database\Eloquent\Scope|\Closure|string $scope
329
     * @param \Closure|null                                       $implementation
330
     *
331
     * @throws \InvalidArgumentException
332
     *
333
     * @return mixed
334
     */
335
    public function addGlobalScope($scope, Closure $implementation = null)
336
    {
337
        return $this->model->addGlobalScope($scope, $implementation);
338
    }
339
340
    /**
341
     * Remove all or passed registered global scopes.
342
     *
343
     * @param array|null $scopes
344
     *
345
     * @return $this
346
     */
347
    public function withoutGlobalScopes(array $scopes = null)
348
    {
349
        $this->model = $this->model->withoutGlobalScopes($scopes);
350
351
        return $this;
352
    }
353
354
    /**
355
     * Dynamically pass missing static methods to the model.
356
     *
357
     * @param $method
358
     * @param $parameters
359
     *
360
     * @return mixed
361
     */
362
    public static function __callStatic($method, $parameters)
363
    {
364
        return call_user_func_array([new static(), $method], $parameters);
365
    }
366
367
    /**
368
     * Dynamically pass missing methods to the model.
369
     *
370
     * @param string $method
371
     * @param array  $parameters
372
     *
373
     * @return mixed
374
     */
375
    public function __call($method, $parameters)
376
    {
377
        $model = $this->model;
378
379
        return call_user_func_array([$model, $method], $parameters);
380
    }
381
382
    /**
383
     * Store cache keys by mimicking cache tags.
384
     *
385
     * @param string $class
386
     * @param string $method
387
     * @param string $hash
388
     *
389
     * @return void
390
     */
391
    protected function storeCacheKeys($class, $method, $hash)
392
    {
393
        $keysFile  = $this->getContainer('config')->get('rinvex.repository.cache.keys_file');
394
        $cacheKeys = $this->getCacheKeys($keysFile);
395
396
        if (! isset($cacheKeys[$class]) || ! in_array($method.'.'.$hash, $cacheKeys[$class])) {
397
            $cacheKeys[$class][] = $method.'.'.$hash;
398
            file_put_contents($keysFile, json_encode($cacheKeys));
399
        }
400
    }
401
402
    /**
403
     * Flush cache keys by mimicking cache tags.
404
     *
405
     * @return array
406
     */
407
    protected function flushCacheKeys()
408
    {
409
        $flushedKeys  = [];
410
        $calledClasss = get_called_class();
411
        $config       = $this->getContainer('config')->get('rinvex.repository.cache');
412
        $cacheKeys    = $this->getCacheKeys($config['keys_file']);
413
414
        if (isset($cacheKeys[$calledClasss]) && is_array($cacheKeys[$calledClasss])) {
415
            foreach ($cacheKeys[$calledClasss] as $cacheKey) {
416
                $flushedKeys[] = $calledClasss.'@'.$cacheKey;
417
            }
418
419
            unset($cacheKeys[$calledClasss]);
420
            file_put_contents($config['keys_file'], json_encode($cacheKeys));
421
        }
422
423
        return $flushedKeys;
424
    }
425
426
    /**
427
     * Get cache keys.
428
     *
429
     * @param string $file
430
     *
431
     * @return array
432
     */
433
    protected function getCacheKeys($file)
434
    {
435
        return json_decode(file_get_contents(file_exists($file) ? $file : file_put_contents($file, null)), true) ?: [];
436
    }
437
438
    /**
439
     * Determine if repository is cacheable.
440
     *
441
     * @return bool
442
     */
443
    protected function isCacheable()
444
    {
445
        $skipUri = $this->getContainer('config')->get('rinvex.repository.cache.skip_uri');
446
447
        return $this->isCacheEnabled() && $this->getCacheLifetime()
448
               && ! $this->getContainer('request')->has($skipUri);
449
    }
450
}
451