Passed
Push — master ( c2a900...613edc )
by Mike
02:31
created

CachedBuilder::recursiveImplodeWithKey()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 3
nop 2
dl 0
loc 15
rs 10
c 0
b 0
f 0
1
<?php namespace GeneaLabs\LaravelModelCaching;
2
3
use GeneaLabs\LaravelModelCaching\Traits\BuilderCaching;
4
use GeneaLabs\LaravelModelCaching\Traits\Caching;
5
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
6
use Illuminate\Support\Collection;
7
8
/**
9
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
10
 */
11
class CachedBuilder extends EloquentBuilder
12
{
13
    use BuilderCaching;
14
    use Caching;
15
16
    public function avg($column)
17
    {
18
        if (! $this->isCachable()) {
19
            return parent::avg($column);
20
        }
21
22
        $cacheKey = $this->makeCacheKey(["*"], null, "-avg_{$column}");
23
24
        return $this->cachedValue(func_get_args(), $cacheKey);
25
    }
26
27
    public function count($columns = "*")
28
    {
29
        if (! $this->isCachable()) {
30
            return parent::count($columns);
31
        }
32
33
        $cacheKey = $this->makeCacheKey([$columns], null, "-count");
34
35
        return $this->cachedValue(func_get_args(), $cacheKey);
36
    }
37
38
    public function delete()
39
    {
40
        $this->cache($this->makeCacheTags())
41
            ->flush();
42
43
        return parent::delete();
44
    }
45
46
    /**
47
     * @SuppressWarnings(PHPMD.ShortVariable)
48
     */
49
    public function find($id, $columns = ["*"])
50
    {
51
        if (! $this->isCachable()) {
52
            return parent::find($id, $columns);
53
        }
54
55
        $idKey = collect($id)->implode('-');
56
        $cacheKey = $this->makeCacheKey($columns, null, "-find_{$idKey}");
57
58
        return $this->cachedValue(func_get_args(), $cacheKey);
59
    }
60
61
    public function first($columns = ["*"])
62
    {
63
        if (! $this->isCachable()) {
64
            return parent::first($columns);
65
        }
66
67
        $cacheKey = $this->makeCacheKey($columns, null, "-first");
68
69
        return $this->cachedValue(func_get_args(), $cacheKey);
70
    }
71
72
    public function forceDelete()
73
    {
74
        $this->cache($this->makeCacheTags())
75
            ->flush();
76
77
        return parent::forceDelete();
78
    }
79
80
    public function get($columns = ["*"])
81
    {
82
        if (! $this->isCachable()) {
83
            return parent::get($columns);
84
        }
85
86
        $cacheKey = $this->makeCacheKey($columns);
87
88
        return $this->cachedValue(func_get_args(), $cacheKey);
89
    }
90
91
    public function inRandomOrder($seed = '')
92
    {
93
        $this->isCachable = false;
94
95
        return parent::inRandomOrder($seed);
1 ignored issue
show
introduced by
The method inRandomOrder() does not exist on Illuminate\Database\Eloquent\Builder. Are you sure you never get this type here, but always one of the subclasses? ( Ignorable by Annotation )

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

95
        return parent::/** @scrutinizer ignore-call */ inRandomOrder($seed);
Loading history...
96
    }
97
98
    public function insert(array $values)
99
    {
100
        $this->checkCooldownAndFlushAfterPersiting($this->model);
101
102
        return parent::insert($values);
103
    }
104
105
    public function max($column)
106
    {
107
        if (! $this->isCachable()) {
108
            return parent::max($column);
109
        }
110
111
        $cacheKey = $this->makeCacheKey(["*"], null, "-max_{$column}");
112
113
        return $this->cachedValue(func_get_args(), $cacheKey);
114
    }
115
116
    public function min($column)
117
    {
118
        if (! $this->isCachable()) {
119
            return parent::min($column);
120
        }
121
122
        $cacheKey = $this->makeCacheKey(["*"], null, "-min_{$column}");
123
124
        return $this->cachedValue(func_get_args(), $cacheKey);
125
    }
126
127
    public function paginate(
128
        $perPage = null,
129
        $columns = ["*"],
130
        $pageName = "page",
131
        $page = null
132
    ) {
133
        if (! $this->isCachable()) {
134
            return parent::paginate($perPage, $columns, $pageName, $page);
135
        }
136
137
        $page = request()->input($pageName)
138
            ?: $page
139
            ?: 1;
140
141
        if (is_array($page)) {
142
            $page = $this->recursiveImplodeWithKey($page);
143
        }
144
        $cacheKey = $this->makeCacheKey($columns, null, "-paginate_by_{$perPage}_{$pageName}_{$page}");
145
146
        return $this->cachedValue(func_get_args(), $cacheKey);
147
    }
148
149
    protected function recursiveImplodeWithKey(array $items, string $glue = "_") : string
150
    {
151
        $result = "";
152
153
        foreach ($items as $key => $value) {
154
            if (is_array($value)) {
155
                $result .= $key . $glue . $this->recursiveImplodeWithKey($value, $glue);
156
157
                continue;
158
            }
159
160
            $result .= $glue . $key . $glue . $value;
161
        }
162
163
        return $result;
164
    }
165
166
    public function pluck($column, $key = null)
167
    {
168
        if (! $this->isCachable()) {
169
            return parent::pluck($column, $key);
170
        }
171
172
        $keyDifferentiator = "-pluck_{$column}" . ($key ? "_{$key}" : "");
173
        $cacheKey = $this->makeCacheKey([$column], null, $keyDifferentiator);
174
175
        return $this->cachedValue(func_get_args(), $cacheKey);
176
    }
177
178
    public function sum($column)
179
    {
180
        if (! $this->isCachable()) {
181
            return parent::sum($column);
182
        }
183
184
        $cacheKey = $this->makeCacheKey(["*"], null, "-sum_{$column}");
185
186
        return $this->cachedValue(func_get_args(), $cacheKey);
187
    }
188
189
    public function update(array $values)
190
    {
191
        $this->checkCooldownAndFlushAfterPersiting($this->model);
192
193
        return parent::update($values);
194
    }
195
196
    public function value($column)
197
    {
198
        if (! $this->isCachable()) {
199
            return parent::value($column);
200
        }
201
202
        $cacheKey = $this->makeCacheKey(["*"], null, "-value_{$column}");
203
204
        return $this->cachedValue(func_get_args(), $cacheKey);
205
    }
206
207
    public function cachedValue(array $arguments, string $cacheKey)
208
    {
209
        $method = debug_backtrace()[1]['function'];
210
        $cacheTags = $this->makeCacheTags();
211
        $hashedCacheKey = sha1($cacheKey);
212
        $result = $this->retrieveCachedValue(
213
            $arguments,
214
            $cacheKey,
215
            $cacheTags,
216
            $hashedCacheKey,
217
            $method
218
        );
219
220
        return $this->preventHashCollision(
221
            $result,
222
            $arguments,
223
            $cacheKey,
224
            $cacheTags,
225
            $hashedCacheKey,
226
            $method
227
        );
228
    }
229
230
    protected function preventHashCollision(
231
        array $result,
232
        array $arguments,
233
        string $cacheKey,
234
        array $cacheTags,
235
        string $hashedCacheKey,
236
        string $method
237
    ) {
238
        if ($result["key"] === $cacheKey) {
239
            return $result["value"];
240
        }
241
242
        $this->cache()
243
            ->tags($cacheTags)
244
            ->forget($hashedCacheKey);
245
246
        return $this->retrieveCachedValue(
247
            $arguments,
248
            $cacheKey,
249
            $cacheTags,
250
            $hashedCacheKey,
251
            $method
252
        );
253
    }
254
255
    protected function retrieveCachedValue(
256
        array $arguments,
257
        string $cacheKey,
258
        array $cacheTags,
259
        string $hashedCacheKey,
260
        string $method
261
    ) {
262
        $this->checkCooldownAndRemoveIfExpired($this->model);
263
264
        return $this->cache($cacheTags)
265
            ->rememberForever(
266
                $hashedCacheKey,
267
                function () use ($arguments, $cacheKey, $method) {
268
                    return [
269
                        "key" => $cacheKey,
270
                        "value" => parent::{$method}(...$arguments),
271
                    ];
272
                }
273
            );
274
    }
275
}
276