Passed
Push — master ( f90b69...128f25 )
by Mike
02:36
created

CacheKey   B

Complexity

Total Complexity 49

Size/Duplication

Total Lines 272
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 272
rs 8.5454
c 0
b 0
f 0
wmc 49

22 Methods

Rating   Name   Duplication   Size   Complexity  
A getLimitClause() 0 7 2
A getModelSlug() 0 3 1
A __construct() 0 8 1
A getIdColumn() 0 3 2
A make() 0 17 2
A getOrderByClauses() 0 13 3
A getOffsetClause() 0 7 2
A getTypeClause() 0 7 2
A getQueryColumns() 0 7 3
B getValuesFromBindings() 0 13 5
A getValuesFromWhere() 0 7 2
A getValuesClause() 0 12 2
A getWhereClauses() 0 13 1
A getOtherClauses() 0 10 2
A recursiveImplode() 0 15 3
A getNestedClauses() 0 9 2
A getNotInClauses() 0 10 2
A getWheres() 0 9 2
B getRawClauses() 0 22 4
A getColumnClauses() 0 9 2
A getWithModels() 0 9 2
A getInClauses() 0 10 2

How to fix   Complexity   

Complex Class

Complex classes like CacheKey often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CacheKey, and based on these observations, apply Extract Interface, too.

