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 UrlAliasRouter 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 UrlAliasRouter, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 34 | class UrlAliasRouter implements ChainedRouterInterface, RequestMatcherInterface |
||
| 35 | { |
||
| 36 | const URL_ALIAS_ROUTE_NAME = 'ez_urlalias'; |
||
| 37 | |||
| 38 | /** |
||
| 39 | * @deprecated since 6.0.0. |
||
| 40 | */ |
||
| 41 | const LOCATION_VIEW_CONTROLLER = 'ez_content:viewLocation'; |
||
| 42 | |||
| 43 | /** |
||
| 44 | * @since 6.0.0 |
||
| 45 | */ |
||
| 46 | const VIEW_ACTION = 'ez_content:viewAction'; |
||
| 47 | |||
| 48 | /** |
||
| 49 | * @var \Symfony\Component\Routing\RequestContext |
||
| 50 | */ |
||
| 51 | protected $requestContext; |
||
| 52 | |||
| 53 | /** |
||
| 54 | * @var \eZ\Publish\API\Repository\LocationService |
||
| 55 | */ |
||
| 56 | protected $locationService; |
||
| 57 | |||
| 58 | /** |
||
| 59 | * @var \eZ\Publish\API\Repository\URLAliasService |
||
| 60 | */ |
||
| 61 | protected $urlAliasService; |
||
| 62 | |||
| 63 | /** |
||
| 64 | * @var \eZ\Publish\API\Repository\ContentService |
||
| 65 | */ |
||
| 66 | protected $contentService; |
||
| 67 | |||
| 68 | /** |
||
| 69 | * @var \eZ\Publish\Core\MVC\Symfony\Routing\Generator\UrlAliasGenerator |
||
| 70 | */ |
||
| 71 | protected $generator; |
||
| 72 | |||
| 73 | /** |
||
| 74 | * Holds current root Location id. |
||
| 75 | * |
||
| 76 | * @var int|string |
||
| 77 | */ |
||
| 78 | protected $rootLocationId; |
||
| 79 | |||
| 80 | /** |
||
| 81 | * @var \Psr\Log\LoggerInterface |
||
| 82 | */ |
||
| 83 | protected $logger; |
||
| 84 | |||
| 85 | public function __construct( |
||
| 100 | |||
| 101 | /** |
||
| 102 | * Injects current root Location id. |
||
| 103 | * |
||
| 104 | * @param int|string $rootLocationId |
||
| 105 | */ |
||
| 106 | public function setRootLocationId($rootLocationId) |
||
| 110 | |||
| 111 | /** |
||
| 112 | * Tries to match a request with a set of routes. |
||
| 113 | * |
||
| 114 | * If the matcher can not find information, it must throw one of the exceptions documented |
||
| 115 | * below. |
||
| 116 | * |
||
| 117 | * @param Request $request The request to match |
||
| 118 | * |
||
| 119 | * @return array An array of parameters |
||
| 120 | * |
||
| 121 | * @throws \Symfony\Component\Routing\Exception\ResourceNotFoundException If no matching resource could be found |
||
| 122 | */ |
||
| 123 | public function matchRequest(Request $request) |
||
| 205 | |||
| 206 | /** |
||
| 207 | * Removes prefix from path. |
||
| 208 | * |
||
| 209 | * Checks for presence of $prefix and removes it from $path if found. |
||
| 210 | * |
||
| 211 | * @param string $path |
||
| 212 | * @param string $prefix |
||
| 213 | * |
||
| 214 | * @return string |
||
| 215 | */ |
||
| 216 | protected function removePathPrefix($path, $prefix) |
||
| 224 | |||
| 225 | /** |
||
| 226 | * Returns true of false on comparing $urlAlias->path and $path with case sensitivity. |
||
| 227 | * |
||
| 228 | * Used to determine if redirect is needed because requested path is case-different |
||
| 229 | * from the stored one. |
||
| 230 | * |
||
| 231 | * @param \eZ\Publish\API\Repository\Values\Content\URLAlias $loadedUrlAlias |
||
| 232 | * @param string $requestedPath |
||
| 233 | * @param string $pathPrefix |
||
| 234 | * |
||
| 235 | * @return bool |
||
| 236 | */ |
||
| 237 | protected function needsCaseRedirect(URLAlias $loadedUrlAlias, $requestedPath, $pathPrefix) |
||
| 252 | |||
| 253 | /** |
||
| 254 | * Returns the UrlAlias object to use, starting from the request. |
||
| 255 | * |
||
| 256 | * @param $pathinfo |
||
| 257 | * |
||
| 258 | * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException if the path does not exist or is not valid for the given language |
||
| 259 | * |
||
| 260 | * @return URLAlias |
||
| 261 | */ |
||
| 262 | protected function getUrlAlias($pathinfo) |
||
| 266 | |||
| 267 | /** |
||
| 268 | * Gets the RouteCollection instance associated with this Router. |
||
| 269 | * |
||
| 270 | * @return RouteCollection A RouteCollection instance |
||
| 271 | */ |
||
| 272 | public function getRouteCollection() |
||
| 276 | |||
| 277 | /** |
||
| 278 | * Generates a URL for a location, from the given parameters. |
||
| 279 | * |
||
| 280 | * It is possible to directly pass a Location object as the route name, as the ChainRouter allows it through ChainedRouterInterface. |
||
| 281 | * |
||
| 282 | * If $name is a route name, the "location" key in $parameters must be set to a valid eZ\Publish\API\Repository\Values\Content\Location object. |
||
| 283 | * "locationId" can also be provided. |
||
| 284 | * |
||
| 285 | * If the generator is not able to generate the url, it must throw the RouteNotFoundException |
||
| 286 | * as documented below. |
||
| 287 | * |
||
| 288 | * @see UrlAliasRouter::supports() |
||
| 289 | * |
||
| 290 | * @param string|\eZ\Publish\API\Repository\Values\Content\Location $name The name of the route or a Location instance |
||
| 291 | * @param mixed $parameters An array of parameters |
||
| 292 | * @param bool $absolute Whether to generate an absolute URL |
||
| 293 | * |
||
| 294 | * @throws \LogicException |
||
| 295 | * @throws \Symfony\Component\Routing\Exception\RouteNotFoundException |
||
| 296 | * @throws \InvalidArgumentException |
||
| 297 | * |
||
| 298 | * @return string The generated URL |
||
| 299 | * |
||
| 300 | * @api |
||
| 301 | */ |
||
| 302 | public function generate($name, $parameters = array(), $absolute = false) |
||
| 347 | |||
| 348 | public function setContext(RequestContext $context) |
||
| 353 | |||
| 354 | public function getContext() |
||
| 358 | |||
| 359 | /** |
||
| 360 | * Not supported. Please use matchRequest() instead. |
||
| 361 | * |
||
| 362 | * @param $pathinfo |
||
| 363 | * |
||
| 364 | * @throws \RuntimeException |
||
| 365 | */ |
||
| 366 | public function match($pathinfo) |
||
| 370 | |||
| 371 | /** |
||
| 372 | * Whether the router supports the thing in $name to generate a route. |
||
| 373 | * |
||
| 374 | * This check does not need to look if the specific instance can be |
||
| 375 | * resolved to a route, only whether the router can generate routes from |
||
| 376 | * objects of this class. |
||
| 377 | * |
||
| 378 | * @param mixed $name The route name or route object |
||
| 379 | * |
||
| 380 | * @return bool |
||
| 381 | */ |
||
| 382 | public function supports($name) |
||
| 386 | |||
| 387 | /** |
||
| 388 | * @see Symfony\Cmf\Component\Routing\VersatileGeneratorInterface::getRouteDebugMessage() |
||
| 389 | */ |
||
| 390 | public function getRouteDebugMessage($name, array $parameters = array()) |
||
| 402 | } |
||
| 403 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.