Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like DocumentationNormalizer 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 DocumentationNormalizer, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
41 | final class DocumentationNormalizer implements NormalizerInterface |
||
42 | { |
||
43 | use FilterLocatorTrait; |
||
44 | |||
45 | const SWAGGER_VERSION = '2.0'; |
||
46 | const FORMAT = 'json'; |
||
47 | |||
48 | private $resourceMetadataFactory; |
||
49 | private $propertyNameCollectionFactory; |
||
50 | private $propertyMetadataFactory; |
||
51 | private $resourceClassResolver; |
||
52 | private $operationMethodResolver; |
||
53 | private $operationPathResolver; |
||
54 | private $urlGenerator; |
||
55 | private $nameConverter; |
||
56 | private $oauthEnabled; |
||
57 | private $oauthType; |
||
58 | private $oauthFlow; |
||
59 | private $oauthTokenUrl; |
||
60 | private $oauthAuthorizationUrl; |
||
61 | private $oauthScopes; |
||
62 | |||
63 | /** |
||
64 | * @param ContainerInterface|FilterCollection|null $filterLocator The new filter locator or the deprecated filter collection |
||
65 | */ |
||
66 | public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory, PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, ResourceClassResolverInterface $resourceClassResolver, OperationMethodResolverInterface $operationMethodResolver, OperationPathResolverInterface $operationPathResolver, UrlGeneratorInterface $urlGenerator, $filterLocator = null, NameConverterInterface $nameConverter = null, $oauthEnabled = false, $oauthType = '', $oauthFlow = '', $oauthTokenUrl = '', $oauthAuthorizationUrl = '', $oauthScopes = []) |
||
85 | |||
86 | /** |
||
87 | * {@inheritdoc} |
||
88 | */ |
||
89 | public function normalize($object, $format = null, array $context = []) |
||
108 | |||
109 | /** |
||
110 | * Updates the list of entries in the paths collection. |
||
111 | * |
||
112 | * @param \ArrayObject $paths |
||
113 | * @param \ArrayObject $definitions |
||
114 | * @param string $resourceClass |
||
115 | * @param string $resourceShortName |
||
116 | * @param ResourceMetadata $resourceMetadata |
||
117 | * @param array $mimeTypes |
||
118 | * @param string $operationType |
||
119 | */ |
||
120 | private function addPaths(\ArrayObject $paths, \ArrayObject $definitions, string $resourceClass, string $resourceShortName, ResourceMetadata $resourceMetadata, array $mimeTypes, string $operationType) |
||
133 | |||
134 | /** |
||
135 | * Gets the path for an operation. |
||
136 | * |
||
137 | * If the path ends with the optional _format parameter, it is removed |
||
138 | * as optional path parameters are not yet supported. |
||
139 | * |
||
140 | * @see https://github.com/OAI/OpenAPI-Specification/issues/93 |
||
141 | * |
||
142 | * @param string $resourceShortName |
||
143 | * @param array $operation |
||
144 | * @param string $operationType |
||
145 | * |
||
146 | * @return string |
||
147 | */ |
||
148 | private function getPath(string $resourceShortName, array $operation, string $operationType): string |
||
157 | |||
158 | /** |
||
159 | * Gets a path Operation Object. |
||
160 | * |
||
161 | * @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#operation-object |
||
162 | * |
||
163 | * @param string $operationName |
||
164 | * @param array $operation |
||
165 | * @param string $method |
||
166 | * @param string $operationType |
||
167 | * @param string $resourceClass |
||
168 | * @param ResourceMetadata $resourceMetadata |
||
169 | * @param string[] $mimeTypes |
||
170 | * @param \ArrayObject $definitions |
||
171 | * |
||
172 | * @return \ArrayObject |
||
173 | */ |
||
174 | private function getPathOperation(string $operationName, array $operation, string $method, string $operationType, string $resourceClass, ResourceMetadata $resourceMetadata, array $mimeTypes, \ArrayObject $definitions): \ArrayObject |
||
194 | |||
195 | /** |
||
196 | * @param \ArrayObject $pathOperation |
||
197 | * @param array $mimeTypes |
||
198 | * @param string $operationType |
||
199 | * @param ResourceMetadata $resourceMetadata |
||
200 | * @param string $resourceClass |
||
201 | * @param string $resourceShortName |
||
202 | * @param string $operationName |
||
203 | * @param \ArrayObject $definitions |
||
204 | * |
||
205 | * @return \ArrayObject |
||
206 | */ |
||
207 | private function updateGetOperation(\ArrayObject $pathOperation, array $mimeTypes, string $operationType, ResourceMetadata $resourceMetadata, string $resourceClass, string $resourceShortName, string $operationName, \ArrayObject $definitions) |
||
250 | |||
251 | /** |
||
252 | * @param \ArrayObject $pathOperation |
||
253 | * @param array $mimeTypes |
||
254 | * @param string $operationType |
||
255 | * @param ResourceMetadata $resourceMetadata |
||
256 | * @param string $resourceClass |
||
257 | * @param string $resourceShortName |
||
258 | * @param string $operationName |
||
259 | * @param \ArrayObject $definitions |
||
260 | * |
||
261 | * @return \ArrayObject |
||
262 | */ |
||
263 | private function updatePostOperation(\ArrayObject $pathOperation, array $mimeTypes, string $operationType, ResourceMetadata $resourceMetadata, string $resourceClass, string $resourceShortName, string $operationName, \ArrayObject $definitions) |
||
289 | |||
290 | /** |
||
291 | * @param \ArrayObject $pathOperation |
||
292 | * @param array $mimeTypes |
||
293 | * @param string $operationType |
||
294 | * @param ResourceMetadata $resourceMetadata |
||
295 | * @param string $resourceClass |
||
296 | * @param string $resourceShortName |
||
297 | * @param string $operationName |
||
298 | * @param \ArrayObject $definitions |
||
299 | * |
||
300 | * @return \ArrayObject |
||
301 | */ |
||
302 | private function updatePutOperation(\ArrayObject $pathOperation, array $mimeTypes, string $operationType, ResourceMetadata $resourceMetadata, string $resourceClass, string $resourceShortName, string $operationName, \ArrayObject $definitions) |
||
336 | |||
337 | /** |
||
338 | * @param \ArrayObject $pathOperation |
||
339 | * @param string $resourceShortName |
||
340 | * |
||
341 | * @return \ArrayObject |
||
342 | */ |
||
343 | private function updateDeleteOperation(\ArrayObject $pathOperation, string $resourceShortName): \ArrayObject |
||
360 | |||
361 | /** |
||
362 | * @param \ArrayObject $definitions |
||
363 | * @param ResourceMetadata $resourceMetadata |
||
364 | * @param string $resourceClass |
||
365 | * @param array|null $serializerContext |
||
366 | * |
||
367 | * @return string |
||
368 | */ |
||
369 | private function getDefinition(\ArrayObject $definitions, ResourceMetadata $resourceMetadata, string $resourceClass, array $serializerContext = null): string |
||
384 | |||
385 | /** |
||
386 | * Gets a definition Schema Object. |
||
387 | * |
||
388 | * @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#schemaObject |
||
389 | * |
||
390 | * @param string $resourceClass |
||
391 | * @param ResourceMetadata $resourceMetadata |
||
392 | * @param \ArrayObject $definitions |
||
393 | * @param array|null $serializerContext |
||
394 | * |
||
395 | * @return \ArrayObject |
||
396 | */ |
||
397 | private function getDefinitionSchema(string $resourceClass, ResourceMetadata $resourceMetadata, \ArrayObject $definitions, array $serializerContext = null): \ArrayObject |
||
423 | |||
424 | /** |
||
425 | * Gets a property Schema Object. |
||
426 | * |
||
427 | * @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#schemaObject |
||
428 | * |
||
429 | * @param PropertyMetadata $propertyMetadata |
||
430 | * @param \ArrayObject $definitions |
||
431 | * @param array|null $serializerContext |
||
432 | * |
||
433 | * @return \ArrayObject |
||
434 | */ |
||
435 | private function getPropertySchema(PropertyMetadata $propertyMetadata, \ArrayObject $definitions, array $serializerContext = null): \ArrayObject |
||
464 | |||
465 | /** |
||
466 | * Gets the Swagger's type corresponding to the given PHP's type. |
||
467 | * |
||
468 | * @param string $type |
||
469 | * @param bool $isCollection |
||
470 | * @param string $className |
||
471 | * @param bool $readableLink |
||
472 | * @param \ArrayObject $definitions |
||
473 | * @param array|null $serializerContext |
||
474 | * |
||
475 | * @return array |
||
476 | */ |
||
477 | private function getType(string $type, bool $isCollection, string $className = null, bool $readableLink = null, \ArrayObject $definitions, array $serializerContext = null): array |
||
522 | |||
523 | /** |
||
524 | * Computes the Swagger documentation. |
||
525 | * |
||
526 | * @param Documentation $documentation |
||
527 | * @param \ArrayObject $definitions |
||
528 | * @param \ArrayObject $paths |
||
529 | * |
||
530 | * @return array |
||
531 | */ |
||
532 | private function computeDoc(Documentation $documentation, \ArrayObject $definitions, \ArrayObject $paths): array |
||
569 | |||
570 | /** |
||
571 | * Gets Swagger parameters corresponding to enabled filters. |
||
572 | * |
||
573 | * @param string $resourceClass |
||
574 | * @param string $operationName |
||
575 | * @param ResourceMetadata $resourceMetadata |
||
576 | * @param \ArrayObject $definitions |
||
577 | * @param array|null $serializerContext |
||
578 | * |
||
579 | * @return array |
||
580 | */ |
||
581 | private function getFiltersParameters(string $resourceClass, string $operationName, ResourceMetadata $resourceMetadata, \ArrayObject $definitions, array $serializerContext = null): array |
||
612 | |||
613 | /** |
||
614 | * {@inheritdoc} |
||
615 | */ |
||
616 | public function supportsNormalization($data, $format = null) |
||
620 | |||
621 | /** |
||
622 | * @param string $operationType |
||
623 | * @param bool $denormalization |
||
624 | * @param ResourceMetadata $resourceMetadata |
||
625 | * @param string $operationType |
||
626 | * |
||
627 | * @return array|null |
||
628 | */ |
||
629 | private function getSerializerContext(string $operationType, bool $denormalization, ResourceMetadata $resourceMetadata, string $operationName) |
||
639 | } |
||
640 |
As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next
break
.There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.