Completed
Push — master ( 4de4c2...6318cc )
by Abdelrahman
04:41 queued 02:39
created

BaseRepository::isCacheableMethod()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 7
rs 9.2
cc 4
eloc 5
nc 4
nop 2
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
     * Execute given callback and cache result set.
61
     *
62
     * @param string   $class
63
     * @param string   $method
64
     * @param string   $hash
65
     * @param \Closure $closure
66
     *
67
     * @return mixed
68
     */
69
    protected function executeCallback($class, $method, $hash, Closure $closure)
70
    {
71
        $cacheKey = $class.'@'.$method.'.'.$hash;
72
        $config   = $this->getContainer('config')->get('rinvex.repository.cache');
73
74
        if ($this->isCacheableMethod($config, $method)) {
75
            if (method_exists($this->getContainer('cache')->getStore(), 'tags')) {
76
                return $config['lifetime'] === -1
77
                    ? $this->getContainer('cache')->tags($this->getRepositoryId())->rememberForever($cacheKey, $closure)
78
                    : $this->getContainer('cache')->tags($this->getRepositoryId())->remember($cacheKey, $config['lifetime'], $closure);
79
            }
80
81
            // Store cache keys by mimicking cache tags
82
            $this->storeCacheKeys($class, $method, $hash, $config['keys_file']);
83
84
            return $config['lifetime'] === -1
85
                ? $this->getContainer('cache')->rememberForever($cacheKey, $closure)
86
                : $this->getContainer('cache')->remember($cacheKey, $config['lifetime'], $closure);
87
        }
88
89
        return call_user_func($closure);
90
    }
91
92
    /**
93
     * Set the IoC container instance.
94
     *
95
     * @param \Illuminate\Contracts\Container\Container $container
96
     *
97
     * @return $this
98
     */
99
    public function setContainer(Container $container)
100
    {
101
        $this->container = $container;
102
103
        return $this;
104
    }
105
106
    /**
107
     * Return the IoC container instance or any of it's services.
108
     *
109
     * @param string|null $service
110
     *
111
     * @return mixed
112
     */
113
    public function getContainer($service = null)
114
    {
115
        return is_null($service) ? ($this->container ?: app()) : ($this->container[$service] ?: app($service));
116
    }
117
118
    /**
119
     * Set the repository identifier.
120
     *
121
     * @param string $repositoryId
122
     *
123
     * @return $this
124
     */
125
    public function setRepositoryId($repositoryId)
126
    {
127
        $this->repositoryId = $repositoryId;
128
129
        return $this;
130
    }
131
132
    /**
133
     * Get the repository identifier.
134
     *
135
     * @return string
136
     */
137
    public function getRepositoryId()
138
    {
139
        return $this->repositoryId ?: get_called_class();
140
    }
141
142
    /**
143
     * Enable repository cache.
144
     *
145
     * @param bool $status
146
     *
147
     * @return $this
148
     */
149
    public function enableCache($status = true)
150
    {
151
        $this->cacheEnabled = $status;
152
153
        return $this;
154
    }
155
156
    /**
157
     * Determine if repository cache is enabled.
158
     *
159
     * @return bool
160
     */
161
    public function isCacheEnabled()
162
    {
163
        return $this->cacheEnabled;
164
    }
165
166
    /**
167
     * Enable repository cache clear.
168
     *
169
     * @param bool $status
170
     *
171
     * @return $this
172
     */
173
    public function enableCacheClear($status = true)
174
    {
175
        $this->cacheClearEnabled = $status;
176
177
        return $this;
178
    }
179
180
    /**
181
     * Determine if repository cache clear is enabled.
182
     *
183
     * @return bool
184
     */
185
    public function isCacheClearEnabled()
186
    {
187
        return $this->cacheClearEnabled;
188
    }
189
190
    /**
191
     * Forget the repository cache.
192
     *
193
     * @return $this
194
     */
195
    public function forgetCache()
196
    {
197
        $lifetime = $this->getContainer('config')->get('rinvex.repository.cache.lifetime');
198
199
        if ($this->cacheEnabled && $lifetime) {
200
            if (method_exists($this->getContainer('cache')->getStore(), 'tags')) {
201
                $this->getContainer('cache')->tags($this->getRepositoryId())->flush();
202
            } else {
203
                // Flush cache keys by mimicking cache tags
204
                foreach ($this->flushCacheKeys() as $cacheKey) {
205
                    $this->getContainer('cache')->forget($cacheKey);
206
                }
207
            }
208
209
            $this->getContainer('events')->fire($this->getRepositoryId().'.entity.cache.flushed', [$this]);
210
        }
211
212
        return $this;
213
    }
