Total Complexity | 43 |
Total Lines | 335 |
Duplicated Lines | 0 % |
Changes | 2 | ||
Bugs | 0 | Features | 0 |
Complex classes like CacheableRepository 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 CacheableRepository, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
16 | trait CacheableRepository |
||
17 | { |
||
18 | |||
19 | /** |
||
20 | * @var CacheRepository |
||
21 | */ |
||
22 | protected $cacheRepository = null; |
||
23 | |||
24 | /** |
||
25 | * Set Cache Repository |
||
26 | * |
||
27 | * @param CacheRepository $repository |
||
28 | * |
||
29 | * @return $this |
||
30 | */ |
||
31 | public function setCacheRepository(CacheRepository $repository) |
||
32 | { |
||
33 | $this->cacheRepository = $repository; |
||
34 | |||
35 | return $this; |
||
36 | } |
||
37 | |||
38 | /** |
||
39 | * Return instance of Cache Repository |
||
40 | * |
||
41 | * @return CacheRepository |
||
42 | */ |
||
43 | public function getCacheRepository() |
||
44 | { |
||
45 | if (is_null($this->cacheRepository)) { |
||
46 | $this->cacheRepository = app(config('domains.repo-cache.repository', 'cache')); |
||
|
|||
47 | } |
||
48 | |||
49 | return $this->cacheRepository; |
||
50 | } |
||
51 | |||
52 | /** |
||
53 | * Skip Cache |
||
54 | * |
||
55 | * @param bool $status |
||
56 | * |
||
57 | * @return $this |
||
58 | */ |
||
59 | public function skipCache($status = true) |
||
60 | { |
||
61 | $this->cacheSkip = $status; |
||
62 | |||
63 | return $this; |
||
64 | } |
||
65 | |||
66 | /** |
||
67 | * @return bool |
||
68 | */ |
||
69 | public function isSkippedCache() |
||
70 | { |
||
71 | $skipped = isset($this->cacheSkip) ? $this->cacheSkip : false; |
||
72 | $request = app('Illuminate\Http\Request'); |
||
73 | $skipCacheParam = config('domains.repo-cache.params.skipCache', 'skipCache'); |
||
74 | |||
75 | if ($request->has($skipCacheParam) && $request->get($skipCacheParam)) { |
||
76 | $skipped = true; |
||
77 | } |
||
78 | |||
79 | return $skipped; |
||
80 | } |
||
81 | |||
82 | /** |
||
83 | * @param $method |
||
84 | * |
||
85 | * @return bool |
||
86 | */ |
||
87 | protected function allowedCache($method) |
||
88 | { |
||
89 | $cacheEnabled = config('domains.repo-cache.enabled', true); |
||
90 | |||
91 | if (!$cacheEnabled) { |
||
92 | return false; |
||
93 | } |
||
94 | |||
95 | $cacheOnly = isset($this->cacheOnly) ? $this->cacheOnly : config('domains.repo-cache.allowed.only', null); |
||
96 | $cacheExcept = isset($this->cacheExcept) ? $this->cacheExcept : config('domains.repo-cache.allowed.except', null); |
||
97 | |||
98 | if (is_array($cacheOnly)) { |
||
99 | return in_array($method, $cacheOnly); |
||
100 | } |
||
101 | |||
102 | if (is_array($cacheExcept)) { |
||
103 | return !in_array($method, $cacheExcept); |
||
104 | } |
||
105 | |||
106 | if (is_null($cacheOnly) && is_null($cacheExcept)) { |
||
107 | return true; |
||
108 | } |
||
109 | |||
110 | return false; |
||
111 | } |
||
112 | |||
113 | /** |
||
114 | * Get Cache key for the method |
||
115 | * |
||
116 | * @param $method |
||
117 | * @param $args |
||
118 | * |
||
119 | * @return string |
||
120 | */ |
||
121 | public function getCacheKey($method, $args = null) |
||
122 | { |
||
123 | |||
124 | $request = app('Illuminate\Http\Request'); |
||
125 | $args = serialize($args); |
||
126 | $criteria = $this->serializeCriteria(); |
||
127 | $key = sprintf('%s@%s-%s', get_called_class(), $method, md5($args . $criteria . $request->fullUrl())); |
||
128 | |||
129 | CacheKeys::putKey(get_called_class(), $key); |
||
130 | |||
131 | return $key; |
||
132 | |||
133 | } |
||
134 | |||
135 | /** |
||
136 | * Serialize the criteria making sure the Closures are taken care of. |
||
137 | * |
||
138 | * @return string |
||
139 | */ |
||
140 | protected function serializeCriteria() |
||
141 | { |
||
142 | try { |
||
143 | return serialize($this->getCriteria()); |
||
144 | } catch (Exception $e) { |
||
145 | return serialize($this->getCriteria()->map(function ($criterion) { |
||
146 | return $this->serializeCriterion($criterion); |
||
147 | })); |
||
148 | } |
||
149 | } |
||
150 | |||
151 | /** |
||
152 | * Serialize single criterion with customized serialization of Closures. |
||
153 | * |
||
154 | * @param \Salah3id\Domains\Repository\Contracts\CriteriaInterface $criterion |
||
155 | * @return \Salah3id\Domains\Repository\Contracts\CriteriaInterface|array |
||
156 | * |
||
157 | * @throws \Exception |
||
158 | */ |
||
159 | protected function serializeCriterion($criterion) |
||
160 | { |
||
161 | try { |
||
162 | serialize($criterion); |
||
163 | |||
164 | return $criterion; |
||
165 | } catch (Exception $e) { |
||
166 | // We want to take care of the closure serialization errors, |
||
167 | // other than that we will simply re-throw the exception. |
||
168 | if ($e->getMessage() !== "Serialization of 'Closure' is not allowed") { |
||
169 | throw $e; |
||
170 | } |
||
171 | |||
172 | $r = new ReflectionObject($criterion); |
||
173 | |||
174 | return [ |
||
175 | 'hash' => md5((string) $r), |
||
176 | ]; |
||
177 | } |
||
178 | } |
||
179 | |||
180 | /** |
||
181 | * Get cache time |
||
182 | * |
||
183 | * Return minutes: version < 5.8 |
||
184 | * Return seconds: version >= 5.8 |
||
185 | * |
||
186 | * @return int |
||
187 | */ |
||
188 | public function getCacheTime() |
||
200 | } |
||
201 | |||
202 | /** |
||
203 | * Retrieve all data of repository |
||
204 | * |
||
205 | * @param array $columns |
||
206 | * |
||
207 | * @return mixed |
||
208 | */ |
||
209 | public function all($columns = ['*']) |
||
210 | { |
||
211 | if (!$this->allowedCache('all') || $this->isSkippedCache()) { |
||
212 | return parent::all($columns); |
||
213 | } |
||
214 | |||
215 | $key = $this->getCacheKey('all', func_get_args()); |
||
216 | $time = $this->getCacheTime(); |
||
217 | $value = $this->getCacheRepository()->remember($key, $time, function () use ($columns) { |
||
218 | return parent::all($columns); |
||
219 | }); |
||
220 | |||
221 | $this->resetModel(); |
||
222 | $this->resetScope(); |
||
223 | return $value; |
||
224 | } |
||
225 | |||
226 | /** |
||
227 | * Retrieve all data of repository, paginated |
||
228 | * |
||
229 | * @param null $limit |
||
230 | * @param array $columns |
||
231 | * @param string $method |
||
232 | * |
||
233 | * @return mixed |
||
234 | */ |
||
235 | public function paginate($limit = null, $columns = ['*'], $method = 'paginate') |
||
236 | { |
||
237 | if (!$this->allowedCache('paginate') || $this->isSkippedCache()) { |
||
238 | return parent::paginate($limit, $columns, $method); |
||
239 | } |
||
240 | |||
241 | $key = $this->getCacheKey('paginate', func_get_args()); |
||
242 | |||
243 | $time = $this->getCacheTime(); |
||
244 | $value = $this->getCacheRepository()->remember($key, $time, function () use ($limit, $columns, $method) { |
||
245 | return parent::paginate($limit, $columns, $method); |
||
246 | }); |
||
247 | |||
248 | $this->resetModel(); |
||
249 | $this->resetScope(); |
||
250 | return $value; |
||
251 | } |
||
252 | |||
253 | /** |
||
254 | * Find data by id |
||
255 | * |
||
256 | * @param $id |
||
257 | * @param array $columns |
||
258 | * |
||
259 | * @return mixed |
||
260 | */ |
||
261 | public function find($id, $columns = ['*']) |
||
276 | } |
||
277 | |||
278 | /** |
||
279 | * Find data by field and value |
||
280 | * |
||
281 | * @param $field |
||
282 | * @param $value |
||
283 | * @param array $columns |
||
284 | * |
||
285 | * @return mixed |
||
286 | */ |
||
287 | public function findByField($field, $value = null, $columns = ['*']) |
||
302 | } |
||
303 | |||
304 | /** |
||
305 | * Find data by multiple fields |
||
306 | * |
||
307 | * @param array $where |
||
308 | * @param array $columns |
||
309 | * |
||
310 | * @return mixed |
||
311 | */ |
||
312 | public function findWhere(array $where, $columns = ['*']) |
||
327 | } |
||
328 | |||
329 | /** |
||
330 | * Find data by Criteria |
||
331 | * |
||
332 | * @param CriteriaInterface $criteria |
||
333 | * |
||
334 | * @return mixed |
||
335 | */ |
||
336 | public function getByCriteria(CriteriaInterface $criteria) |
||
351 | } |
||
352 | } |
||
353 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.