Exponential 5.x Kernel 7.5.40 Exponential New Stack (Symfony-based) Kernel — PHP Class Reference

Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php
Go to the documentation of this file.
1 <?php
2
7 namespace eZ\Publish\Core\MVC\Symfony\Routing;
8
9 use eZ\Publish\API\Repository\LocationService;
10 use eZ\Publish\API\Repository\URLAliasService;
11 use eZ\Publish\API\Repository\ContentService;
12 use eZ\Publish\API\Repository\Values\Content\URLAlias;
13 use eZ\Publish\API\Repository\Exceptions\NotFoundException;
14 use eZ\Publish\API\Repository\Values\Content\Location;
15 use eZ\Publish\Core\MVC\Symfony\View\Manager as ViewManager;
16 use eZ\Publish\Core\MVC\Symfony\Routing\Generator\UrlAliasGenerator;
17 use Symfony\Cmf\Component\Routing\ChainedRouterInterface;
18 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
19 use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
20 use Symfony\Component\HttpFoundation\Request;
21 use Symfony\Component\Routing\RequestContext;
22 use Psr\Log\LoggerInterface;
23 use Symfony\Component\Routing\RouteCollection;
24 use Symfony\Component\Routing\Route as SymfonyRoute;
25 use Symfony\Component\Routing\Exception\RouteNotFoundException;
26 use Symfony\Component\Routing\Exception\ResourceNotFoundException;
27 use InvalidArgumentException;
28 use LogicException;
29 use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
30
31 class UrlAliasRouter implements ChainedRouterInterface, RequestMatcherInterface
32 {
33 const URL_ALIAS_ROUTE_NAME = 'ez_urlalias';
34
38 const LOCATION_VIEW_CONTROLLER = 'ez_content:viewLocation';
39
43 const VIEW_ACTION = 'ez_content:viewAction';
44
46 protected $requestContext;
47
49 protected $locationService;
50
52 protected $urlAliasService;
53
55 protected $contentService;
56
58 protected $generator;
59
65 protected $rootLocationId;
66
68 protected $logger;
69
70 public function __construct(
71 LocationService $locationService,
72 URLAliasService $urlAliasService,
73 ContentService $contentService,
74 UrlAliasGenerator $generator,
75 RequestContext $requestContext,
76 LoggerInterface $logger = null
77 ) {
78 $this->locationService = $locationService;
79 $this->urlAliasService = $urlAliasService;
80 $this->contentService = $contentService;
81 $this->generator = $generator;
82 $this->requestContext = $requestContext !== null ? $requestContext : new RequestContext();
83 $this->logger = $logger;
84 }
85
91 public function setRootLocationId($rootLocationId)
92 {
93 $this->rootLocationId = $rootLocationId;
94 }
95
108 public function matchRequest(Request $request)
109 {
110 try {
111 $requestedPath = $request->attributes->get('semanticPathinfo', $request->getPathInfo());
112 $urlAlias = $this->getUrlAlias($requestedPath);
113 if ($this->rootLocationId === null) {
114 $pathPrefix = '/';
115 } else {
116 $pathPrefix = $this->generator->getPathPrefixByRootLocationId($this->rootLocationId);
117 }
118
119 $params = [
120 '_route' => self::URL_ALIAS_ROUTE_NAME,
121 ];
122 switch ($urlAlias->type) {
123 case URLAlias::LOCATION:
124 $location = $this->generator->loadLocation($urlAlias->destination);
125 $params += [
126 '_controller' => static::VIEW_ACTION,
127 'contentId' => $location->contentId,
128 'locationId' => $urlAlias->destination,
129 'viewType' => ViewManager::VIEW_TYPE_FULL,
130 'layout' => true,
131 ];
132
133 // For Location alias setup 301 redirect to Location's current URL when:
134 // 1. alias is history
135 // 2. alias is custom with forward flag true
136 // 3. requested URL is not case-sensitive equal with the one loaded
137 if ($urlAlias->isHistory === true || ($urlAlias->isCustom === true && $urlAlias->forward === true)) {
138 $params += [
139 'semanticPathinfo' => $this->generate($location),
140 'needsRedirect' => true,
141 // Specify not to prepend siteaccess while redirecting when applicable since it would be already present (see UrlAliasGenerator::doGenerate())
142 'prependSiteaccessOnRedirect' => false,
143 ];
144 } elseif ($this->needsCaseRedirect($urlAlias, $requestedPath, $pathPrefix)) {
145 $params += [
146 'semanticPathinfo' => $this->removePathPrefix($urlAlias->path, $pathPrefix),
147 'needsRedirect' => true,
148 ];
149
150 if ($urlAlias->destination instanceof Location) {
151 $params += ['locationId' => $urlAlias->destination->id];
152 }
153 }
154
155 if (isset($this->logger)) {
156 $this->logger->info("UrlAlias matched location #{$urlAlias->destination}. Forwarding to ViewController");
157 }
158
159 break;
160
161 case URLAlias::RESOURCE:
162 // In URLAlias terms, "forward" means "redirect".
163 if ($urlAlias->forward) {
164 $params += [
165 'semanticPathinfo' => '/' . trim($urlAlias->destination, '/'),
166 'needsRedirect' => true,
167 ];
168 } elseif ($this->needsCaseRedirect($urlAlias, $requestedPath, $pathPrefix)) {
169 // Handle case-correction redirect
170 $params += [
171 'semanticPathinfo' => $this->removePathPrefix($urlAlias->path, $pathPrefix),
172 'needsRedirect' => true,
173 ];
174 } else {
175 $params += [
176 'semanticPathinfo' => '/' . trim($urlAlias->destination, '/'),
177 'needsForward' => true,
178 ];
179 }
180
181 break;
182
183 case URLAlias::VIRTUAL:
184 // Handle case-correction redirect
185 if ($this->needsCaseRedirect($urlAlias, $requestedPath, $pathPrefix)) {
186 $params += [
187 'semanticPathinfo' => $this->removePathPrefix($urlAlias->path, $pathPrefix),
188 'needsRedirect' => true,
189 ];
190 } else {
191 // Virtual aliases should load the Content at homepage URL
192 $params += [
193 'semanticPathinfo' => '/',
194 'needsForward' => true,
195 ];
196 }
197
198 break;
199 }
200
201 return $params;
202 } catch (NotFoundException $e) {
203 throw new ResourceNotFoundException($e->getMessage(), $e->getCode(), $e);
204 }
205 }
206
217 protected function removePathPrefix($path, $prefix)
218 {
219 if ($prefix !== '/' && mb_stripos($path, $prefix) === 0) {
220 $path = mb_substr($path, mb_strlen($prefix));
221 }
222
223 return $path;
224 }
225
238 protected function needsCaseRedirect(URLAlias $loadedUrlAlias, $requestedPath, $pathPrefix)
239 {
240 // If requested path is excluded from tree root jail, compare it to loaded UrlAlias directly.
241 if ($this->generator->isUriPrefixExcluded($requestedPath)) {
242 return strcmp($loadedUrlAlias->path, $requestedPath) !== 0;
243 }
244
245 // Compare loaded UrlAlias with requested path, prefixed with configured path prefix.
246 return
247 strcmp(
248 $loadedUrlAlias->path,
249 $pathPrefix . ($pathPrefix === '/' ? trim($requestedPath, '/') : rtrim($requestedPath, '/'))
250 ) !== 0
251 ;
252 }
253
263 protected function getUrlAlias($pathinfo)
264 {
265 return $this->urlAliasService->lookup($pathinfo);
266 }
267
273 public function getRouteCollection()
274 {
275 return new RouteCollection();
276 }
277
303 public function generate($name, $parameters = [], $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH)
304 {
305 // Direct access to Location
306 if ($name instanceof Location) {
307 return $this->generator->generate($name, $parameters, $referenceType);
308 }
309
310 // Normal route name
311 if ($name === self::URL_ALIAS_ROUTE_NAME) {
312 if (isset($parameters['location']) || isset($parameters['locationId'])) {
313 // Check if location is a valid Location object
314 if (isset($parameters['location']) && !$parameters['location'] instanceof Location) {
315 throw new LogicException(
316 "When generating an UrlAlias route, 'location' parameter must be a valid eZ\\Publish\\API\\Repository\\Values\\Content\\Location."
317 );
318 }
319
320 $location = isset($parameters['location']) ? $parameters['location'] : $this->locationService->loadLocation($parameters['locationId']);
321 unset($parameters['location'], $parameters['locationId'], $parameters['viewType'], $parameters['layout']);
322
323 return $this->generator->generate($location, $parameters, $referenceType);
324 }
325
326 if (isset($parameters['contentId'])) {
327 $contentInfo = $this->contentService->loadContentInfo($parameters['contentId']);
328 unset($parameters['contentId'], $parameters['viewType'], $parameters['layout']);
329
330 if (empty($contentInfo->mainLocationId)) {
331 throw new LogicException('Cannot generate an UrlAlias route for content without main location.');
332 }
333
334 return $this->generator->generate(
335 $this->locationService->loadLocation($contentInfo->mainLocationId),
336 $parameters,
337 $referenceType
338 );
339 }
340
341 throw new InvalidArgumentException(
342 "When generating an UrlAlias route, either 'location', 'locationId' or 'contentId' must be provided."
343 );
344 }
345
346 throw new RouteNotFoundException('Could not match route');
347 }
348
349 public function setContext(RequestContext $context)
350 {
351 $this->requestContext = $context;
352 $this->generator->setRequestContext($context);
353 }
354
355 public function getContext()
356 {
357 return $this->requestContext;
358 }
359
367 public function match($pathinfo)
368 {
369 throw new \RuntimeException("The UrlAliasRouter doesn't support the match() method. Please use matchRequest() instead.");
370 }
371
383 public function supports($name)
384 {
385 return $name instanceof Location || $name === self::URL_ALIAS_ROUTE_NAME;
386 }
387
391 public function getRouteDebugMessage($name, array $parameters = [])
392 {
393 if ($name instanceof RouteObjectInterface) {
394 return 'Route with key ' . $name->getRouteKey();
395 }
396
397 if ($name instanceof SymfonyRoute) {
398 return 'Route with pattern ' . $name->getPath();
399 }
400
401 return $name;
402 }
403 }
eZ\Publish\API\Repository\Exceptions\NotFoundException
This Exception is thrown if an object referenced by an id or identifier could not be found in the rep...
Definition: API/Repository/Exceptions/NotFoundException.php:16
eZ\Publish\API\Repository\Values\Content\Location
Definition: API/Repository/Values/Content/Location.php:32
eZ\Publish\API\Repository\Values\Content\URLAlias
Definition: API/Repository/Values/Content/URLAlias.php:25
eZ\Publish\API\Repository\Values\Content\URLAlias\VIRTUAL
const VIRTUAL
Definition: API/Repository/Values/Content/URLAlias.php:28
eZ\Publish\API\Repository\Values\Content\URLAlias\LOCATION
const LOCATION
Definition: API/Repository/Values/Content/URLAlias.php:26
eZ\Publish\API\Repository\Values\Content\URLAlias\RESOURCE
const RESOURCE
Definition: API/Repository/Values/Content/URLAlias.php:27
eZ\Publish\Core\MVC\Symfony\Routing\Generator\UrlAliasGenerator
URL generator for UrlAlias based links.
Definition: UrlAliasGenerator.php:21
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:32
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\$rootLocationId
$rootLocationId
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:65
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\URL_ALIAS_ROUTE_NAME
const URL_ALIAS_ROUTE_NAME
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:33
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\supports
supports($name)
Whether the router supports the thing in $name to generate a route.
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:383
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\setContext
setContext(RequestContext $context)
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:349
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\needsCaseRedirect
needsCaseRedirect(URLAlias $loadedUrlAlias, $requestedPath, $pathPrefix)
Returns true of false on comparing $urlAlias->path and $path with case sensitivity.
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:238
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\getRouteDebugMessage
getRouteDebugMessage($name, array $parameters=[])
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:391
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\getRouteCollection
getRouteCollection()
Gets the RouteCollection instance associated with this Router.
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:273
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\getUrlAlias
getUrlAlias($pathinfo)
Returns the UrlAlias object to use, starting from the request.
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:263
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\matchRequest
matchRequest(Request $request)
Tries to match a request with a set of routes.
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:108
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\generate
generate($name, $parameters=[], $referenceType=UrlGeneratorInterface::ABSOLUTE_PATH)
Generates a URL for a location, from the given parameters.
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:303
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\match
match($pathinfo)
Not supported.
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:367
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\__construct
__construct(LocationService $locationService, URLAliasService $urlAliasService, ContentService $contentService, UrlAliasGenerator $generator, RequestContext $requestContext, LoggerInterface $logger=null)
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:70
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\$contentService
$contentService
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:55
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\$generator
$generator
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:58
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\$urlAliasService
$urlAliasService
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:52
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\LOCATION_VIEW_CONTROLLER
const LOCATION_VIEW_CONTROLLER
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:38
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\$locationService
$locationService
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:49
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\setRootLocationId
setRootLocationId($rootLocationId)
Injects current root Location id.
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:91
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\$requestContext
$requestContext
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:46
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\VIEW_ACTION
const VIEW_ACTION
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:43
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\$logger
$logger
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:68
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\removePathPrefix
removePathPrefix($path, $prefix)
Removes prefix from path.
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:217
eZ\Publish\Core\MVC\Symfony\Routing\UrlAliasRouter\getContext
getContext()
Definition: Publish/Core/MVC/Symfony/Routing/UrlAliasRouter.php:355
eZ\Publish\Core\MVC\Symfony\View\Manager
Definition: Publish/Core/MVC/Symfony/View/Manager.php:22
eZ\Publish\API\Repository\ContentService
Definition: API/Repository/ContentService.php:27
eZ\Publish\API\Repository\LocationService
Definition: API/Repository/LocationService.php:21
eZ\Publish\API\Repository\URLAliasService
Definition: API/Repository/URLAliasService.php:17
eZ\Publish\Core\MVC\Symfony\Routing
Definition: ChainRouter.php:7
Copyright © 1998 – 2026 7x. All rights reserved. Licensed under the GNU GPLv2+.