Passed
Push — master ( a9f4ea...76cbc1 )
by Mike
04:02
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 9.4285
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 get($columns = ["*"])
73
    {
74
        if (! $this->isCachable()) {
75
            return parent::get($columns);
76
        }
77
78
        $cacheKey = $this->makeCacheKey($columns);
79
80
        return $this->cachedValue(func_get_args(), $cacheKey);
81
    }
82
83
    public function inRandomOrder($seed = '')
84
    {
85
        $this->isCachable = false;
86
87
        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

87
        return parent::/** @scrutinizer ignore-call */ inRandomOrder($seed);
Loading history...
88
    }
89
90
    public function insert(array $values)
91
    {
92
        $this->checkCooldownAndFlushAfterPersiting($this->model);
93
94
        return parent::insert($values);
95
    }
96
97
    public function max($column)
98
    {
99
        if (! $this->isCachable()) {
100
            return parent::max($column);
101
        }
102
103
        $cacheKey = $this->makeCacheKey(["*"], null, "-max_{$column}");
104
105
        return $this->cachedValue(func_get_args(), $cacheKey);
106
    }
107
108
    public function min($column)
109
    {
110
        if (! $this->isCachable()) {
111
            return parent::min($column);
112
        }
113
114
        $cacheKey = $this->makeCacheKey(["*"], null, "-min_{$column}");
115
116
        return $this->cachedValue(func_get_args(), $cacheKey);
117
    }
118
119
    public function paginate(
120
        $perPage = null,
121
        $columns = ["*"],
122
        $pageName = "page",
123
        $page = null
124
    ) {
125
        if (! $this->isCachable()) {
126
            return parent::paginate($perPage, $columns, $pageName, $page);
127
        }
128
129
        $page = request("page", $page ?: 1);
130
131
        if (is_array($page)) {
132
            $page = $this->recursiveImplodeWithKey($page);
133
        }
134
        dump($perPage, $columns, $pageName, $page);
0 ignored issues
show
Unused Code introduced by
The call to dump() has too many arguments starting with $pageName. ( Ignorable by Annotation )

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

134
        /** @scrutinizer ignore-call */ 
135
        dump($perPage, $columns, $pageName, $page);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
135
136
        $cacheKey = $this->makeCacheKey($columns, null, "-paginate_by_{$perPage}_{$pageName}_{$page}");
137
138
        return $this->cachedValue(func_get_args(), $cacheKey);
139
    }
140
141
    protected function recursiveImplodeWithKey(array $items, string $glue = "_") : string
142
    {
143
        $result = "";
144
145
        foreach ($items as $key => $value) {
146
            if (is_array($value)) {
147
                $result .= $key . $glue . $this->recursiveImplode($value, $glue);
0 ignored issues
show
Bug introduced by
The method recursiveImplode() does not exist on GeneaLabs\LaravelModelCaching\CachedBuilder. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

147
                $result .= $key . $glue . $this->/** @scrutinizer ignore-call */ recursiveImplode($value, $glue);
Loading history...
Bug introduced by
Are you sure $this->recursiveImplode($value, $glue) of type GeneaLabs\LaravelModelCaching\CachedBuilder|mixed can be used in concatenation? ( Ignorable by Annotation )

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

147
                $result .= $key . $glue . /** @scrutinizer ignore-type */ $this->recursiveImplode($value, $glue);
Loading history...
148
149
                continue;
150
            }
151
152
            $result .= $glue . $key . $glue . $value;
153
        }
154
155
        return $result;
156
    }
157
158
    public function pluck($column, $key = null)
159
    {
160
        if (! $this->isCachable()) {
161
            return parent::pluck($column, $key);
162
        }
163
164
        $keyDifferentiator = "-pluck_{$column}" . ($key ? "_{$key}" : "");
165
        $cacheKey = $this->makeCacheKey([$column], null, $keyDifferentiator);
166
167
        return $this->cachedValue(func_get_args(), $cacheKey);
168
    }
169
170
    public function sum($column)
171
    {
172
        if (! $this->isCachable()) {
173
            return parent::sum($column);
174
        }
175
176
        $cacheKey = $this->makeCacheKey(["*"], null, "-sum_{$column}");
177
178
        return $this->cachedValue(func_get_args(), $cacheKey);
179
    }
180
181
    public function update(array $values)
182
    {
183
        $this->checkCooldownAndFlushAfterPersiting($this->model);
184
185
        return parent::update($values);
186
    }
187
188
    public function value($column)
189
    {
190
        if (! $this->isCachable()) {
191
            return parent::value($column);
192
        }
193
194
        $cacheKey = $this->makeCacheKey(["*"], null, "-value_{$column}");
195
196
        return $this->cachedValue(func_get_args(), $cacheKey);
197
    }
198
199
    public function cachedValue(array $arguments, string $cacheKey)
200
    {
201
        $method = debug_backtrace()[1]['function'];
202
        $cacheTags = $this->makeCacheTags();
203
        $hashedCacheKey = sha1($cacheKey);
204
        $result = $this->retrieveCachedValue(
205
            $arguments,
206
            $cacheKey,
207
            $cacheTags,
208
            $hashedCacheKey,
209
            $method
210
        );
211
212
        return $this->preventHashCollision(
213
            $result,
214
            $arguments,
215
            $cacheKey,
216
            $cacheTags,
217
            $hashedCacheKey,
218
            $method
219
        );
220
    }
221
222
    protected function preventHashCollision(
223
        array $result,
224
        array $arguments,
225
        string $cacheKey,
226
        array $cacheTags,
227
        string $hashedCacheKey,
228
        string $method
229
    ) {
230
        if ($result["key"] === $cacheKey) {
231
            return $result["value"];
232
        }
233
234
        $this->cache()
235
            ->tags($cacheTags)
236
            ->forget($hashedCacheKey);
237
238
        return $this->retrieveCachedValue(
239
            $arguments,
240
            $cacheKey,
241
            $cacheTags,
242
            $hashedCacheKey,
243
            $method
244
        );
245
    }
246
247
    protected function retrieveCachedValue(
248
        array $arguments,
249
        string $cacheKey,
250
        array $cacheTags,
251
        string $hashedCacheKey,
252
        string $method
253
    ) {
254
        $this->checkCooldownAndRemoveIfExpired($this->model);
255
256
        return $this->cache($cacheTags)
257
            ->rememberForever(
258
                $hashedCacheKey,
259
                function () use ($arguments, $cacheKey, $method) {
260
                    return [
261
                        "key" => $cacheKey,
262
                        "value" => parent::{$method}(...$arguments),
263
                    ];
264
                }
265
            );
266
    }
267
}
268