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 Handler 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 Handler, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
32 | class Handler implements UrlAliasHandlerInterface |
||
33 | { |
||
34 | const ROOT_LOCATION_ID = 1; |
||
35 | |||
36 | /** |
||
37 | * This is intentionally hardcoded for now as: |
||
38 | * 1. We don't implement this configuration option. |
||
39 | * 2. Such option should not be in this layer, should be handled higher up. |
||
40 | * |
||
41 | * @deprecated |
||
42 | */ |
||
43 | const CONTENT_REPOSITORY_ROOT_LOCATION_ID = 2; |
||
44 | |||
45 | /** |
||
46 | * The maximum level of alias depth. |
||
47 | */ |
||
48 | const MAX_URL_ALIAS_DEPTH_LEVEL = 60; |
||
49 | |||
50 | /** |
||
51 | * UrlAlias Gateway. |
||
52 | * |
||
53 | * @var \eZ\Publish\Core\Persistence\Legacy\Content\UrlAlias\Gateway |
||
54 | */ |
||
55 | protected $gateway; |
||
56 | |||
57 | /** |
||
58 | * Gateway for handling location data. |
||
59 | * |
||
60 | * @var \eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway |
||
61 | */ |
||
62 | protected $locationGateway; |
||
63 | |||
64 | /** |
||
65 | * UrlAlias Mapper. |
||
66 | * |
||
67 | * @var \eZ\Publish\Core\Persistence\Legacy\Content\UrlAlias\Mapper |
||
68 | */ |
||
69 | protected $mapper; |
||
70 | |||
71 | /** |
||
72 | * Caching language handler. |
||
73 | * |
||
74 | * @var \eZ\Publish\Core\Persistence\Legacy\Content\Language\CachingHandler |
||
75 | */ |
||
76 | protected $languageHandler; |
||
77 | |||
78 | /** |
||
79 | * URL slug converter. |
||
80 | * |
||
81 | * @var \eZ\Publish\Core\Persistence\Legacy\Content\UrlAlias\SlugConverter |
||
82 | */ |
||
83 | protected $slugConverter; |
||
84 | |||
85 | /** |
||
86 | * Gateway for handling content data. |
||
87 | * |
||
88 | * @var \eZ\Publish\Core\Persistence\Legacy\Content\Gateway |
||
89 | */ |
||
90 | protected $contentGateway; |
||
91 | |||
92 | /** |
||
93 | * Language mask generator. |
||
94 | * |
||
95 | * @var \eZ\Publish\Core\Persistence\Legacy\Content\Language\MaskGenerator |
||
96 | */ |
||
97 | protected $maskGenerator; |
||
98 | |||
99 | /** @var \eZ\Publish\SPI\Persistence\TransactionHandler */ |
||
100 | private $transactionHandler; |
||
101 | |||
102 | /** |
||
103 | * Creates a new UrlAlias Handler. |
||
104 | * |
||
105 | * @param \eZ\Publish\Core\Persistence\Legacy\Content\UrlAlias\Gateway $gateway |
||
106 | * @param \eZ\Publish\Core\Persistence\Legacy\Content\UrlAlias\Mapper $mapper |
||
107 | * @param \eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway $locationGateway |
||
108 | * @param \eZ\Publish\SPI\Persistence\Content\Language\Handler $languageHandler |
||
109 | * @param \eZ\Publish\Core\Persistence\Legacy\Content\UrlAlias\SlugConverter $slugConverter |
||
110 | * @param \eZ\Publish\Core\Persistence\Legacy\Content\Gateway $contentGateway |
||
111 | * @param \eZ\Publish\Core\Persistence\Legacy\Content\Language\MaskGenerator $maskGenerator |
||
112 | * @param \eZ\Publish\SPI\Persistence\TransactionHandler $transactionHandler |
||
113 | */ |
||
114 | public function __construct( |
||
133 | |||
134 | public function publishUrlAliasForLocation( |
||
153 | |||
154 | /** |
||
155 | * Internal publish method, accepting language ID instead of language code and optionally |
||
156 | * new alias ID (used when swapping Locations). |
||
157 | * |
||
158 | * @see \eZ\Publish\Core\Persistence\Legacy\Content\UrlAlias\Handler::locationSwapped() |
||
159 | * |
||
160 | * @param int $locationId |
||
161 | * @param int $parentLocationId |
||
162 | * @param string $name |
||
163 | * @param int $languageId |
||
164 | * @param bool $alwaysAvailable |
||
165 | * @param bool $updatePathIdentificationString legacy storage specific for updating ezcontentobject_tree.path_identification_string |
||
166 | * @param int $newId |
||
167 | */ |
||
168 | private function internalPublishUrlAliasForLocation( |
||
301 | |||
302 | /** |
||
303 | * Create a user chosen $alias pointing to $locationId in $languageCode. |
||
304 | * |
||
305 | * If $languageCode is null the $alias is created in the system's default |
||
306 | * language. $alwaysAvailable makes the alias available in all languages. |
||
307 | * |
||
308 | * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException |
||
309 | * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException |
||
310 | * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException |
||
311 | * |
||
312 | * @param mixed $locationId |
||
313 | * @param string $path |
||
314 | * @param bool $forwarding |
||
315 | * @param string $languageCode |
||
316 | * @param bool $alwaysAvailable |
||
317 | * |
||
318 | * @return \eZ\Publish\SPI\Persistence\Content\UrlAlias |
||
319 | */ |
||
320 | public function createCustomUrlAlias($locationId, $path, $forwarding = false, $languageCode = null, $alwaysAvailable = false) |
||
330 | |||
331 | /** |
||
332 | * Create a user chosen $alias pointing to a resource in $languageCode. |
||
333 | * This method does not handle location resources - if a user enters a location target |
||
334 | * the createCustomUrlAlias method has to be used. |
||
335 | * |
||
336 | * If $languageCode is null the $alias is created in the system's default |
||
337 | * language. $alwaysAvailable makes the alias available in all languages. |
||
338 | * |
||
339 | * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException if the path already exists for the given language |
||
340 | * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException if the path is broken |
||
341 | * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException |
||
342 | * |
||
343 | * @param string $resource |
||
344 | * @param string $path |
||
345 | * @param bool $forwarding |
||
346 | * @param string $languageCode |
||
347 | * @param bool $alwaysAvailable |
||
348 | * |
||
349 | * @return \eZ\Publish\SPI\Persistence\Content\UrlAlias |
||
350 | */ |
||
351 | public function createGlobalUrlAlias($resource, $path, $forwarding = false, $languageCode = null, $alwaysAvailable = false) |
||
361 | |||
362 | /** |
||
363 | * Internal method for creating global or custom URL alias (these are handled in the same way). |
||
364 | * |
||
365 | * @throws \eZ\Publish\Core\Base\Exceptions\ForbiddenException if the path already exists for the given language |
||
366 | * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException |
||
367 | * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException |
||
368 | * |
||
369 | * @param string $action |
||
370 | * @param string $path |
||
371 | * @param bool $forward |
||
372 | * @param string|null $languageCode |
||
373 | * @param bool $alwaysAvailable |
||
374 | * |
||
375 | * @return \eZ\Publish\SPI\Persistence\Content\UrlAlias |
||
376 | */ |
||
377 | protected function createUrlAlias($action, $path, $forward, $languageCode, $alwaysAvailable) |
||
461 | |||
462 | /** |
||
463 | * Convenience method for inserting nop type row. |
||
464 | * |
||
465 | * @param mixed $parentId |
||
466 | * @param string $text |
||
467 | * @param string $textMD5 |
||
468 | * |
||
469 | * @return mixed |
||
470 | */ |
||
471 | protected function insertNopEntry($parentId, $text, $textMD5) |
||
483 | |||
484 | /** |
||
485 | * List of user generated or autogenerated url entries, pointing to $locationId. |
||
486 | * |
||
487 | * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException |
||
488 | * |
||
489 | * @param mixed $locationId |
||
490 | * @param bool $custom if true the user generated aliases are listed otherwise the autogenerated |
||
491 | * |
||
492 | * @return \eZ\Publish\SPI\Persistence\Content\UrlAlias[] |
||
493 | */ |
||
494 | View Code Duplication | public function listURLAliasesForLocation($locationId, $custom = false) |
|
503 | |||
504 | /** |
||
505 | * List global aliases. |
||
506 | * |
||
507 | * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException |
||
508 | * |
||
509 | * @param string|null $languageCode |
||
510 | * @param int $offset |
||
511 | * @param int $limit |
||
512 | * |
||
513 | * @return \eZ\Publish\SPI\Persistence\Content\UrlAlias[] |
||
514 | */ |
||
515 | View Code Duplication | public function listGlobalURLAliases($languageCode = null, $offset = 0, $limit = -1) |
|
524 | |||
525 | /** |
||
526 | * Removes url aliases. |
||
527 | * |
||
528 | * Autogenerated aliases are not removed by this method. |
||
529 | * |
||
530 | * @param \eZ\Publish\SPI\Persistence\Content\UrlAlias[] $urlAliases |
||
531 | * |
||
532 | * @return bool |
||
533 | */ |
||
534 | public function removeURLAliases(array $urlAliases) |
||
547 | |||
548 | /** |
||
549 | * Looks up a url alias for the given url. |
||
550 | * |
||
551 | * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException |
||
552 | * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException |
||
553 | * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException |
||
554 | * |
||
555 | * @param string $url |
||
556 | * |
||
557 | * @return \eZ\Publish\SPI\Persistence\Content\UrlAlias |
||
558 | */ |
||
559 | public function lookup($url) |
||
595 | |||
596 | /** |
||
597 | * Loads URL alias by given $id. |
||
598 | * |
||
599 | * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException |
||
600 | * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException |
||
601 | * |
||
602 | * @param string $id |
||
603 | * |
||
604 | * @return \eZ\Publish\SPI\Persistence\Content\UrlAlias |
||
605 | */ |
||
606 | public function loadUrlAlias($id) |
||
619 | |||
620 | /** |
||
621 | * Notifies the underlying engine that a location has moved. |
||
622 | * |
||
623 | * This method triggers the change of the autogenerated aliases. |
||
624 | * |
||
625 | * @param mixed $locationId |
||
626 | * @param mixed $oldParentId |
||
627 | * @param mixed $newParentId |
||
628 | */ |
||
629 | public function locationMoved($locationId, $oldParentId, $newParentId) |
||
649 | |||
650 | /** |
||
651 | * Notifies the underlying engine that a location was copied. |
||
652 | * |
||
653 | * This method triggers the creation of the autogenerated aliases for the copied locations |
||
654 | * |
||
655 | * @param mixed $locationId |
||
656 | * @param mixed $newLocationId |
||
657 | * @param mixed $newParentId |
||
658 | */ |
||
659 | public function locationCopied($locationId, $newLocationId, $newParentId) |
||
672 | |||
673 | /** |
||
674 | * Notify the underlying engine that a Location has been swapped. |
||
675 | * |
||
676 | * This method triggers the change of the autogenerated aliases. |
||
677 | * |
||
678 | * @param int $location1Id |
||
679 | * @param int $location1ParentId |
||
680 | * @param int $location2Id |
||
681 | * @param int $location2ParentId |
||
682 | * @throws \eZ\Publish\Core\Base\Exceptions\NotFoundException |
||
683 | */ |
||
684 | public function locationSwapped($location1Id, $location1ParentId, $location2Id, $location2ParentId) |
||
737 | |||
738 | /** |
||
739 | * @param array $contentInfo |
||
740 | * |
||
741 | * @return array |
||
742 | */ |
||
743 | private function getNamesForAllLanguages(array $contentInfo) |
||
760 | |||
761 | /** |
||
762 | * Historizes given existing active entries for two swapped Locations. |
||
763 | * |
||
764 | * This should be done before republishing URL aliases, in order to avoid unnecessary |
||
765 | * conflicts when swapped Locations are siblings. |
||
766 | * |
||
767 | * We need to historize everything separately per language (mask), in case the entries |
||
768 | * remain history future publishing reusages need to be able to take them over cleanly. |
||
769 | * |
||
770 | * @see \eZ\Publish\Core\Persistence\Legacy\Content\UrlAlias\Handler::locationSwapped() |
||
771 | * |
||
772 | * @param array $location1Entries |
||
773 | * @param array $location2Entries |
||
774 | */ |
||
775 | private function historizeBeforeSwap($location1Entries, $location2Entries) |
||
785 | |||
786 | /** |
||
787 | * Decides if UrlAlias for $location2 should be published first. |
||
788 | * |
||
789 | * The order in which Locations are published only matters if swapped Locations are siblings and they have the same |
||
790 | * name in a given language. In this case, the UrlAlias for Location which previously had lower number at the end of |
||
791 | * its UrlAlias text (or no number at all) should be published first. This ensures that the number still stays lower |
||
792 | * for this Location after the swap. If it wouldn't stay lower, then swapping Locations in conjunction with swapping |
||
793 | * UrlAliases would effectively cancel each other. |
||
794 | * |
||
795 | * @param array $location1Entries |
||
796 | * @param int $location1ParentId |
||
797 | * @param string $name1 |
||
798 | * @param array $location2Entries |
||
799 | * @param int $location2ParentId |
||
800 | * @param string $name2 |
||
801 | * @param int $languageId |
||
802 | * |
||
803 | * @return bool |
||
804 | */ |
||
805 | private function shouldUrlAliasForSecondLocationBePublishedFirst( |
||
829 | |||
830 | /** |
||
831 | * Get in a proper order - to be published - a list of URL aliases for swapped Locations. |
||
832 | * |
||
833 | * @see shouldUrlAliasForSecondLocationBePublishedFirst |
||
834 | * |
||
835 | * @param \eZ\Publish\SPI\Persistence\Content\Language $language |
||
836 | * @param \eZ\Publish\Core\Persistence\Legacy\Content\UrlAlias\DTO\SwappedLocationProperties $location1 |
||
837 | * @param \eZ\Publish\Core\Persistence\Legacy\Content\UrlAlias\DTO\SwappedLocationProperties $location2 |
||
838 | * |
||
839 | * @return \eZ\Publish\Core\Persistence\Legacy\Content\UrlAlias\DTO\UrlAliasForSwappedLocation[] |
||
840 | */ |
||
841 | private function getUrlAliasesForSwappedLocations( |
||
885 | |||
886 | /** |
||
887 | * @param array $locationEntries |
||
888 | * @param int $languageId |
||
889 | * |
||
890 | * @return array|null |
||
891 | */ |
||
892 | private function getLocationEntryInLanguage(array $locationEntries, $languageId) |
||
903 | |||
904 | /** |
||
905 | * Returns possibly corrected alias id for given $locationId !! For use as parent id in logic. |
||
906 | * |
||
907 | * First level entries must have parent id set to 0 instead of their parent location alias id. |
||
908 | * There are two cases when alias id needs to be corrected: |
||
909 | * 1) location is special location without URL alias (location with id=1 in standard installation) |
||
910 | * 2) location is site root location, having special root entry in the ezurlalias_ml table (location with id=2 |
||
911 | * in standard installation) |
||
912 | * |
||
913 | * @param mixed $locationId |
||
914 | * |
||
915 | * @return mixed |
||
916 | */ |
||
917 | protected function getRealAliasId($locationId) |
||
935 | |||
936 | /** |
||
937 | * Recursively copies aliases from old parent under new parent. |
||
938 | * |
||
939 | * @param array $actionMap |
||
940 | * @param mixed $oldParentAliasId |
||
941 | * @param mixed $newParentAliasId |
||
942 | */ |
||
943 | protected function copySubtree($actionMap, $oldParentAliasId, $newParentAliasId) |
||
967 | |||
968 | /** |
||
969 | * @param mixed $oldParentId |
||
970 | * @param mixed $newParentId |
||
971 | * |
||
972 | * @return array |
||
973 | */ |
||
974 | protected function getCopiedLocationsMap($oldParentId, $newParentId) |
||
986 | |||
987 | public function locationDeleted($locationId): array |
||
1005 | |||
1006 | /** |
||
1007 | * Notifies the underlying engine that Locations Content Translation was removed. |
||
1008 | * |
||
1009 | * @param int[] $locationIds all Locations of the Content that got Translation removed |
||
1010 | * @param string $languageCode language code of the removed Translation |
||
1011 | */ |
||
1012 | public function translationRemoved(array $locationIds, $languageCode) |
||
1022 | |||
1023 | /** |
||
1024 | * Recursively removes aliases by given $id and $action. |
||
1025 | * |
||
1026 | * $original parameter is used to limit removal of moved Location aliases to history entries only. |
||
1027 | * |
||
1028 | * @param mixed $id |
||
1029 | * @param string $action |
||
1030 | * @param mixed $original |
||
1031 | */ |
||
1032 | protected function removeSubtree($id, $action, $original) |
||
1052 | |||
1053 | /** |
||
1054 | * @param string $text |
||
1055 | * |
||
1056 | * @return string |
||
1057 | */ |
||
1058 | protected function getHash($text) |
||
1062 | |||
1063 | /** |
||
1064 | * {@inheritdoc} |
||
1065 | */ |
||
1066 | public function archiveUrlAliasesForDeletedTranslations($locationId, $parentLocationId, array $languageCodes) |
||
1091 | |||
1092 | /** |
||
1093 | * Remove corrupted URL aliases (global, custom and system). |
||
1094 | * |
||
1095 | * @return int Number of removed URL aliases |
||
1096 | * |
||
1097 | * @throws \Exception |
||
1098 | */ |
||
1099 | public function deleteCorruptedUrlAliases() |
||
1116 | |||
1117 | /** |
||
1118 | * Attempt repairing auto-generated URL aliases for the given Location (including history). |
||
1119 | * |
||
1120 | * Note: it is assumed that at this point original, working, URL Alias for Location is published. |
||
1121 | * |
||
1122 | * @param int $locationId |
||
1123 | * |
||
1124 | * @throws \eZ\Publish\Core\Base\Exceptions\BadStateException |
||
1125 | */ |
||
1126 | public function repairBrokenUrlAliasesForLocation(int $locationId) |
||
1134 | |||
1135 | private function insertAliasEntryAsNop(array $aliasEntry): void |
||
1142 | |||
1143 | /** |
||
1144 | * Internal publish custom aliases method, accepting language mask to set correct language mask on url aliases |
||
1145 | * new alias ID (used when swapping Locations). |
||
1146 | */ |
||
1147 | private function internalPublishCustomUrlAliasForLocation(SwappedLocationProperties $location, int $languageMask) |
||
1172 | } |
||
1173 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.
Either this assignment is in error or an instanceof check should be added for that assignment.