Complex classes like ResourceGenerator 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 ResourceGenerator, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
29 | class ResourceGenerator extends AbstractGenerator |
||
30 | { |
||
31 | /** |
||
32 | * @private Filesystem |
||
33 | */ |
||
34 | private $filesystem; |
||
35 | |||
36 | /** |
||
37 | * @private DoctrineRegistry |
||
38 | */ |
||
39 | private $doctrine; |
||
40 | |||
41 | /** |
||
42 | * @private HttpKernelInterface |
||
43 | */ |
||
44 | private $kernel; |
||
45 | |||
46 | /** |
||
47 | * our json file definition |
||
48 | * |
||
49 | * @var JsonDefinition|null |
||
50 | */ |
||
51 | private $json = null; |
||
52 | |||
53 | /** |
||
54 | * @var ArrayCollection |
||
55 | */ |
||
56 | protected $xmlParameters; |
||
57 | |||
58 | /** |
||
59 | * @var \DomDocument |
||
60 | */ |
||
61 | private $serviceDOM; |
||
62 | |||
63 | /** |
||
64 | * @var FieldMapper |
||
65 | */ |
||
66 | private $mapper; |
||
67 | |||
68 | /** |
||
69 | * @var boolean |
||
70 | */ |
||
71 | private $generateController = false; |
||
72 | |||
73 | /** |
||
74 | * @var ParameterBuilder |
||
75 | */ |
||
76 | private $parameterBuilder; |
||
77 | |||
78 | /** |
||
79 | * Instantiates generator object |
||
80 | * |
||
81 | * @param Filesystem $filesystem fs abstraction layer |
||
82 | * @param DoctrineRegistry $doctrine odm registry |
||
83 | * @param HttpKernelInterface $kernel app kernel |
||
84 | * @param FieldMapper $mapper field type mapper |
||
85 | * @param ParameterBuilder $parameterBuilder param builder |
||
86 | */ |
||
87 | 4 | public function __construct( |
|
88 | Filesystem $filesystem, |
||
89 | DoctrineRegistry $doctrine, |
||
90 | HttpKernelInterface $kernel, |
||
91 | FieldMapper $mapper, |
||
92 | ParameterBuilder $parameterBuilder |
||
93 | ) { |
||
94 | 4 | $this->filesystem = $filesystem; |
|
95 | 4 | $this->doctrine = $doctrine; |
|
96 | 4 | $this->kernel = $kernel; |
|
97 | 4 | $this->mapper = $mapper; |
|
98 | 4 | $this->parameterBuilder = $parameterBuilder; |
|
99 | 4 | $this->xmlParameters = new ArrayCollection(); |
|
100 | 4 | } |
|
101 | |||
102 | /** |
||
103 | * @param JsonDefinition $json optional JsonDefinition object |
||
104 | * |
||
105 | * @return void |
||
106 | */ |
||
107 | public function setJson(JsonDefinition $json) |
||
108 | { |
||
109 | $this->json = $json; |
||
110 | } |
||
111 | |||
112 | /** |
||
113 | * @param boolean $generateController should the controller be generated or not |
||
114 | * |
||
115 | * @return void |
||
116 | */ |
||
117 | public function setGenerateController($generateController) |
||
118 | { |
||
119 | $this->generateController = $generateController; |
||
120 | } |
||
121 | |||
122 | /** |
||
123 | * generate the resource with all its bits and parts |
||
124 | * |
||
125 | * @param BundleInterface $bundle bundle |
||
126 | * @param string $document document name |
||
127 | * @param string $format format of config files (please use xml) |
||
128 | * @param array $fields fields to add |
||
129 | * |
||
130 | * @return EntityGeneratorResult |
||
131 | */ |
||
132 | public function generate( |
||
133 | BundleInterface $bundle, |
||
134 | $document, |
||
135 | $format, |
||
136 | array $fields |
||
137 | ) { |
||
138 | $dir = $bundle->getPath(); |
||
139 | $basename = $this->getBundleBaseName($document); |
||
140 | $bundleNamespace = substr(get_class($bundle), 0, 0 - strlen($bundle->getName())); |
||
141 | |||
142 | if (!is_null($this->json)) { |
||
143 | $this->json->setNamespace($bundleNamespace); |
||
144 | } |
||
145 | |||
146 | // add more info to the fields array |
||
147 | $mapper = $this->mapper; |
||
148 | $fields = array_map( |
||
149 | function ($field) use ($mapper) { |
||
150 | return $mapper->map($field, $this->json); |
||
151 | }, |
||
152 | $fields |
||
153 | ); |
||
154 | |||
155 | $parameters = $this->parameterBuilder |
||
156 | ->setParameter('document', $document) |
||
157 | ->setParameter('base', $bundleNamespace) |
||
158 | ->setParameter('bundle', $bundle->getName()) |
||
159 | ->setParameter('format', $format) |
||
160 | ->setParameter('json', $this->json) |
||
161 | ->setParameter('fields', $fields) |
||
162 | ->setParameter('basename', $basename) |
||
163 | ->setParameter('isrecordOriginFlagSet', $this->json->isRecordOriginFlagSet()) |
||
164 | ->setParameter('recordOriginModifiable', $this->json->isRecordOriginModifiable()) |
||
165 | ->setParameter('isVersioning', $this->json->isVersionedService()) |
||
166 | ->setParameter('collection', $this->json->getServiceCollection()) |
||
167 | ->setParameter('indexes', $this->json->getIndexes()) |
||
168 | ->setParameter('textIndexes', $this->json->getAllTextIndexes()) |
||
169 | ->getParameters(); |
||
170 | |||
171 | $this->generateDocument($parameters, $dir, $document); |
||
172 | $this->generateSerializer($parameters, $dir, $document); |
||
173 | $this->generateModel($parameters, $dir, $document); |
||
174 | |||
175 | if ($this->json instanceof JsonDefinition && $this->json->hasFixtures() === true) { |
||
176 | $this->generateFixtures($parameters, $dir, $document); |
||
177 | } |
||
178 | |||
179 | if ($this->generateController) { |
||
180 | $this->generateController($parameters, $dir, $document); |
||
181 | } |
||
182 | |||
183 | $this->generateParameters($dir); |
||
184 | |||
185 | return new EntityGeneratorResult( |
||
186 | $dir . '/Document/' . $document . '.php', |
||
187 | $dir . '/Repository/' . $document . 'Repository.php', |
||
188 | $dir . '/Resources/config/doctrine/' . $document . '.mongodb.xml' |
||
189 | ); |
||
190 | } |
||
191 | |||
192 | /** |
||
193 | * Writes the current services definition to a file. |
||
194 | * |
||
195 | * @param string $dir base bundle dir |
||
196 | * |
||
197 | * @return void |
||
198 | */ |
||
199 | 8 | protected function persistServicesXML($dir) |
|
200 | { |
||
201 | 8 | $services = $this->loadServices($dir); |
|
202 | |||
203 | 8 | file_put_contents($dir . '/Resources/config/services.xml', $services->saveXML()); |
|
204 | 8 | } |
|
205 | |||
206 | /** |
||
207 | * generate document part of a resource |
||
208 | * |
||
209 | * @param array $parameters twig parameters |
||
210 | * @param string $dir base bundle dir |
||
211 | * @param string $document document name |
||
212 | * |
||
213 | * @return void |
||
214 | */ |
||
215 | 6 | protected function generateDocument($parameters, $dir, $document) |
|
216 | { |
||
217 | // doctrine mapping normal class |
||
218 | 6 | $this->renderFile( |
|
219 | 6 | 'document/Document.mongodb.xml.twig', |
|
220 | 6 | $dir . '/Resources/config/doctrine/' . $document . '.mongodb.xml', |
|
221 | 3 | $parameters |
|
222 | 3 | ); |
|
223 | |||
224 | // doctrine mapping embedded |
||
225 | 6 | $this->renderFile( |
|
226 | 6 | 'document/Document.mongodb.xml.twig', |
|
227 | 6 | $dir . '/Resources/config/doctrine/' . $document . 'Embedded.mongodb.xml', |
|
228 | 6 | array_merge( |
|
229 | 6 | $parameters, |
|
230 | [ |
||
231 | 6 | 'document' => $document.'Embedded', |
|
232 | 3 | 'docType' => 'embedded-document' |
|
233 | 3 | ] |
|
234 | 3 | ) |
|
235 | 3 | ); |
|
236 | |||
237 | 6 | $this->renderFile( |
|
238 | 6 | 'document/Document.php.twig', |
|
239 | 6 | $dir . '/Document/' . $document . '.php', |
|
240 | 3 | $parameters |
|
241 | 3 | ); |
|
242 | 6 | $this->renderFile( |
|
243 | 6 | 'document/DocumentEmbedded.php.twig', |
|
244 | 6 | $dir . '/Document/' . $document . 'Embedded.php', |
|
245 | 3 | $parameters |
|
246 | 3 | ); |
|
247 | 6 | $this->renderFile( |
|
248 | 6 | 'document/DocumentBase.php.twig', |
|
249 | 6 | $dir . '/Document/' . $document . 'Base.php', |
|
250 | 3 | $parameters |
|
251 | 3 | ); |
|
252 | |||
253 | 6 | $this->generateServices($parameters, $dir, $document); |
|
254 | 6 | } |
|
255 | |||
256 | /** |
||
257 | * update xml services |
||
258 | * |
||
259 | * @param array $parameters twig parameters |
||
260 | * @param string $dir base bundle dir |
||
261 | * @param string $document document name |
||
262 | * |
||
263 | * @return void |
||
264 | */ |
||
265 | 6 | protected function generateServices($parameters, $dir, $document) |
|
266 | { |
||
267 | 6 | $services = $this->loadServices($dir); |
|
268 | |||
269 | 6 | $bundleParts = explode('\\', $parameters['base']); |
|
270 | 6 | $shortName = $bundleParts[0]; |
|
271 | 6 | $shortBundle = $this->getBundleBaseName($bundleParts[1]); |
|
272 | |||
273 | 6 | $docName = implode( |
|
274 | 6 | '.', |
|
275 | array( |
||
276 | 6 | strtolower($shortName), |
|
277 | 6 | strtolower($shortBundle), |
|
278 | 6 | 'document', |
|
279 | 6 | strtolower($parameters['document']) |
|
280 | 3 | ) |
|
281 | 3 | ); |
|
282 | |||
283 | 6 | $this->addXMLParameter( |
|
284 | 6 | $parameters['base'] . 'Document\\' . $parameters['document'], |
|
285 | 3 | $docName . '.class' |
|
286 | 3 | ); |
|
287 | |||
288 | 6 | $this->addXMLParameter( |
|
289 | 6 | $parameters['json']->getRoles(), |
|
290 | 6 | $docName . '.roles', |
|
291 | 3 | 'collection' |
|
292 | 3 | ); |
|
293 | |||
294 | 6 | $services = $this->addService( |
|
295 | 6 | $services, |
|
296 | 3 | $docName |
|
297 | 3 | ); |
|
298 | |||
299 | 6 | $repoName = implode( |
|
300 | 6 | '.', |
|
301 | array( |
||
302 | 6 | strtolower($shortName), |
|
303 | 6 | strtolower($shortBundle), |
|
304 | 6 | 'repository', |
|
305 | 6 | strtolower($parameters['document']) |
|
306 | 3 | ) |
|
307 | 3 | ); |
|
308 | |||
309 | // normal repo service |
||
310 | 6 | $services = $this->addParam( |
|
311 | 6 | $services, |
|
312 | 6 | $repoName . '.class', |
|
313 | 6 | $parameters['base'] . 'Repository\\' . $parameters['document'] |
|
314 | 3 | ); |
|
315 | |||
316 | 6 | $this->addService( |
|
317 | 6 | $services, |
|
318 | 6 | $repoName, |
|
319 | 6 | null, |
|
320 | 6 | array(), |
|
321 | 6 | null, |
|
322 | array( |
||
323 | array( |
||
324 | 6 | 'type' => 'string', |
|
325 | 6 | 'value' => $parameters['bundle'] . ':' . $document |
|
326 | 3 | ) |
|
327 | 3 | ), |
|
328 | 6 | 'doctrine_mongodb.odm.default_document_manager', |
|
329 | 3 | 'getRepository' |
|
330 | 3 | ); |
|
331 | |||
332 | // embedded repo service |
||
333 | 6 | $services = $this->addParam( |
|
334 | 6 | $services, |
|
335 | 6 | $repoName . 'embedded.class', |
|
336 | 6 | $parameters['base'] . 'Repository\\' . $parameters['document'] . 'Embedded' |
|
337 | 3 | ); |
|
338 | |||
339 | 6 | $this->addService( |
|
340 | 6 | $services, |
|
341 | 6 | $repoName . 'embedded', |
|
342 | 6 | null, |
|
343 | 6 | array(), |
|
344 | 6 | null, |
|
345 | array( |
||
346 | array( |
||
347 | 6 | 'type' => 'string', |
|
348 | 6 | 'value' => $parameters['bundle'] . ':' . $document . 'Embedded' |
|
349 | 3 | ) |
|
350 | 3 | ), |
|
351 | 6 | 'doctrine_mongodb.odm.default_document_manager', |
|
352 | 3 | 'getRepository' |
|
353 | 3 | ); |
|
354 | |||
355 | 6 | $this->renderFile( |
|
356 | 6 | 'document/DocumentRepository.php.twig', |
|
357 | 6 | $dir . '/Repository/' . $document . 'Repository.php', |
|
358 | 3 | $parameters |
|
359 | 3 | ); |
|
360 | 6 | $this->renderFile( |
|
361 | 6 | 'document/DocumentRepository.php.twig', |
|
362 | 6 | $dir . '/Repository/' . $document . 'EmbeddedRepository.php', |
|
363 | 6 | array_merge( |
|
364 | 6 | $parameters, |
|
365 | [ |
||
366 | 6 | 'document' => $document.'Embedded', |
|
367 | ] |
||
368 | 3 | ) |
|
369 | 3 | ); |
|
370 | |||
371 | 6 | $this->persistServicesXML($dir); |
|
372 | 6 | } |
|
373 | |||
374 | /** |
||
375 | * Generates the parameters section of the services.xml file. |
||
376 | * |
||
377 | * @param string $dir base bundle dir |
||
378 | * |
||
379 | * @return void |
||
380 | */ |
||
381 | 2 | protected function generateParameters($dir) |
|
400 | |||
401 | /** |
||
402 | * Registers information to be generated to a parameter tag. |
||
403 | * |
||
404 | * @param mixed $value Content of the tag |
||
405 | * @param string $key Content of the key attribute |
||
406 | * @param string $type Type of the tag |
||
407 | * |
||
408 | * @return void |
||
409 | */ |
||
410 | 2 | protected function addXmlParameter($value, $key, $type = 'string') |
|
426 | |||
427 | /** |
||
428 | * load services.xml |
||
429 | * |
||
430 | * @param string $dir base dir |
||
431 | * |
||
432 | * @return \DOMDocument |
||
433 | */ |
||
434 | 4 | protected function loadServices($dir) |
|
445 | |||
446 | /** |
||
447 | * add param to services.xml |
||
448 | * |
||
449 | * @param \DOMDocument $dom services.xml document |
||
450 | * @param string $key parameter key |
||
451 | * @param string $value parameter value |
||
452 | * |
||
453 | * @return \DOMDocument |
||
454 | */ |
||
455 | 12 | protected function addParam(\DOMDocument $dom, $key, $value) |
|
469 | |||
470 | /** |
||
471 | * Adds a new parameter tag to parameters section reflecting the defined roles. |
||
472 | * |
||
473 | * @param \DOMDocument $dom services.xml document |
||
474 | * @param string $key parameter key |
||
475 | * @param array $values parameter value |
||
476 | * |
||
477 | * @return void |
||
478 | * |
||
479 | * @link http://symfony.com/doc/current/book/service_container.html#array-parameters |
||
480 | */ |
||
481 | 4 | protected function addCollectionParam(\DomDocument $dom, $key, array $values) |
|
500 | |||
501 | /** |
||
502 | * Determines, if the provided key attribute was already claimed by a parameter node. |
||
503 | * |
||
504 | * @param \DomDocument $dom Current document |
||
505 | * @param string $key Key to be found in document |
||
506 | * |
||
507 | * @return bool |
||
508 | */ |
||
509 | 14 | private function parameterNodeExists(\DomDocument $dom, $key) |
|
516 | |||
517 | /** |
||
518 | * add node if missing |
||
519 | * |
||
520 | * @param \DOMDocument $dom document |
||
521 | * @param string $element name for new node element |
||
522 | * @param string $insertBefore xPath query of the new node shall be added before |
||
523 | * @param string $container name of container tag |
||
524 | * |
||
525 | * @return \DOMNode new element node |
||
526 | */ |
||
527 | 14 | private function addNodeIfMissing(&$dom, $element, $insertBefore = '', $container = 'container') |
|
553 | |||
554 | /** |
||
555 | * add attribute to node if needed |
||
556 | * |
||
557 | * @param string $name attribute name |
||
558 | * @param string $value attribute value |
||
559 | * @param \DOMDocument $dom document |
||
560 | * @param \DOMElement $node parent node |
||
561 | * |
||
562 | * @return void |
||
563 | */ |
||
564 | 14 | private function addAttributeToNode($name, $value, $dom, $node) |
|
572 | |||
573 | /** |
||
574 | * add service to services.xml |
||
575 | * |
||
576 | * @param \DOMDocument $dom services.xml dom |
||
577 | * @param string $id id of new service |
||
578 | * @param string $parent parent for service |
||
|
|||
579 | * @param array $calls methodCalls to add |
||
580 | * @param string $tag tag name or empty if no tag needed |
||
581 | * @param array $arguments service arguments |
||
582 | * @param string $factoryService factory service id |
||
583 | * @param string $factoryMethod factory method name |
||
584 | * |
||
585 | * @return \DOMDocument |
||
586 | */ |
||
587 | protected function addService( |
||
649 | |||
650 | /** |
||
651 | * add calls to service |
||
652 | * |
||
653 | * @param array $calls info on calls to create |
||
654 | * @param \DOMDocument $dom current domdocument |
||
655 | * @param \DOMElement $node node to add call to |
||
656 | * |
||
657 | * @return void |
||
658 | */ |
||
659 | private function addCallsToService($calls, $dom, $node) |
||
665 | |||
666 | /** |
||
667 | * add call to service |
||
668 | * |
||
669 | * @param array $call info on call node to create |
||
670 | * @param \DOMDocument $dom current domdocument |
||
671 | * @param \DOMElement $node node to add call to |
||
672 | * |
||
673 | * @return void |
||
674 | */ |
||
675 | private function addCallToService($call, $dom, $node) |
||
697 | |||
698 | /** |
||
699 | * add arguments to servie |
||
700 | * |
||
701 | * @param array $arguments arguments to create |
||
702 | * @param \DOMDocument $dom dom document to add to |
||
703 | * @param \DOMElement $node node to use as parent |
||
704 | * |
||
705 | * @return void |
||
706 | */ |
||
707 | private function addArgumentsToService($arguments, $dom, $node) |
||
713 | |||
714 | /** |
||
715 | * add argument to service |
||
716 | * |
||
717 | * @param array $argument info on argument to create |
||
718 | * @param \DOMDocument $dom dom document to add to |
||
719 | * @param \DOMElement $node node to use as parent |
||
720 | * |
||
721 | * @return void |
||
722 | */ |
||
723 | private function addArgumentToService($argument, $dom, $node) |
||
743 | |||
744 | /** |
||
745 | * generate serializer part of a resource |
||
746 | * |
||
747 | * @param array $parameters twig parameters |
||
748 | * @param string $dir base bundle dir |
||
749 | * @param string $document document name |
||
750 | * |
||
751 | * @return void |
||
752 | */ |
||
753 | protected function generateSerializer(array $parameters, $dir, $document) |
||
804 | |||
805 | /** |
||
806 | * generate model part of a resource |
||
807 | * |
||
808 | * @param array $parameters twig parameters |
||
809 | * @param string $dir base bundle dir |
||
810 | * @param string $document document name |
||
811 | * |
||
812 | * @return void |
||
813 | */ |
||
814 | protected function generateModel(array $parameters, $dir, $document) |
||
884 | |||
885 | /** |
||
886 | * generate RESTful controllers ans service configs |
||
887 | * |
||
888 | * @param array $parameters twig parameters |
||
889 | * @param string $dir base bundle dir |
||
890 | * @param string $document document name |
||
891 | * |
||
892 | * @return void |
||
893 | */ |
||
894 | protected function generateController(array $parameters, $dir, $document) |
||
932 | |||
933 | /** |
||
934 | * generates fixtures |
||
935 | * |
||
936 | * @param array $parameters twig parameters |
||
937 | * @param string $dir base bundle dir |
||
938 | * @param string $document document name |
||
939 | * |
||
940 | * @return void |
||
941 | */ |
||
942 | protected function generateFixtures(array $parameters, $dir, $document) |
||
953 | } |
||
954 |
This check looks for
@param
annotations where the type inferred by our type inference engine differs from the declared type.It makes a suggestion as to what type it considers more descriptive.
Most often this is a case of a parameter that can be null in addition to its declared types.