final class EventSourcedFrontendNodeRoutePartHandler extends AbstractRoutePart implements DynamicRoutePartInterface, ParameterAwareRoutePartInterface, FrontendNodeRoutePartHandlerInterface (View source)

A route part handler for finding nodes in the website's frontend. Like every RoutePartHandler, this handles both directions:

  • from URL to NodeAddress (via {EventSourcedFrontendNodeRoutePartHandler::matchWithParameters})
  • from NodeAddress to URL (via {EventSourcedFrontendNodeRoutePartHandler::resolveWithParameters})

For performance reasons, this uses a special projection {\Neos\Neos\FrontendRouting\Projection\DocumentUriPathFinder}, and does NOT use the graph projection in any way.

Match Direction (URL to NodeAddress)

This is usually simply triggered ONCE per request, before the controller starts working. The RoutePartHandler is invoked from {\Neos\Flow\Mvc\Routing\RoutingMiddleware} (which handles the routing).

The overall process is as follows:

 (*) = Extension Point               ┌───────────────────────────────────────────────┐
┌──────────────┐                     │   EventSourcedFrontendNodeRoutePartHandler    │
│SiteDetection │                     │ ┌─────────────────────┐                       │
│Middleware (*)│────────────────────▶│ │DimensionResolver (*)│─────▶ Finding the    ─┼─▶NodeAddress
└──────────────┘ current site        │ └─────────────────────┘       NodeId          │
                                     └───────────────────────────────────────────────┘
                 current Content                              current
                 Repository                                   DimensionSpacePoint

{\Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionMiddleware}: Multi-Site Support (implemented)

and Multiple Content Repository Support (planned)

The Dimension Resolving configuration might be site-specific, f.e. one site maps a subdomain to a different language; and another site which wants to use the UriPathSegment. Additionally, we soon want to support using different content repositories for different sites (e.g. to have different NodeTypes configured, or differing dimension configuration).

Thus, the {\Neos\Neos\FrontendRouting\DimensionResolution\DimensionResolverInterface} and the frontend routing in general needs the result of the site detection as input.

Because of this, the site detection is done before the routing; inside the {\Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionMiddleware}, which runs the routing. Feel free to replace the Site Detection with your own custom Middleware (it's very little code).

The Site Detection is done at every request.

{\Neos\Neos\FrontendRouting\DimensionResolution\DimensionResolverInterface}: Custom Dimension Resolving

Especially the {\Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint} matching must be very extensible, because people might want to map domains, subdomains, URL slugs, ... to different dimensions; and maybe even handle every dimension individually.

This is why the {\Neos\Neos\FrontendRouting\EventSourcedFrontendNodeRoutePartHandler} calls the {\Neos\Neos\FrontendRouting\DimensionResolution\DelegatingResolver}, which calls potentially multiple {\Neos\Neos\FrontendRouting\DimensionResolution\DimensionResolverInterface}s.

For details on how to customize the Dimension Resolving, please see {\Neos\Neos\FrontendRouting\DimensionResolution\DimensionResolverInterface}.

Because the Dimension Resolving runs inside the RoutePartHandler, this is all cached (via the Routing Cache).

Reading the Uri Path Segment and finding the node

This is the core capability of this class (the {\Neos\Neos\FrontendRouting\EventSourcedFrontendNodeRoutePartHandler}).

Result of the Routing

The result of the {\Neos\Neos\FrontendRouting\EventSourcedFrontendNodeRoutePartHandler::matchWithParameters} call is a {\Neos\Neos\FrontendRouting\NodeAddress} (wrapped in a {\Neos\Flow\Mvc\Routing\Dto\MatchResult}); so to build the NodeAddress, we need:

  • the {\Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName} (which is always live in our case)
  • the {\Neos\Neos\FrontendRouting\ContentStreamId} of the Live workspace
  • The {\Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint} we want to see the page in (i.e. in language=de)
    • resolved by {\Neos\Neos\FrontendRouting\DimensionResolution\DimensionResolverInterface}
  • The {\Neos\Neos\FrontendRouting\NodeAggregateId} (of the Document Node we want to show)
    • resolved by {\Neos\Neos\FrontendRouting\EventSourcedFrontendNodeRoutePartHandler}

Resolve Direction (NodeAddress to URL)

               ┌────────────────────────────────────────────────────────────────────────┐
               │                EventSourcedFrontendNodeRoutePartHandler                │
               │                   ┌─────────────────────┐      ┌─────────────────────┐ │
NodeAddress────┼▶ Finding the ────▶│ CrossSiteLinker (*) │─────▶│DimensionResolver (*)│─┼──▶ URL
               │  URL              └─────────────────────┘      └─────────────────────┘ │
               └────────────────────────────────────────────────────────────────────────┘

First, the URL path is resolved by checking the {\Neos\Neos\FrontendRouting\Projection\DocumentUriPathFinder} projection.

Then, the {\Neos\Neos\FrontendRouting\CrossSiteLinking\CrossSiteLinkerInterface} is responsible for adjusting the built URL in case it needs to be generated for a different Site. It is basically a global singleton, but can be replaced globally if needed.

Then, the {\Neos\Neos\FrontendRouting\DimensionResolution\DimensionResolverInterface} of the target site is called for adjusting the URL.

Properties

protected ContentRepositoryRegistry $contentRepositoryRegistry
protected NodeShortcutResolver $nodeShortcutResolver
protected DelegatingResolver $delegatingResolver
protected CrossSiteLinkerInterface $crossSiteLinker

Methods

bool|MatchResult
matchWithParameters(mixed $requestPath, RouteParameters $parameters)

Incoming URLs

ResolveResult|false
resolveWithParameters(array $routeValues, RouteParameters $parameters)

Outgoing URLs (link generation)

void
setSplitString($splitString)

No description

bool
match($routePath)

No description

bool
resolve(array $routeValues)

No description

Details

bool|MatchResult matchWithParameters(mixed $requestPath, RouteParameters $parameters)

Incoming URLs

Parameters

mixed $requestPath
RouteParameters $parameters

Return Value

bool|MatchResult

ResolveResult|false resolveWithParameters(array $routeValues, RouteParameters $parameters)

Outgoing URLs (link generation)

Parameters

array $routeValues
RouteParameters $parameters

Return Value

ResolveResult|false

void setSplitString($splitString)

No description

Parameters

$splitString

Return Value

void

bool match($routePath)

No description

Parameters

$routePath

Return Value

bool

bool resolve(array $routeValues)

No description

Parameters

array $routeValues

Return Value

bool