Completed
Push — master ( 2cb525...32e808 )
by Abdelrahman
05:28 queued 03:06
created

Cacheable::getCacheKeys()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 3
eloc 4
nc 4
nop 1
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\Traits;
17
18
use Closure;
19
20
trait Cacheable
21
{
22
    /**
23
     * The repository cache lifetime.
24
     *
25
     * @var float|int
26
     */
27
    protected $cacheLifetime;
28
29
    /**
30
     * The repository cache driver.
31
     *
32
     * @var string
33
     */
34
    protected $cacheDriver;
35
36
    /**
37
     * Indicate if the repository cache clear is enabled.
38
     *
39
     * @var bool
40
     */
41
    protected $cacheClearEnabled = true;
42
43
    /**
44
     * Generate unique query hash.
45
     *
46
     * @param $args
47
     *
48
     * @return string
49
     */
50
    protected function generateCacheHash($args)
51
    {
52
        return md5(json_encode($args + [
53
                $this->getRepositoryId(),
0 ignored issues
show
Bug introduced by
It seems like getRepositoryId() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
54
                $this->getModel(),
0 ignored issues
show
Bug introduced by
It seems like getModel() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
55
                $this->getCacheDriver(),
56
                $this->getCacheLifetime(),
57
                $this->relations,
0 ignored issues
show
Bug introduced by
The property relations does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
58
                $this->where,
0 ignored issues
show
Bug introduced by
The property where does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
59
                $this->whereIn,
0 ignored issues
show
Bug introduced by
The property whereIn does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
60
                $this->whereNotIn,
0 ignored issues
show
Bug introduced by
The property whereNotIn does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
61
                $this->offset,
0 ignored issues
show
Bug introduced by
The property offset does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
62
                $this->limit,
0 ignored issues
show
Bug introduced by
The property limit does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
63
                $this->orderBy,
0 ignored issues
show
Bug introduced by
The property orderBy does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
64
            ]));
65
    }
66
67
    /**
68
     * Store cache keys by mimicking cache tags.
69
     *
70
     * @param string $class
71
     * @param string $method
72
     * @param string $hash
73
     *
74
     * @return void
75
     */
76
    protected function storeCacheKeys($class, $method, $hash)
77
    {
78
        $keysFile  = $this->getContainer('config')->get('rinvex.repository.cache.keys_file');
0 ignored issues
show
Bug introduced by
It seems like getContainer() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
79
        $cacheKeys = $this->getCacheKeys($keysFile);
80
81
        if (! isset($cacheKeys[$class]) || ! in_array($method.'.'.$hash, $cacheKeys[$class])) {
82
            $cacheKeys[$class][] = $method.'.'.$hash;
83
            file_put_contents($keysFile, json_encode($cacheKeys));
84
        }
85
    }
86
87
    /**
88
     * Get cache keys.
89
     *
90
     * @param string $file
91
     *
92
     * @return array
93
     */
94
    protected function getCacheKeys($file)
95
    {
96
        if (! file_exists($file)) {
97
            file_put_contents($file, null);
98
        }
99
100
        return json_decode(file_get_contents($file), true) ?: [];
101
    }
102
103
    /**
104
     * Flush cache keys by mimicking cache tags.
105
     *
106
     * @return array
107
     */
108
    protected function flushCacheKeys()
109
    {
110
        $flushedKeys = [];
111
        $calledClass = get_called_class();
112
        $config      = $this->getContainer('config')->get('rinvex.repository.cache');
0 ignored issues
show
Bug introduced by
It seems like getContainer() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
113
        $cacheKeys   = $this->getCacheKeys($config['keys_file']);
114
115
        if (isset($cacheKeys[$calledClass]) && is_array($cacheKeys[$calledClass])) {
116
            foreach ($cacheKeys[$calledClass] as $cacheKey) {
117
                $flushedKeys[] = $calledClass.'@'.$cacheKey;
118
            }
119
120
            unset($cacheKeys[$calledClass]);
121
            file_put_contents($config['keys_file'], json_encode($cacheKeys));
122
        }
123
124
        return $flushedKeys;
125
    }
126
127
    /**
128
     * Set the repository cache lifetime.
129
     *
130
     * @param float|int $cacheLifetime
131
     *
132
     * @return $this
133
     */
134
    public function setCacheLifetime($cacheLifetime)
135
    {
136
        $this->cacheLifetime = $cacheLifetime;
137
138
        return $this;
139
    }
140
141
    /**
142
     * Get the repository cache lifetime.
143
     *
144
     * @return float|int
145
     */
146
    public function getCacheLifetime()
147
    {
148
        $lifetime = $this->getContainer('config')->get('rinvex.repository.cache.lifetime');
0 ignored issues
show
Bug introduced by
It seems like getContainer() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
149
150
        // Return value even if it's zero "0" (which means cache is disabled)
151
        return ! is_null($this->cacheLifetime) ? $this->cacheLifetime : $lifetime;
152
    }
153
154
    /**
155
     * Set the repository cache driver.
156
     *
157
     * @param string $cacheDriver
158
     *
159
     * @return $this
160
     */
161
    public function setCacheDriver($cacheDriver)
162
    {
163
        $this->cacheDriver = $cacheDriver;
164
165
        return $this;
166
    }
167
168
    /**
169
     * Get the repository cache driver.
170
     *
171
     * @return string
172
     */
173
    public function getCacheDriver()
174
    {
175
        return $this->cacheDriver;
176
    }
177
178
    /**
179
     * Enable repository cache clear.
180
     *
181
     * @param bool $status
182
     *
183
     * @return $this
184
     */
185
    public function enableCacheClear($status = true)
186
    {
187
        $this->cacheClearEnabled = $status;
188
189
        return $this;
190
    }
191
192
    /**
193
     * Determine if repository cache clear is enabled.
194
     *
195
     * @return bool
196
     */
197
    public function isCacheClearEnabled()
198
    {
199
        return $this->cacheClearEnabled;
200
    }
201
202
    /**
203
     * Forget the repository cache.
204
     *
205
     * @return $this
206
     */
207
    public function forgetCache()
208
    {
209
        if ($this->getCacheLifetime()) {
210
            // Flush cache tags
211
            if (method_exists($this->getContainer('cache')->getStore(), 'tags')) {
0 ignored issues
show
Bug introduced by
It seems like getContainer() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
212
                $this->getContainer('cache')->tags($this->getRepositoryId())->flush();
0 ignored issues
show
Bug introduced by
It seems like getContainer() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
Bug introduced by
It seems like getRepositoryId() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
213
            } else {
214
                // Flush cache keys, then forget actual cache
215
                foreach ($this->flushCacheKeys() as $cacheKey) {
216
                    $this->getContainer('cache')->forget($cacheKey);
0 ignored issues
show
Bug introduced by
It seems like getContainer() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
217
                }
218
            }
219
220
            $this->getContainer('events')->fire($this->getRepositoryId().'.entity.cache.flushed', [$this]);
0 ignored issues
show
Bug introduced by
It seems like getContainer() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
Bug introduced by
It seems like getRepositoryId() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
221
        }
222
223
        return $this;
224
    }
225
226
    /**
227
     * Cache given callback.
228
     *
229
     * @param string   $class
230
     * @param string   $method
231
     * @param array    $args
232
     * @param \Closure $closure
233
     *
234
     * @return mixed
235
     */
236
    protected function cacheCallback($class, $method, $args, Closure $closure)
237
    {
238
        $repositoryId = $this->getRepositoryId();
0 ignored issues
show
Bug introduced by
It seems like getRepositoryId() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
239
        $lifetime     = $this->getCacheLifetime();
240
        $hash         = $this->generateCacheHash($args);
241
        $cacheKey     = $class.'@'.$method.'.'.$hash;
242
243
        // Switch cache driver on runtime
244
        if ($driver = $this->getCacheDriver()) {
245
            $this->getContainer('cache')->setDefaultDriver($driver);
0 ignored issues
show
Bug introduced by
It seems like getContainer() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
246
        }
247
248
        // We need cache tags, check if default driver supports it
249
        if (method_exists($this->getContainer('cache')->getStore(), 'tags')) {
0 ignored issues
show
Bug introduced by
It seems like getContainer() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
250
            $result = $lifetime === -1
251
                ? $this->getContainer('cache')->tags($repositoryId)->rememberForever($cacheKey, $closure)
0 ignored issues
show
Bug introduced by
It seems like getContainer() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
252
                : $this->getContainer('cache')->tags($repositoryId)->remember($cacheKey, $lifetime, $closure);
0 ignored issues
show
Bug introduced by
It seems like getContainer() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
253
254
            // We're done, let's clean up!
255
            $this->resetRepository();
0 ignored issues
show
Bug introduced by
It seems like resetRepository() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
256
257
            return $result;
258
        }
259
260
        // Default cache driver doesn't support tags, let's do it manually
261
        $this->storeCacheKeys($class, $method, $hash);
262
263
        $result = $lifetime === -1
264
            ? $this->getContainer('cache')->rememberForever($cacheKey, $closure)
0 ignored issues
show
Bug introduced by
It seems like getContainer() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
265
            : $this->getContainer('cache')->remember($cacheKey, $lifetime, $closure);
0 ignored issues
show
Bug introduced by
It seems like getContainer() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
266
267
        // We're done, let's clean up!
268
        $this->resetCachedRepository();
269
270
        return $result;
271
    }
272
273
    /**
274
     * Reset cached repository to it's defaults.
275
     *
276
     * @return $this
277
     */
278
    protected function resetCachedRepository()
279
    {
280
        $this->resetRepository();
0 ignored issues
show
Bug introduced by
It seems like resetRepository() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
281
282
        $this->cacheLifetime = null;
283
        $this->cacheDriver   = null;
284
285
        return $this;
286
    }
287
}
288