Complex classes like RepositoryTrait 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
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 RepositoryTrait, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
26 | trait RepositoryTrait |
||
27 | { |
||
28 | /** |
||
29 | * Supported magic methods. |
||
30 | * |
||
31 | * @var array |
||
32 | */ |
||
33 | protected static $supportedMethods = [ |
||
34 | 'findBy', |
||
35 | 'findOneBy', |
||
36 | 'findPaginatedBy', |
||
37 | 'removeBy', |
||
38 | 'removeOneBy', |
||
39 | 'countBy', |
||
40 | ]; |
||
41 | |||
42 | /** |
||
43 | * Methods that support exception throwing on fail. |
||
44 | * |
||
45 | * @var array |
||
46 | */ |
||
47 | protected static $falibleMethods = [ |
||
48 | 'findBy', |
||
49 | 'findOneBy', |
||
50 | 'findPaginatedBy', |
||
51 | ]; |
||
52 | |||
53 | /** |
||
54 | * Auto flush changes. |
||
55 | * |
||
56 | * @var bool |
||
57 | */ |
||
58 | protected $autoFlush = false; |
||
59 | |||
60 | /** |
||
61 | * New object factory. |
||
62 | * |
||
63 | * @var callable |
||
64 | */ |
||
65 | protected $objectFactory; |
||
66 | |||
67 | /** |
||
68 | * Get automatic manager flushing. |
||
69 | * |
||
70 | * @return bool |
||
71 | */ |
||
72 | public function isAutoFlush(): bool |
||
76 | |||
77 | /** |
||
78 | * Set automatic manager flushing. |
||
79 | * |
||
80 | * @param bool $autoFlush |
||
81 | */ |
||
82 | public function setAutoFlush(bool $autoFlush = true) |
||
86 | |||
87 | /** |
||
88 | * Manager flush. |
||
89 | */ |
||
90 | public function flush() |
||
94 | |||
95 | /** |
||
96 | * Find elements or throw an exception if none found. |
||
97 | * |
||
98 | * @param array $criteria |
||
99 | * @param array|null $orderBy |
||
100 | * @param int|null $limit |
||
101 | * @param int|null $offset |
||
102 | * |
||
103 | * @throws \DomainException |
||
104 | * |
||
105 | * @return object[] |
||
106 | */ |
||
107 | public function findByOrFail(array $criteria, array $orderBy = null, int $limit = null, int $offset = null): array |
||
117 | |||
118 | /** |
||
119 | * Find elements or throw an exception if none found. |
||
120 | * |
||
121 | * @param array $criteria |
||
122 | * |
||
123 | * @throws \DomainException |
||
124 | * |
||
125 | * @return object |
||
126 | */ |
||
127 | public function findOneByOrFail(array $criteria) |
||
137 | |||
138 | /** |
||
139 | * Find one object by a set of criteria or create a new one. |
||
140 | * |
||
141 | * @param array $criteria |
||
142 | * |
||
143 | * @throws \RuntimeException |
||
144 | * |
||
145 | * @return object |
||
146 | */ |
||
147 | public function findOneByOrGetNew(array $criteria) |
||
157 | |||
158 | /** |
||
159 | * Get a new managed object instance. |
||
160 | * |
||
161 | * @throws \RuntimeException |
||
162 | * |
||
163 | * @return object |
||
164 | */ |
||
165 | public function getNew() |
||
181 | |||
182 | /** |
||
183 | * Get object factory. |
||
184 | * |
||
185 | * @return callable |
||
186 | */ |
||
187 | private function getObjectFactory(): callable |
||
199 | |||
200 | /** |
||
201 | * Set object factory. |
||
202 | * |
||
203 | * @param callable $objectFactory |
||
204 | */ |
||
205 | public function setObjectFactory(callable $objectFactory) |
||
209 | |||
210 | /** |
||
211 | * Add objects. |
||
212 | * |
||
213 | * @param object|iterable $objects |
||
214 | * @param bool $flush |
||
215 | * |
||
216 | * @throws \InvalidArgumentException |
||
217 | */ |
||
218 | public function add($objects, bool $flush = false) |
||
222 | |||
223 | /** |
||
224 | * Remove all objects. |
||
225 | * |
||
226 | * @param bool $flush |
||
227 | */ |
||
228 | public function removeAll(bool $flush = false) |
||
232 | |||
233 | /** |
||
234 | * Remove object filtered by a set of criteria. |
||
235 | * |
||
236 | * @param array $criteria |
||
237 | * @param bool $flush |
||
238 | */ |
||
239 | public function removeBy(array $criteria, bool $flush = false) |
||
243 | |||
244 | /** |
||
245 | * Remove first object filtered by a set of criteria. |
||
246 | * |
||
247 | * @param array $criteria |
||
248 | * @param bool $flush |
||
249 | */ |
||
250 | public function removeOneBy(array $criteria, bool $flush = false) |
||
254 | |||
255 | /** |
||
256 | * Remove objects. |
||
257 | * |
||
258 | * @param object|iterable|string|int $objects |
||
259 | * @param bool $flush |
||
260 | * |
||
261 | * @throws \InvalidArgumentException |
||
262 | */ |
||
263 | public function remove($objects, bool $flush = false) |
||
271 | |||
272 | /** |
||
273 | * Refresh objects. |
||
274 | * |
||
275 | * @param object|iterable $objects |
||
276 | * |
||
277 | * @throws \InvalidArgumentException |
||
278 | */ |
||
279 | public function refresh($objects) |
||
288 | |||
289 | /** |
||
290 | * Detach objects. |
||
291 | * |
||
292 | * @param object|iterable $objects |
||
293 | * |
||
294 | * @throws \InvalidArgumentException |
||
295 | */ |
||
296 | public function detach($objects) |
||
305 | |||
306 | /** |
||
307 | * Get all objects count. |
||
308 | * |
||
309 | * @return int |
||
310 | */ |
||
311 | public function countAll(): int |
||
315 | |||
316 | /** |
||
317 | * Get object count filtered by a set of criteria. |
||
318 | * |
||
319 | * @param mixed $criteria |
||
320 | * |
||
321 | * @return int |
||
322 | */ |
||
323 | abstract public function countBy($criteria): int; |
||
324 | |||
325 | /** |
||
326 | * Adds support for magic methods. |
||
327 | * |
||
328 | * @param string $method |
||
329 | * @param array $arguments |
||
330 | * |
||
331 | * @throws \BadMethodCallException |
||
332 | * |
||
333 | * @return mixed |
||
334 | */ |
||
335 | public function __call($method, $arguments) |
||
360 | |||
361 | /** |
||
362 | * Get supported magic method. |
||
363 | * |
||
364 | * @param string $method |
||
365 | * |
||
366 | * @throws \BadMethodCallException |
||
367 | * |
||
368 | * @return string |
||
369 | */ |
||
370 | private function getSupportedMethod(string $method): string |
||
384 | |||
385 | /** |
||
386 | * Internal method call. |
||
387 | * |
||
388 | * @param string $method |
||
389 | * @param string $fieldName |
||
390 | * @param array $arguments |
||
391 | * |
||
392 | * @throws \BadMethodCallException |
||
393 | * |
||
394 | * @return mixed |
||
395 | */ |
||
396 | protected function callSupportedMethod(string $method, string $fieldName, array $arguments) |
||
418 | |||
419 | /** |
||
420 | * Run manager action. |
||
421 | * |
||
422 | * @param string $action |
||
423 | * @param object|iterable $objects |
||
424 | * @param bool $flush |
||
425 | * |
||
426 | * @throws \InvalidArgumentException |
||
427 | */ |
||
428 | protected function runManagerAction(string $action, $objects, bool $flush) |
||
458 | |||
459 | /** |
||
460 | * Flush managed objects. |
||
461 | * |
||
462 | * @param array $objects |
||
463 | * @param bool $flush |
||
464 | */ |
||
465 | protected function flushObjects(array $objects, bool $flush) |
||
471 | |||
472 | /** |
||
473 | * Check if the object is of the proper type. |
||
474 | * |
||
475 | * @param object $object |
||
476 | * |
||
477 | * @return bool |
||
478 | */ |
||
479 | protected function canBeManaged($object): bool |
||
485 | |||
486 | /** |
||
487 | * Returns the fully qualified class name of the objects managed by the repository. |
||
488 | * |
||
489 | * @return string |
||
490 | */ |
||
491 | abstract public function getClassName(): string; |
||
492 | |||
493 | /** |
||
494 | * Get object manager. |
||
495 | * |
||
496 | * @return \Doctrine\Common\Persistence\ObjectManager |
||
497 | */ |
||
498 | abstract protected function getManager(); |
||
499 | |||
500 | /** |
||
501 | * Get class metadata. |
||
502 | * |
||
503 | * @return \Doctrine\Common\Persistence\Mapping\ClassMetadata |
||
504 | */ |
||
505 | abstract protected function getClassMetadata(); |
||
506 | } |
||
507 |
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.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.