New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prepare Routing for multi-domains / add extension points #1120
Comments
Intermediate statusI managed to get a first version running (without adjusted tests & caching) that allows for custom RoutePart implementations to react to/influence parts of the URI "outside" of their respective route part. I mostly followed the steps outlined above, with the following deviations: 2. Adjust Router Cache.. I skipped that step (yet) 3. Allow hooking into RouteContextInstead of hooking into the context via $dispatcher->connect(Router::class, 'beforeRoute', function(RouteContext &$routeContext) {
// some check based on the current context, e.g. $routeContext->getHttpRequest()->getPort() === 8080
$routeContext = $routeContext->withParameter('Some.Namespace', new Parameter('parameterName', 'parameterValue'));
}); There is no major advantage over a HTTP component, but I felt it was more in sync with the signal for the ConsiderationsThe impact of the change is not too bad, but the implementation feels a bit hacky and I think it make sense to abandon the Signal/Slot approach in favor of a more straight-forward implementation. RecapWe need a way to set "route context parameters" before But we could maybe skip the whole "Url post-processing" by extending the RoutePart implementation to return some request. That way we can get rid of the need to post-process the |
I removed this from the 3.3 project-board in favor of pr #1126 that fixes this issue. |
An overhauled Router implementation that allows for more flexible routing. ## Features: ### Routing Parameters Routing `Parameters` can be defined globally (via HTTP component) in order to allow custom RoutePart handler to react to influences that are outside of the incoming URI path (example: The requested host name or scheme) For a RoutePart handler to access the parameters they have to implement the new `ParameterAwareRoutePartInterface`. The `DynamicRoutePart` already implements the interface. For custom implementations extending `DynamicRoutePart` the parameters will be accessible via `$this->parameters`. ### Extended URI matching RoutePart handlers can now return an instance of `MatchResult` when mapping incoming requests. This allows the handler to specify *Tags* to be associated with the route. #### Example: *Before:* ```php protected function matchValue($value) { // custom logic, returning false if the $value doesn't match $this->value = $matchedValue; return true; } ``` *Now:* ```php protected function matchValue($value) { // custom logic, returning false if the $value doesn't match return new MatchResult($matchedValue, RouteTags::createFromTag('some-tag')); } ``` *Note:* The RouteTags argument is optional *Note:* For backwards compatibility the above still works as before ### Extended URI resolving Similar to the above, RoutePart handlers can now specify tags for *resolved* routes by returning an instance of `ResolveResult`. This also allows RouteParts to specify `UriConstraints` that will affect the resolved URI. UriConstraints allow to pre-set the following attributes of the resulting URI: * Scheme (for example "https") * Host (for example "www.somedomain.tld") * Host prefix (for example "en.") * Host suffix (for example "co.uk") * Port (for example 443) * Path (for example "some/path") * Path prefix (for example "en/") * Path suffix (for example ".html") #### Example: *Before:* ```php protected function resolveValue($value) { // custom logic, returning false if the $value doesn't resolved $this->value = $resolvedPathSegment; return true; } ``` *Now:* ```php protected function resolveValue($value) { // custom logic, returning false if the $value doesn't resolve return new ResolveResult($resolvedPathSegment, UriConstraints::create()->withHost('some-domain.tld'), RouteTags::createFromTag('some-tag')); } ``` *Note:* The UriConstraints and RouteTags arguments are optional *Note:* For backwards compatibility the above still works as before ## Breaking Change This isn't a breaking feature in the strict sense because it doesn't affect the public API. But it introduces some profound changes that potentially requires 3rd party code to be adjusted: #### UriBuilder return type `UriBuilder::build()` (and thus also `UriBuilder::uriFor()`) no longer returns a `string` but instead an instance of `UriInterface`. In most places this won't be a problem, because it can be casted to a string but sometimes you need to manually convert the result: `$uri = (string)$uri;` #### RouterInterface signature In case you implemented a custom router: Congratulations for being brave! You'll need to slightly adjust the code due to the modified signature of the two methods `route` and `resolve`: *Previously:* ```php /** * @return array|null **/ public function route(Request $httpRequest); /** * @return string **/ public function resolve(array $routeValues); ``` *Now:* ```php public function route(RouteContext $routeContext): array; public function resolve(ResolveContext $resolveContext): UriInterface; ``` #### RouterCachingService Some public methods of the `RouterCachingService` have been changed and you might need to adjust code that accesses those (directly or via AOP). Resolves: #1120
This partly reverts neos#1126 by casting the resolved URI so that `UriBuilder::uriFor()` and `UriBuilder::build()` returns a `string` again rather than an instance of `UriInterface`. Background: Even though `UriInterface` is mostly casted to a string implicitly, this change was considered "too dangerous" for a minor release because it breaks code that relies on the previous return type (i.e. when serializing the resolved URI). For the next major release we can re-consider this change. Related: neos#1120
An overhauled Router implementation that allows for more flexible routing. ## Features: ### Routing Parameters Routing `Parameters` can be defined globally (via HTTP component) in order to allow custom RoutePart handler to react to influences that are outside of the incoming URI path (example: The requested host name or scheme) For a RoutePart handler to access the parameters they have to implement the new `ParameterAwareRoutePartInterface`. The `DynamicRoutePart` already implements the interface. For custom implementations extending `DynamicRoutePart` the parameters will be accessible via `$this->parameters`. ### Extended URI matching RoutePart handlers can now return an instance of `MatchResult` when mapping incoming requests. This allows the handler to specify *Tags* to be associated with the route. #### Example: *Before:* ```php protected function matchValue($value) { // custom logic, returning false if the $value doesn't match $this->value = $matchedValue; return true; } ``` *Now:* ```php protected function matchValue($value) { // custom logic, returning false if the $value doesn't match return new MatchResult($matchedValue, RouteTags::createFromTag('some-tag')); } ``` *Note:* The RouteTags argument is optional *Note:* For backwards compatibility the above still works as before ### Extended URI resolving Similar to the above, RoutePart handlers can now specify tags for *resolved* routes by returning an instance of `ResolveResult`. This also allows RouteParts to specify `UriConstraints` that will affect the resolved URI. UriConstraints allow to pre-set the following attributes of the resulting URI: * Scheme (for example "https") * Host (for example "www.somedomain.tld") * Host prefix (for example "en.") * Host suffix (for example "co.uk") * Port (for example 443) * Path (for example "some/path") * Path prefix (for example "en/") * Path suffix (for example ".html") #### Example: *Before:* ```php protected function resolveValue($value) { // custom logic, returning false if the $value doesn't resolved $this->value = $resolvedPathSegment; return true; } ``` *Now:* ```php protected function resolveValue($value) { // custom logic, returning false if the $value doesn't resolve return new ResolveResult($resolvedPathSegment, UriConstraints::create()->withHost('some-domain.tld'), RouteTags::createFromTag('some-tag')); } ``` *Note:* The UriConstraints and RouteTags arguments are optional *Note:* For backwards compatibility the above still works as before ## Breaking Change This isn't a breaking feature in the strict sense because it doesn't affect the public API. But it introduces some profound changes that potentially requires 3rd party code to be adjusted: #### UriBuilder return type `UriBuilder::build()` (and thus also `UriBuilder::uriFor()`) no longer returns a `string` but instead an instance of `UriInterface`. In most places this won't be a problem, because it can be casted to a string but sometimes you need to manually convert the result: `$uri = (string)$uri;` #### RouterInterface signature In case you implemented a custom router: Congratulations for being brave! You'll need to slightly adjust the code due to the modified signature of the two methods `route` and `resolve`: *Previously:* ```php /** * @return array|null **/ public function route(Request $httpRequest); /** * @return string **/ public function resolve(array $routeValues); ``` *Now:* ```php public function route(RouteContext $routeContext): array; public function resolve(ResolveContext $resolveContext): UriInterface; ``` #### RouterCachingService Some public methods of the `RouterCachingService` have been changed and you might need to adjust code that accesses those (directly or via AOP). Resolves: neos#1120
This partly reverts neos#1126 by casting the resolved URI so that `UriBuilder::uriFor()` and `UriBuilder::build()` returns a `string` again rather than an instance of `UriInterface`. Background: Even though `UriInterface` is mostly casted to a string implicitly, this change was considered "too dangerous" for a minor release because it breaks code that relies on the previous return type (i.e. when serializing the resolved URI). For the next major release we can re-consider this change. Related: neos#1120
Extend the Router as follows:
1. Extend RouterInterface
As a first step we should change the
RouterInterface
from:to sth like:
RouteContext
contains some optionalrouteValues
in addition to the currentHttp\Request
(so that we can pre-set route values before the routing kicks in).RouteResult
wraps the resolvedrouteValues
and/or contains a flag whether a route matched at all.ResolveContext
contains therouteValues
in addition to the currentHttp\Request
and (in v2) some flags likeforceAbsoluteUrl
,forceScheme
ResolveResult
contains the resolvedHttp\Uri
and/or a flag whether a route resolved2. Adjust Router Cache
The cache identifiers must be built from the
RouteContext
/ResolveContext
(i.e. they should probably implement theCacheAwareInterface
)3. Allow hooking into RouteContext
I.e. it should be possible to write a
Http\Component
that can setrouteValues
for the currentRouteContext
(example: extract language from theAccept-Language
HTTP header and set a routeValue correspondingly)4. Allow hooking into ResolveResult
Introduce a signal that allows 3rd party code to hook into the
ResolveResult
just before it is put into the Cache. It should receive theResolveContext
and the currentResolveResult
and might return a new result (or modify the existing one somehow)To be discussed
Background:
This will allow 3rd party packages (and Neos) to hook into the routing process and is a first step for a fully fledged multi-domain routing in Flow as described in #614
Neos: 3.3 LTS
Flow: 4.3 LTS
The text was updated successfully, but these errors were encountered: