Complex classes like ManyToManyRelation 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 ManyToManyRelation, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
33 | class ManyToManyRelation extends MultipleRelation implements \IteratorAggregate, \Countable |
||
34 | { |
||
35 | use LookupTrait; |
||
36 | |||
37 | /** |
||
38 | * @var Table|null |
||
39 | */ |
||
40 | private $pivotTable = null; |
||
41 | |||
42 | /** |
||
43 | * @var \SplObjectStorage |
||
44 | */ |
||
45 | private $pivotData; |
||
46 | |||
47 | /** |
||
48 | * Linked but not saved yet records. |
||
49 | * |
||
50 | * @var array |
||
51 | */ |
||
52 | private $scheduled = []; |
||
53 | |||
54 | /** |
||
55 | * Record which pivot data was updated, record must still present in linked array. |
||
56 | * |
||
57 | * @var array |
||
58 | */ |
||
59 | private $updated = []; |
||
60 | |||
61 | /** |
||
62 | * Records scheduled to be de-associated. |
||
63 | * |
||
64 | * @var RecordInterface[] |
||
65 | */ |
||
66 | private $unlinked = []; |
||
67 | |||
68 | /** |
||
69 | * When target role is null parent role to be used. Redefine this variable to revert behaviour |
||
70 | * of ManyToMany relation. |
||
71 | * |
||
72 | * @see ManyToMorphedRelation |
||
73 | * @var string|null |
||
74 | */ |
||
75 | private $targetRole = null; |
||
76 | |||
77 | /** |
||
78 | * @param string $class |
||
79 | * @param array $schema |
||
80 | * @param \Spiral\ORM\ORMInterface $orm |
||
81 | * @param string|null $targetRole |
||
82 | */ |
||
83 | public function __construct($class, array $schema, ORMInterface $orm, string $targetRole = null) |
||
89 | |||
90 | /** |
||
91 | * {@inheritdoc} |
||
92 | * |
||
93 | * Pivot data must be set separatelly. |
||
94 | */ |
||
95 | public function setRelated($value) |
||
132 | |||
133 | /** |
||
134 | * Get all unlinked records. |
||
135 | * |
||
136 | * @return \ArrayIterator |
||
137 | */ |
||
138 | public function getUnlinked() |
||
142 | |||
143 | /** |
||
144 | * Get pivot data associated with specific instance. |
||
145 | * |
||
146 | * @param RecordInterface $record |
||
147 | * |
||
148 | * @return array |
||
149 | */ |
||
150 | public function getPivot(RecordInterface $record): array |
||
158 | |||
159 | /** |
||
160 | * Link record with parent entity. Only record instances is accepted. |
||
161 | * |
||
162 | * Attention, attached instances MIGHT be de-referenced IF parent object was reselected in a |
||
163 | * different scope. |
||
164 | * |
||
165 | * @param RecordInterface $record |
||
166 | * @param array $pivotData |
||
167 | * |
||
168 | * @return self |
||
169 | * |
||
170 | * @throws RelationException |
||
171 | */ |
||
172 | public function link(RecordInterface $record, array $pivotData = []): self |
||
200 | |||
201 | /** |
||
202 | * Unlink specific entity from relation. Will load relation data! Record to delete will be |
||
203 | * automatically matched to a give record. |
||
204 | * |
||
205 | * @param RecordInterface $record |
||
206 | * |
||
207 | * @return self |
||
208 | * |
||
209 | * @throws RelationException When entity not linked. |
||
210 | */ |
||
211 | public function unlink(RecordInterface $record): self |
||
235 | |||
236 | /** |
||
237 | * {@inheritdoc} |
||
238 | */ |
||
239 | public function queueCommands(ContextualCommandInterface $parentCommand): CommandInterface |
||
324 | |||
325 | /** |
||
326 | * Insane method used to properly set pivot command context (where or insert statement) based on |
||
327 | * parent and outer records AND/OR based on command promises. |
||
328 | * |
||
329 | * @param ContextualCommandInterface $pivotCommand |
||
330 | * @param RecordInterface $parent |
||
331 | * @param ContextualCommandInterface $parentCommand |
||
332 | * @param RecordInterface $outer |
||
333 | * @param ContextualCommandInterface $outerCommand |
||
334 | * |
||
335 | * @return ContextualCommandInterface |
||
336 | */ |
||
337 | protected function ensureContext( |
||
366 | |||
367 | /** |
||
368 | * Fetch data from database. Lazy load. Method require a bit of love. |
||
369 | * |
||
370 | * @return array |
||
371 | */ |
||
372 | protected function loadRelated(): array |
||
402 | |||
403 | /** |
||
404 | * Create query for lazy loading. |
||
405 | * |
||
406 | * @param mixed $innerKey |
||
407 | * |
||
408 | * @return SelectQuery |
||
409 | */ |
||
410 | protected function createQuery($innerKey): SelectQuery |
||
456 | |||
457 | /** |
||
458 | * Init relations and populate pivot map. |
||
459 | * |
||
460 | * @return self|MultipleRelation |
||
461 | */ |
||
462 | protected function initInstances(): MultipleRelation |
||
484 | |||
485 | /** |
||
486 | * @return Table |
||
487 | */ |
||
488 | private function pivotTable() |
||
500 | |||
501 | /** |
||
502 | * Make sure that pivot data in a valid format. |
||
503 | * |
||
504 | * @param array $pivotData |
||
505 | * |
||
506 | * @throws RelationException |
||
507 | */ |
||
508 | private function assertPivot(array $pivotData) |
||
516 | |||
517 | /** |
||
518 | * Defined role to be used in morphed relations. |
||
519 | * |
||
520 | * @return string |
||
521 | */ |
||
522 | private function targetRole(): string |
||
529 | } |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.