1
<?php namespace GeneaLabs\LaravelModelCaching;
2
3
use GeneaLabs\LaravelModelCaching\Traits\CachePrefixing;
4
use Illuminate\Database\Eloquent\Model;
5
use Illuminate\Database\Query\Builder;
6
use Illuminate\Support\Collection;
7
8
class CacheKey
9
{
10
    use CachePrefixing;
1 ignored issue
show
Bug introduced by
The trait GeneaLabs\LaravelModelCa...g\Traits\CachePrefixing requires the property $connection which is not provided by GeneaLabs\LaravelModelCaching\CacheKey.
Loading history...
11
12
    protected $eagerLoad;
13
    protected $model;
14
    protected $query;
15
    protected $currentBinding = 0;
16
17
    public function __construct(
18
        array $eagerLoad,
19
        Model $model,
20
        Builder $query
21
    ) {
22
        $this->eagerLoad = $eagerLoad;
23
        $this->model = $model;
24
        $this->query = $query;
25
    }
26
27
    public function make(
28
        array $columns = ["*"],
29
        $idColumn = null,
30
        string $keyDifferentiator = ""
31
    ) : string {
32
        $key = $this->getCachePrefix();
33
        $key .= $this->getModelSlug();
34
        $key .= $this->getIdColumn($idColumn ?: "");
35
        $key .= $this->getQueryColumns($columns);
36
        $key .= $this->getWhereClauses();
37
        $key .= $this->getWithModels();
38
        $key .= $this->getOrderByClauses();
39
        $key .= $this->getOffsetClause();
40
        $key .= $this->getLimitClause();
41
        $key .= $keyDifferentiator;
42
43
        return $key;
44
    }
45
46
    protected function getIdColumn(string $idColumn) : string
47
    {
48
        return $idColumn ? "_{$idColumn}" : "";
49
    }
50
51
    protected function getLimitClause() : string
52
    {
53
        if (! $this->query->limit) {
54
            return "";
55
        }
56
57
        return "-limit_{$this->query->limit}";
58
    }
59
60
    protected function getModelSlug() : string
61
    {
62
        return str_slug(get_class($this->model));
63
    }
64
65
    protected function getOffsetClause() : string
66
    {
67
        if (! $this->query->offset) {
68
            return "";
69
        }
70
71
        return "-offset_{$this->query->offset}";
72
    }
73
74
    protected function getOrderByClauses() : string
75
    {
76
        $orders = collect($this->query->orders);
77
78
        return $orders
79
            ->reduce(function ($carry, $order) {
80
                if (($order["type"] ?? "") === "Raw") {
81
                    return $carry . "_orderByRaw_" . str_slug($order["sql"]);
82
                }
83
84
                return $carry . "_orderBy_" . $order["column"] . "_" . $order["direction"];
85
            })
86
            ?: "";
87
    }
88
89
    protected function getQueryColumns(array $columns) : string
90
    {
91
        if ($columns === ["*"] || $columns === []) {
92
            return "";
93
        }
94
95
        return "_" . implode("_", $columns);
96
    }
97
98
    protected function getTypeClause($where) : string
99
    {
100
        $type =in_array($where["type"], ["In", "NotIn", "Null", "NotNull", "between"])
101
            ? strtolower($where["type"])
102
            : strtolower($where["operator"]);
103
104
        return str_replace(" ", "_", $type);
105
    }
106
107
    protected function getValuesClause(array $where = null) : string
108
    {
109
        if (in_array($where["type"], ["NotNull", "Null"])) {
110
            return "";
111
        }
112
113
        $values = $this->getValuesFromWhere($where);
114
        $values = $this->getValuesFromBindings($where, $values);
0 ignored issues
show
Bug introduced by
It seems like $where can also be of type null; however, parameter $where of GeneaLabs\LaravelModelCa...getValuesFromBindings() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

114
        $values = $this->getValuesFromBindings(/** @scrutinizer ignore-type */ $where, $values);
Loading history...
115
116
117
118
        return "_" . $values;
119
    }
120
121
    protected function getValuesFromWhere(array $where) : string
122
    {
123
        if (is_array(array_get($where, "values"))) {
124
            return implode("_", $where["values"]);
125
        }
126
127
        return array_get($where, "value", "");
128
    }
129
130
    protected function getValuesFromBindings(array $where, string $values) : string
131
    {
132
        if (! $values && ($this->query->bindings["where"] ?? false)) {
133
            $values = $this->query->bindings["where"][$this->currentBinding];
134
            $this->currentBinding++;
135
136
            if ($where["type"] === "between") {
137
                $values .= "_" . $this->query->bindings["where"][$this->currentBinding];
138
                $this->currentBinding++;
139
            }
140
        }
141
142
        return $values ?: "";
143
    }
144
145
    protected function getWhereClauses(array $wheres = []) : string
146
    {
147
        return "" . $this->getWheres($wheres)
148
            ->reduce(function ($carry, $where) {
149
                $value = $carry;
150
                $value .= $this->getNestedClauses($where);
151
                $value .= $this->getColumnClauses($where);
152
                $value .= $this->getRawClauses($where);
153
                $value .= $this->getInClauses($where);
154
                $value .= $this->getNotInClauses($where);
155
                $value .= $this->getOtherClauses($where, $carry);
0 ignored issues
show
Unused Code introduced by
The call to GeneaLabs\LaravelModelCa...eKey::getOtherClauses() has too many arguments starting with $carry. ( Ignorable by Annotation )

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

155
                $value .= $this->/** @scrutinizer ignore-call */ getOtherClauses($where, $carry);

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...
156
157
                return $value;
158
            });
159
    }
160
161
    protected function getNestedClauses(array $where) : string
162
    {
163
        if (! in_array($where["type"], ["Exists", "Nested", "NotExists"])) {
164
            return "";
165
        }
166
167
        $this->currentBinding++;
168
169
        return "-" . strtolower($where["type"]) . $this->getWhereClauses($where["query"]->wheres);
170
    }
171
172
    protected function getColumnClauses(array $where) : string
173
    {
174
        if ($where["type"] !== "Column") {
175
            return "";
176
        }
177
178
        $this->currentBinding++;
179
180
        return "-{$where["boolean"]}_{$where["first"]}_{$where["operator"]}_{$where["second"]}";
181
    }
182
183
    protected function getInClauses(array $where) : string
184
    {
185
        if (! in_array($where["type"], ["In"])) {
186
            return "";
187
        }
188
189
        $this->currentBinding++;
190
        $values = $this->recursiveImplode($where["values"], "_");
191
192
        return "-{$where["column"]}_in{$values}";
193
    }
194
195
    protected function getNotInClauses(array $where) : string
196
    {
197
        if (! in_array($where["type"], ["NotIn"])) {
198
            return "";
199
        }
200
201
        $this->currentBinding++;
202
        $values = $this->recursiveImplode($where["values"], "_");
203
204
        return "-{$where["column"]}_not_in{$values}";
205
    }
206
207
    protected function recursiveImplode(array $items, string $glue = ",") : string
208
    {
209
        $result = "";
210
211
        foreach ($items as $key => $value) {
212
            if (is_array($value)) {
213
                $result .= $this->recursiveImplode($value, $glue);
214
215
                continue;
216
            }
217
218
            $result .= $glue . $value;
219
        }
220
221
        return $result;
222
    }
223
224
    protected function getRawClauses(array $where) : string
225
    {
226
        if ($where["type"] !== "raw") {
227
            return "";
228
        }
229
230
        $queryParts = explode("?", $where["sql"]);
231
        $clause = "_{$where["boolean"]}";
232
233
        while (count($queryParts) > 1) {
234
            $clause .= "_" . array_shift($queryParts);
235
            $clause .= $this->query->bindings["where"][$this->currentBinding];
236
            $this->currentBinding++;
237
        }
238
239
        $lastPart = array_shift($queryParts);
240
241
        if ($lastPart) {
242
            $clause .= "_" . $lastPart;
243
        }
244
245
        return "-" . str_replace(" ", "_", $clause);
246
    }
247
248
    protected function getOtherClauses(array $where) : string
249
    {
250
        if (in_array($where["type"], ["Exists", "Nested", "NotExists", "Column", "raw", "In", "NotIn"])) {
251
            return "";
252
        }
253
254
        $value = $this->getTypeClause($where);
255
        $value .= $this->getValuesClause($where);
256
257
        return "-{$where["column"]}_{$value}";
258
    }
259
260
    protected function getWheres(array $wheres) : Collection
261
    {
262
        $wheres = collect($wheres);
263
264
        if ($wheres->isEmpty()) {
265
            $wheres = collect($this->query->wheres);
266
        }
267
268
        return $wheres;
269
    }
270
271
    protected function getWithModels() : string
272
    {
273
        $eagerLoads = collect($this->eagerLoad);
274
275
        if ($eagerLoads->isEmpty()) {
276
            return "";
277
        }
278
279
        return "-" . implode("-", $eagerLoads->keys()->toArray());
280
    }
281
}
282