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 |
||
31 | class MetadataGrapher |
||
32 | { |
||
33 | /** |
||
34 | * Temporary array where already visited collections are stored |
||
35 | * |
||
36 | * @var array |
||
37 | */ |
||
38 | protected $visitedAssociations = array(); |
||
39 | |||
40 | /** |
||
41 | * @var \Doctrine\Common\Persistence\Mapping\ClassMetadata[] |
||
42 | */ |
||
43 | private $metadata; |
||
44 | |||
45 | /** |
||
46 | * Temporary array where reverse association name are stored |
||
47 | * |
||
48 | * @var \Doctrine\Common\Persistence\Mapping\ClassMetadata[] |
||
49 | */ |
||
50 | private $classByNames = array(); |
||
51 | |||
52 | /** |
||
53 | * Generate a YUML compatible `dsl_text` to describe a given array |
||
54 | * of entities |
||
55 | * |
||
56 | * @param $metadata \Doctrine\Common\Persistence\Mapping\ClassMetadata[] |
||
57 | * |
||
58 | * @return string |
||
59 | */ |
||
60 | 21 | public function generateFromMetadata(array $metadata) |
|
61 | { |
||
62 | 21 | $this->metadata = $metadata; |
|
63 | 21 | $this->visitedAssociations = array(); |
|
64 | 21 | $str = array(); |
|
65 | |||
66 | 21 | foreach ($metadata as $class) { |
|
67 | 21 | $parent = $this->getParent($class); |
|
68 | |||
69 | 21 | if ($parent) { |
|
70 | 3 | $str[] = $this->getClassString($parent) . '^' . $this->getClassString($class); |
|
71 | 3 | } |
|
72 | |||
73 | 21 | $associations = $class->getAssociationNames(); |
|
74 | |||
75 | 21 | if (empty($associations) && !isset($this->visitedAssociations[$class->getName()])) { |
|
76 | 3 | $str[] = $this->getClassString($class); |
|
77 | |||
78 | 3 | continue; |
|
79 | } |
||
80 | |||
81 | 19 | foreach ($associations as $associationName) { |
|
82 | 17 | if ($parent && in_array($associationName, $parent->getAssociationNames())) { |
|
83 | 1 | continue; |
|
84 | } |
||
85 | |||
86 | 17 | if ($this->visitAssociation($class->getName(), $associationName)) { |
|
87 | 17 | $str[] = $this->getAssociationString($class, $associationName); |
|
88 | 17 | } |
|
89 | 19 | } |
|
90 | 21 | } |
|
91 | |||
92 | 21 | return implode(',', $str); |
|
93 | } |
||
94 | |||
95 | /** |
||
96 | * @param ClassMetadata $class1 |
||
97 | * @param string $association |
||
98 | * @return string |
||
99 | */ |
||
100 | 17 | private function getAssociationString(ClassMetadata $class1, $association) |
|
142 | |||
143 | /** |
||
144 | * @param ClassMetadata $class1 |
||
145 | * @param ClassMetadata $class2 |
||
146 | * @return string|null |
||
147 | */ |
||
148 | 15 | private function getClassReverseAssociationName(ClassMetadata $class1, ClassMetadata $class2) |
|
159 | |||
160 | /** |
||
161 | * Build the string representing the single graph item |
||
162 | * |
||
163 | * @param ClassMetadata $class |
||
164 | * |
||
165 | * @return string |
||
166 | */ |
||
167 | 21 | private function getClassString(ClassMetadata $class) |
|
197 | |||
198 | /** |
||
199 | * Retrieve a class metadata instance by name from the given array |
||
200 | * |
||
201 | * @param string $className |
||
202 | * |
||
203 | * @return ClassMetadata|null |
||
204 | */ |
||
205 | 19 | private function getClassByName($className) |
|
218 | |||
219 | /** |
||
220 | * Retrieve a class metadata's parent class metadata |
||
221 | * |
||
222 | * @param ClassMetadata $class |
||
223 | * |
||
224 | * @return ClassMetadata|null |
||
225 | */ |
||
226 | 21 | private function getParent($class) |
|
227 | { |
||
228 | 21 | $className = $class->getName(); |
|
229 | |||
230 | 21 | if (!class_exists($className) || (!$parent = get_parent_class($className))) { |
|
231 | 21 | return null; |
|
232 | } |
||
233 | |||
234 | 3 | return $this->getClassByName($parent); |
|
235 | } |
||
236 | |||
237 | /** |
||
238 | * Visit a given association and mark it as visited |
||
239 | * |
||
240 | * @param string $className |
||
241 | * @param string|null $association |
||
242 | * |
||
243 | * @return bool true if the association was visited before |
||
244 | */ |
||
245 | 21 | private function visitAssociation($className, $association = null) |
|
269 | } |
||
270 |