Complex classes like MetadataGrapher 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 MetadataGrapher, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
18 | class MetadataGrapher |
||
19 | { |
||
20 | /** |
||
21 | * Temporary array where already visited collections are stored |
||
22 | * |
||
23 | * @var mixed[] |
||
24 | */ |
||
25 | protected $visitedAssociations = []; |
||
26 | |||
27 | /** @var ClassMetadata[] */ |
||
28 | private $metadata; |
||
29 | |||
30 | /** |
||
31 | * Temporary array where reverse association name are stored |
||
32 | * |
||
33 | * @var ClassMetadata[] |
||
34 | */ |
||
35 | private $classByNames = []; |
||
36 | |||
37 | /** |
||
38 | * Generate a YUML compatible `dsl_text` to describe a given array |
||
39 | * of entities |
||
40 | * |
||
41 | * @param ClassMetadata[] $metadata |
||
42 | */ |
||
43 | 21 | public function generateFromMetadata(array $metadata) : string |
|
44 | { |
||
45 | 21 | $this->metadata = $metadata; |
|
46 | 21 | $this->visitedAssociations = []; |
|
47 | 21 | $str = []; |
|
48 | |||
49 | 21 | foreach ($metadata as $class) { |
|
50 | 21 | $parent = $this->getParent($class); |
|
51 | |||
52 | 21 | if ($parent) { |
|
53 | 3 | $str[] = $this->getClassString($parent) . '^' . $this->getClassString($class); |
|
54 | } |
||
55 | |||
56 | 21 | $associations = $class->getAssociationNames(); |
|
57 | |||
58 | 21 | if (empty($associations) && ! isset($this->visitedAssociations[$class->getName()])) { |
|
59 | 3 | $str[] = $this->getClassString($class); |
|
60 | |||
61 | 3 | continue; |
|
62 | } |
||
63 | |||
64 | 19 | foreach ($associations as $associationName) { |
|
65 | 17 | if ($parent && in_array($associationName, $parent->getAssociationNames())) { |
|
66 | 1 | continue; |
|
67 | } |
||
68 | |||
69 | 17 | if (! $this->visitAssociation($class->getName(), $associationName)) { |
|
70 | 12 | continue; |
|
71 | } |
||
72 | |||
73 | 17 | $str[] = $this->getAssociationString($class, $associationName); |
|
74 | } |
||
75 | } |
||
76 | |||
77 | 21 | return implode(',', $str); |
|
78 | } |
||
79 | |||
80 | 17 | private function getAssociationString(ClassMetadata $class1, string $association) : string |
|
122 | |||
123 | 15 | private function getClassReverseAssociationName(ClassMetadata $class1, ClassMetadata $class2) : ?string |
|
138 | |||
139 | /** |
||
140 | * Build the string representing the single graph item |
||
141 | */ |
||
142 | 21 | private function getClassString(ClassMetadata $class) : string |
|
172 | |||
173 | /** |
||
174 | * Retrieve a class metadata instance by name from the given array |
||
175 | */ |
||
176 | 19 | private function getClassByName(string $className) : ?ClassMetadata |
|
189 | |||
190 | /** |
||
191 | * Retrieve a class metadata's parent class metadata |
||
192 | */ |
||
193 | 21 | private function getParent(ClassMetadata $class) : ?ClassMetadata |
|
204 | |||
205 | /** |
||
206 | * Visit a given association and mark it as visited |
||
207 | * |
||
208 | * @return bool true if the association was visited before |
||
209 | */ |
||
210 | 21 | private function visitAssociation(string $className, ?string $association = null) : bool |
|
234 | } |
||
235 |