214
215
    /**
216
     * Set the relationships that should be eager loaded.
217
     *
218
     * @param mixed $relations
219
     *
220
     * @return $this
221
     */
222
    public function with($relations)
223
    {
224
        $this->model = $this->model->with($relations);
225
226
        return $this;
227
    }
228
229
    /**
230
     * Add an "order by" clause to the repository.
231
     *
232
     * @param string $column
233
     * @param string $direction
234
     *
235
     * @return $this
236
     */
237
    public function orderBy($column, $direction = 'asc')
238
    {
239
        $this->model = $this->model->orderBy($column, $direction);
240
241
        return $this;
242
    }
243
244
    /**
245
     * Register a new global scope.
246
     *
247
     * @param \Illuminate\Database\Eloquent\Scope|\Closure|string $scope
248
     * @param \Closure|null                                       $implementation
249
     *
250
     * @throws \InvalidArgumentException
251
     *
252
     * @return mixed
253
     */
254
    public function addGlobalScope($scope, Closure $implementation = null)
255
    {
256
        return $this->model->addGlobalScope($scope, $implementation);
257
    }
258
259
    /**
260
     * Remove all or passed registered global scopes.
261
     *
262
     * @param array|null $scopes
263
     *
264
     * @return $this
265
     */
266
    public function withoutGlobalScopes(array $scopes = null)
267
    {
268
        $this->model = $this->model->withoutGlobalScopes($scopes);
269
270
        return $this;
271
    }
272
273
    /**
274
     * Dynamically pass missing static methods to the model.
275
     *
276
     * @param $method
277
     * @param $parameters
278
     *
279
     * @return mixed
280
     */
281
    public static function __callStatic($method, $parameters)
282
    {
283
        return call_user_func_array([new static(), $method], $parameters);
284
    }
285
286
    /**
287
     * Dynamically pass missing methods to the model.
288
     *
289
     * @param string $method
290
     * @param array  $parameters
291
     *
292
     * @return mixed
293
     */
294
    public function __call($method, $parameters)
295
    {
296
        $model = $this->model;
297
298
        return call_user_func_array([$model, $method], $parameters);
299
    }
300
301
    /**
302
     * Store cache keys by mimicking cache tags.
303
     *
304
     * @param string $class
305
     * @param string $method
306
     * @param string $hash
307
     * @param string $file
308
     *
309
     * @return void
310
     */
311
    protected function storeCacheKeys($class, $method, $hash, $file)
312
    {
313
        $cacheKeys = $this->getCacheKeys($file);
314
315
        if (! isset($cacheKeys[$class]) || ! in_array($method.'.'.$hash, $cacheKeys[$class])) {
316
            $cacheKeys[$class][] = $method.'.'.$hash;
317
            file_put_contents($file, json_encode($cacheKeys));
318
        }
319
    }
320
321
    /**
322
     * Flush cache keys by mimicking cache tags.
323
     *
324
     * @return array
325
     */
326
    protected function flushCacheKeys()
327
    {
328
        $flushedKeys = [];
329
330
        $config    = $this->getContainer('config')->get('rinvex.repository.cache');
331
        $cacheKeys = $this->getCacheKeys($config['keys_file']);
332
333
        if (isset($cacheKeys[get_called_class()]) && is_array($cacheKeys[get_called_class()])) {
334
            foreach ($cacheKeys[get_called_class()] as $cacheKey) {
335
                $flushedKeys[] = $cacheKey;
336
            }
337
338
            unset($cacheKeys[get_called_class()]);
339
            file_put_contents($config['keys_file'], json_encode($cacheKeys));
340
        }
341
342
        return $flushedKeys;
343
    }
344
345
    /**
346
     * Get cache keys file.
347
     *
348
     * @param string $file
349
     *
350
     * @return array
351
     */
352
    protected function getCacheKeys($file)
353
    {
354
        return json_decode(file_get_contents(file_exists($file) ? $file : file_put_contents($file, null)), true) ?: [];
355
    }
356
357
    /**
358
     * Determine if repository method is cacheable.
359
     *
360
     * @param array  $config
361
     * @param string $method
362
     *
363
     * @return bool
364
     */
365
    protected function isCacheableMethod($config, $method)
366
    {
367
        return $this->cacheEnabled
368
               && $config['lifetime']
369
               && in_array($method, $config['methods'])
370
               && ! $this->getContainer('request')->has($config['skip_uri']);
371
    }
372
}
373