As explained in the Model View Controller chapter, in Flow the dispatcher passes the
request to a controller which then calls the respective action. But how to tell, what
controller of what package is the right one for the current request? This is were the
Routing Framework comes into play.

The request builder asks the router for the correct package, controller and action. For
this it passes the current request to the routers route() method. The router then
iterates through all configured routes and invokes their matches() method. The first
route that matches, determines which action will be called with what parameters.

The same works for the opposite direction: If a link is generated the routers resolve()
method calls the resolve() method of all routes until one route can return the correct
URI for the specified arguments.

Note

If no matching route can be found, a NotFoundException is thrown which
results in a 404 status code for the HTTP response and an error page being
displayed. In Development context that error page contains some more details
about the error that occurred.

A route describes the way from your browser to the controller - and back.

With the uriPattern you can define how a route is represented in the browser’s address
bar. By setting defaults you can specify package, controller and action that should
apply when a request matches the route. Besides you can set arbitrary default values that
will be available in your controller. They are called defaults because you can overwrite
them by so called dynamic route parts.

name is optional, but it’s recommended to set a name for all routes to make debugging
easier.

If you insert these lines at the beginning of the file Configurations/Routes.yaml,
the indexAction of the StandardController in your My.Demo package will be called
when you open up the homepage of your Flow installation (http://localhost/).

The URI pattern defines the appearance of the URI. In a simple setup the pattern only
consists of static route parts and is equal to the actual URI (without protocol and
host).

In order to reduce the amount of routes that have to be created, you are allowed to insert
markers, so called dynamic route parts, that will be replaced by the Routing Framework.
You can even mark route parts optional.

Now http://localhost/my/demo/list calls the listAction just like in the previous
example.

With http://localhost/my/demo/new you’d invoke the newAction and so on.

Note

It’s not allowed to have successive dynamic route parts in the URI pattern because it
wouldn’t be possible to determine the end of the first dynamic route part then.

The @ prefix should reveal that action has a special meaning here. Other predefined keys
are @package, @subpackage, @controller and @format. But you can use dynamic route parts to
set any kind of arguments:

If you add this route above the previously generated dynamic routes, an URI pointing to the show action of
the ProductController will look like http://localhost/products/afb275ed-f4a3-49ab-9f2f-1adff12c674f.

Probably you prefer more human readable URIs and you get them by specifying the objecttype:

This will add the title of the product category to the resulting URI:
http://localhost/products/product-category/the-product-name
The route part URI pattern can contain all properties of the object or it’s relations.

Note

For properties of type \DateTime you can define the date format by appending a PHP
date format string separated by colon: {creationDate:m-Y}. If no format is specified,
the default of Y-m-d is used.

Note

If an uriPattern is set or the objectType contains identity properties, mappings from an object to it’s
URI representation are stored in the ObjectPathMappingRepository in order to make sure that existing links
work even after a property has changed!
This mapping is not required if no uriPattern is set because in this case the mapping is ubiquitous.

Internally the above is handled by the so called IdentityRoutePart that gives you a lot of power and flexibility
when working with entities. If you have more specialized requirements or want to use routing for objects that are not
known to the Persistence Manager, you can create your custom route part handlers, as described below.

Route part handlers are classes that implement
Neos\Flow\Mvc\Routing\DynamicRoutePartInterface. But for most cases it will be
sufficient to extend Neos\Flow\Mvc\Routing\DynamicRoutePart and overwrite the
methods matchValue and resolveValue.

Let’s have a look at a (very simple) route part handler that allows you to match values against
configurable regular expressions:

The option toLowerCase will change the default behavior for this route
and reset it for the username route part.
Given the same username of “Kasper” the resulting URI will now be
http://localhost/Users/kasper (note the lower case “k” in “kasper”).

Matching of incoming URIs to static route parts is always done case sensitive. So “users/kasper” won’t match.
For dynamic route parts the case is usually not defined. If you want to handle data coming in through dynamic
route parts case-sensitive, you need to handle that in your own code.

Now route values that are neither defined in the uriPattern nor specified in the defaults will be
appended to the resulting URI: http://localhost/foo/dynamicValue?someOtherArgument=argumentValue

This setting is mostly useful for fallback routes and it is enabled for the default action route provided
with Flow, so that most links will work out of the box.

Note

The setting appendExceedingArguments is only relevant for creating URIs (resolve).
While matching an incoming request to a route, this has no effect. Nevertheless, all query parameters
will be available in the resulting action request via $actionRequest::getArguments().

Usually the Routing Framework does not care whether it handles a GET or POST request and just looks at the request path.
However in some cases it makes sense to restrict a route to certain HTTP methods. This is especially true for REST APIs
where you often need the same URI to invoke different actions depending on the HTTP method.

This can be achieved with a setting httpMethods, which accepts an array of HTTP verbs:

This will load the SubRoutes from a file Routes.Foo.yaml in the My.Demo package.
With that feature you can include multiple Routes with your package (for example providing different URI styles).
Furthermore you can nest routes in order to minimize duplication in your configuration. You nest SubRoutes by including
different SubRoutes from within a SubRoute, using the same syntax as before.
Additionally you can specify a set of variables that will be replaced in name, uriPattern and defaults
of merged routes:

Having to adjust the main Routes.yaml whenever you want to include SubRoutes can be cumbersome and error prone,
especially when working with 3rd party packages that come with their own routes.
Therefore Flow allows you to include SubRoutes via settings, too:

Settings.yaml (Configuration/Settings.yaml):

Neos:Flow:mvc:routes:'Some.Package':TRUE

This will include all routes from the main Routes.yaml file of the Some.Package (and all its nested SubRoutes
if it defines any).

You can also adjust the position of the included SubRoutes:

Neos:Flow:mvc:routes:'Some.Package':position:'start'

Internally Flow uses the PositionalArraySorter to resolve the order of SubRoutes loaded from Settings.
Following values are supported for the position option:

start (<weight>)

end (<weight>)

before <key> (<weight>)

after <key> (<weight>)

<numerical-order>

<weight> defines the priority in case of conflicting configurations. <key> refers to another package key allowing
you to set order depending on other SubRoutes.

Note

SubRoutes that are loaded via Settings will always be appended after Routes loaded via Routes.yaml
Therefore you should consider getting rid of the main Routes.yaml and only use settings to include routes
for greater flexibility.

It’s not possible to adjust route defaults or the UriPattern when including SubRoutes via Settings, but there are
two more options you can use:

For performance reasons the routing is cached by default.
During development of route part handlers it can be useful to disable the routing cache temporarily.
You can do so by using the following configuration in your Caches.yaml:

Also it can be handy to be able to flush caches for certain routes programmatically so that they can be
regenerated. This is useful for example to update all related routes when an entity was renamed.
The RouterCachingService allows flushing of all route caches via the flushCaches() method.
Individual routes can be removed from the cache with the flushCachesByTag() method.

Any UUID string (see UuidValidator::PATTERN_MATCH_UUID) in the route values (when resolving URIs) and the
match values (when matching incoming requests) will be added to the cache entries automatically
as well as an md5 hash of all URI path segments for matched and resolved routes.

Custom route part handlers can register additional tags to be associated with a route by returning an instance of
MatchResult / ResolveResult instead of true/false:

Most route parts only affect the path when resolving URIs.
Sometimes it can be useful for route parts to affect other parts of the resolved URI. For example there could
be routes enforcing https URIs, a specific HTTP port or global domain and path pre/suffixes.

In the last code example above the ResolveResult was constructed with the second argument being null.
This argument allows route part handlers to specify UriConstraints that can 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”)

Let’s have a look at another simple route part handler that allows you to enforce https URLs:

All URIs pointing to the respective action will be forced to be https:// URIs.

As you can see, in this example the route part handler doesn’t affect the URI path at all, so with the configured route
this will always point to the homepage. But of course route parts can specify a path (segment) and UriConstraints at the
same time.

The last example only carse about URI resolving. What if a route should react to conditions that are not extractable
from the request URI path? For example the counter-part to the example above, matching only https:// URIs?

Warning

One could be tempted to access the current request from within the route part handler using Dependency
Injection. But remember that routes are cached and that route part handlers won’t be invoked again once a
corresponding cache entry exists.

For route part handlers to safely access values that are not encoded in the URI path, those values have to be registered
as Routing Parameters, usually via a HTTP Component (see respective chapter about HTTP Foundation).

A HTTP Component that registers the current request scheme as Routing Parameter could look like this:

For route part handlers to be able to access the Routing Parameters they have to implement the ParameterAwareRoutePartInterface
and its matchWithParameters() method. The DynamicRoutePart already implements the interface and makes parameters
available in the parameters field.