Completed
Push — master ( fa70a6...b71a5d )
by Mike
06:15
created

CachedBuilder::getOffsetClause()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 2
nop 0
1
<?php namespace GeneaLabs\LaravelModelCaching;
2
3
use Closure;
4
use Illuminate\Cache\TaggableStore;
5
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
6
use Illuminate\Database\Eloquent\Relations\Pivot;
7
use Illuminate\Support\Collection;
8
use Illuminate\Database\Eloquent\Relations\Relation;
9
use Ramsey\Uuid\Uuid;
10
11
class CachedBuilder extends EloquentBuilder
12
{
13
    protected function cache(array $tags = [])
14
    {
15
        $cache = cache();
16
17
        if (is_subclass_of($cache->getStore(), TaggableStore::class)) {
18
            $cache = $cache->tags($tags);
19
        }
20
21
        return $cache;
22
    }
23
24
    protected function getCacheKey(array $columns = ['*'], $idColumn = null) : string
25
    {
26
        $key = $this->getModelSlug();
27
        $key .= $this->getIdColumn($idColumn ?: '');
28
        $key .= $this->getQueryColumns($columns);
29
        $key .= $this->getWhereClauses();
30
        $key .= $this->getWithModels();
31
        $key .= $this->getOffsetClause();
32
        $key .= $this->getLimitClause();
33
34
        return $key;
35
    }
36
37
    protected function getIdColumn(string $idColumn) : string
38
    {
39
        return $idColumn ? "_{$idColumn}" : '';
40
    }
41
42
    protected function getLimitClause() : string
43
    {
44
        if (! $this->query->limit) {
45
            return '';
46
        }
47
48
        return "-limit_{$this->query->limit}";
49
    }
50
51
    protected function getModelSlug() : string
52
    {
53
        return str_slug(get_class($this->model));
54
    }
55
56
    protected function getOffsetClause() : string
57
    {
58
        if (! $this->query->offset) {
59
            return '';
60
        }
61
62
        return "-offset_{$this->query->offset}";
63
    }
64
65
    protected function getQueryColumns(array $columns) : string
66
    {
67
        if ($columns === ['*'] || $columns === []) {
68
            return '';
69
        }
70
71
        return '_' . implode('_', $columns);
72
    }
73
74
    protected function getWhereClauses() : string
75
    {
76
        return collect($this->query->wheres)->reduce(function ($carry, $where) {
77
            $value = $where['value'] ?? implode('_', ($where['values'] ?? []));
78
79
            return "{$carry}-{$where['column']}_{$value}";
80
        }) ?: '';
81
    }
82
83
    protected function getWithModels() : string
84
    {
85
        $eagerLoads = collect($this->eagerLoad);
86
87
        if ($eagerLoads->isEmpty()) {
88
            return '';
89
        }
90
91
        return '-' . implode('-', $eagerLoads->keys()->toArray());
92
    }
93
94
    protected function getCacheTags() : array
95
    {
96
        return collect($this->eagerLoad)->keys()
97
            ->map(function ($relationName) {
98
                $relation = collect(explode('.', $relationName))
99
                    ->reduce(function ($carry, $name) {
100
                        if (! $carry) {
101
                            $carry = $this->model;
102
                        }
103
104
                        if ($carry instanceof Relation) {
105
                            $carry = $carry->getQuery()->model;
1 ignored issue
show
Bug introduced by
The property model does not seem to exist on Illuminate\Database\Query\Builder.
Loading history...
106
                        }
107
108
                        return $carry->{$name}();
109
                    });
110
111
                return str_slug(get_class($relation->getQuery()->model));
112
            })
113
            ->prepend(str_slug(get_class($this->model)))
114
            ->values()
115
            ->toArray();
116
    }
117
118
    protected function isCaching() : bool
119
    {
120
        return (session('genealabs-laravel-model-is-caching') !== null);
121
    }
122
123
    protected function setCachingFlag() : string
124
    {
125
126
        $cachingFlag = UUID::uuid4()->toString();
127
        session(['genealabs-laravel-model-is-caching' => $cachingFlag]);
128
129
        return $cachingFlag;
130
    }
131
132
    protected function clearCachingFlag(string $cachingFlag)
133
    {
134
        if (session('genealabs-laravel-model-is-caching') === $cachingFlag) {
135
            session()->forget('genealabs-laravel-model-is-caching');
136
        }
137
    }
138
139 View Code Duplication
    public function avg($column)
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
140
    {
141
        $tags = [str_slug(get_class($this->model))];
142
        $key = str_slug(get_class($this->model)) ."-avg_{$column}";
143
144
        if ($this->isCaching()) {
145
            return parent::avg($column);
1 ignored issue
show
Bug introduced by
The method avg() does not exist on Illuminate\Database\Eloquent\Builder. It seems like you code against a sub-type of Illuminate\Database\Eloquent\Builder such as GeneaLabs\LaravelModelCaching\CachedBuilder. ( Ignorable by Annotation )

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

145
            return parent::/** @scrutinizer ignore-call */ avg($column);
Loading history...
146
        }
147
148
        $cachingFlag = $this->setCachingFlag();
149
        $result = $this->cache($tags)
150
            ->rememberForever($key, function () use ($column) {
151
                return parent::avg($column);
152
            });
153
        $this->clearCachingFlag($cachingFlag);
154
155
        return $result;
156
    }
157
158 View Code Duplication
    public function count($columns = ['*'])
159
    {
160
        $tags = [str_slug(get_class($this->model))];
161
        $key = str_slug(get_class($this->model)) ."-count";
162
163
        if ($this->isCaching()) {
164
            return parent::count($columns);
1 ignored issue
show
Bug introduced by
The method count() does not exist on Illuminate\Database\Eloquent\Builder. It seems like you code against a sub-type of Illuminate\Database\Eloquent\Builder such as GeneaLabs\LaravelModelCaching\CachedBuilder. ( Ignorable by Annotation )

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

164
            return parent::/** @scrutinizer ignore-call */ count($columns);
Loading history...
165
        }
166
167
        $cachingFlag = $this->setCachingFlag();
168
        $result = $this->cache($tags)
169
            ->rememberForever($key, function () use ($columns) {
170
                return parent::count($columns);
171
            });
172
        $this->clearCachingFlag($cachingFlag);
173
174
        return $result;
175
    }
176
177
    public function cursor()
178
    {
179
        $tags = [str_slug(get_class($this->model))];
180
        $key = str_slug(get_class($this->model)) ."-cursor";
181
182
        if ($this->isCaching()) {
183
            return collect(parent::cursor());
184
        }
185
186
        $cachingFlag = $this->setCachingFlag();
187
        $result = $this->cache($tags)
188
            ->rememberForever($key, function () {
189
                return collect(parent::cursor());
190
            });
191
        $this->clearCachingFlag($cachingFlag);
192
193
        return $result;
194
    }
195
196
    /**
197
     * @SuppressWarnings(PHPMD.ShortVariable)
198
     */
199
    public function find($id, $columns = ['*'])
200
    {
201
        $tags = $this->getCacheTags();
202
        $key = $this->getCacheKey($columns, $id);
203
204
        if ($this->isCaching()) {
205
            return parent::find($id, $columns);
206
        }
207
208
        $cachingFlag = $this->setCachingFlag();
209
        $result = $this->cache($tags)
210
            ->rememberForever($key, function () use ($id, $columns) {
211
                return parent::find($id, $columns);
212
            });
213
        $this->clearCachingFlag($cachingFlag);
214
215
        return $result;
216
    }
217
218 View Code Duplication
    public function first($columns = ['*'])
219
    {
220
        $tags = $this->getCacheTags();
221
        $key = $this->getCacheKey($columns) . '-first';
222
223
        if ($this->isCaching()) {
224
            return parent::first($columns);
225
        }
226
227
        $cachingFlag = $this->setCachingFlag();
228
        $result = $this->cache($tags)
229
            ->rememberForever($key, function () use ($columns) {
230
                return parent::first($columns);
231
            });
232
        $this->clearCachingFlag($cachingFlag);
233
234
        return $result;
235
    }
236
237 View Code Duplication
    public function get($columns = ['*'])
238
    {
239
        $tags = $this->getCacheTags();
240
        $key = $this->getCacheKey($columns);
241
242
        if ($this->isCaching()) {
243
            return parent::get($columns);
244
        }
245
246
        $cachingFlag = $this->setCachingFlag();
247
        $result = $this->cache($tags)
248
            ->rememberForever($key, function () use ($columns) {
249
                return parent::get($columns);
250
            });
251
        $this->clearCachingFlag($cachingFlag);
252
253
        return $result;
254
    }
255
256 View Code Duplication
    public function max($column)
257
    {
258
        $tags = [str_slug(get_class($this->model))];
259
        $key = str_slug(get_class($this->model)) ."-max_{$column}";
260
261
        if ($this->isCaching()) {
262
            return parent::max($column);
1 ignored issue
show
Bug introduced by
The method max() does not exist on Illuminate\Database\Eloquent\Builder. It seems like you code against a sub-type of Illuminate\Database\Eloquent\Builder such as GeneaLabs\LaravelModelCaching\CachedBuilder. ( Ignorable by Annotation )

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

262
            return parent::/** @scrutinizer ignore-call */ max($column);
Loading history...
263
        }
264
265
        $cachingFlag = $this->setCachingFlag();
266
        $result = $this->cache($tags)
267
            ->rememberForever($key, function () use ($column) {
268
                return parent::max($column);
269
            });
270
        $this->clearCachingFlag($cachingFlag);
271
272
        return $result;
273
    }
274
275 View Code Duplication
    public function min($column)
276
    {
277
        $tags = [str_slug(get_class($this->model))];
278
        $key = str_slug(get_class($this->model)) ."-min_{$column}";
279
280
        if ($this->isCaching()) {
281
            return parent::min($column);
1 ignored issue
show
Bug introduced by
The method min() does not exist on Illuminate\Database\Eloquent\Builder. It seems like you code against a sub-type of Illuminate\Database\Eloquent\Builder such as GeneaLabs\LaravelModelCaching\CachedBuilder. ( Ignorable by Annotation )

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

281
            return parent::/** @scrutinizer ignore-call */ min($column);
Loading history...
282
        }
283
284
        $cachingFlag = $this->setCachingFlag();
285
        $result = $this->cache($tags)
286
            ->rememberForever($key, function () use ($column) {
287
                return parent::min($column);
288
            });
289
        $this->clearCachingFlag($cachingFlag);
290
291
        return $result;
292
    }
293
294
    public function pluck($column, $key = null)
295
    {
296
        $tags = $this->getCacheTags();
297
        $cacheKey = $this->getCacheKey([$column]) . "-pluck_{$column}";
298
299
        if ($key) {
300
            $cacheKey .= "_{$key}";
301
        }
302
303
        if ($this->isCaching()) {
304
            return parent::pluck($column, $key);
305
        }
306
307
        $cachingFlag = $this->setCachingFlag();
308
        $result = $this->cache($tags)
309
            ->rememberForever($cacheKey, function () use ($column, $key) {
310
                return parent::pluck($column, $key);
311
            });
312
        $this->clearCachingFlag($cachingFlag);
313
314
        return $result;
315
    }
316
317 View Code Duplication
    public function sum($column)
318
    {
319
        $tags = [str_slug(get_class($this->model))];
320
        $key = str_slug(get_class($this->model)) ."-sum_{$column}";
321
322
        if ($this->isCaching()) {
323
            return parent::sum($column);
1 ignored issue
show
Bug introduced by
The method sum() does not exist on Illuminate\Database\Eloquent\Builder. It seems like you code against a sub-type of Illuminate\Database\Eloquent\Builder such as GeneaLabs\LaravelModelCaching\CachedBuilder. ( Ignorable by Annotation )

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

323
            return parent::/** @scrutinizer ignore-call */ sum($column);
Loading history...
324
        }
325
326
        $cachingFlag = $this->setCachingFlag();
327
        $result = $this->cache($tags)
328
            ->rememberForever($key, function () use ($column) {
329
                return parent::sum($column);
330
            });
331
        $this->clearCachingFlag($cachingFlag);
332
333
        return $result;
334
    }
335
}
336