NestedMatcher

NestedMatcher

The provided RequestMatcherInterface implementation is the NestedMatcher. It is suitable to use with DynamicRouter, and it uses a multiple step matching process to determine the resulting routing parameters from a given Request.

The NestedMatcher uses a 3-step matching process to determine which Route to use when handling the current Request:

  1. Ask the RouteProviderInterface for the collection of Route instances potentially matching the Request;
  2. Apply all RouteFilterInterface to filter down this collection;
  3. Let the FinalMatcherInterface instance decide on the best match among the remaining Route instances and transform it into the parameter array.

1. The RouteProvider

Although the RouteProviderInterface can be used in other ways, it's main goal is to be easily implemented on top of Doctrine PHPCR ODM or any other database, effectively allowing you to store and manage routes dynamically from the database.

Based on the Request, the NestedMatcher will retrieve an ordered collection of Route objects from the Route Provider. The idea of this provider is to provide all routes that could potentially match, but not to do any elaborate matching operations yet - this will be done in the later steps.

Tip

The RoutingBundle provides implementations for everything needed to get this component running with Doctrine PHPCR-ODM as well as with the Doctrine ORM.

Tip

This component provides the Candidates implementation for the very first step of splitting the URL on the / to allow matching with variable patterns.

To create and register your own Route Provider, create a class implementing Symfony\Cmf\Component\Routing\RouteProviderInterface which will have the following methods:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
use Symfony\Cmf\Component\Routing\RouteProviderInterface;

use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Exception\RouteNotFoundException;

class DoctrineOrmRouteProvider implements RouteProviderInterface
{
    // ...

    public function getRouteCollectionForRequest(Request $request)
    {
        // you should do some simple filtering on the URL here
        $routes = $this->routeRepository->findAll();

        $collection = new RouteCollection();
        if (0 === count($routes)) {
            return $collection; // an empty collection means no routes found
        }

        foreach ($routes as $route) {
            $collection->add($route);
        }

        return $collection;
    }

    public function getRouteByName($name, $parameters = array())
    {
        $route = $this->routeRepository->findByName($name);
        if (!$route) {
            throw new RouteNotFoundException("No route found for path '$name'");
        }

        return $route;
    }

    public function getRoutesByNames($names, $parameters = array())
    {
        return $this->routeRepository->createQueryBuilder('r')
            ->where("r.name IN (:names)")
            ->setParameter(':names', '"'.implode('","', $names.'"'))
            ->getQuery()
            ->getResult();
    }
}

The Route Provider is set using the first argument of the constructor for the NestedMatcher:

1
2
3
4
5
use Symfony\Cmf\Component\Routing\NestedMatcher\NestedMatcher;
// ...

$routeProvider = new DoctrineOrmRouteProvider(...);
$nestedMatcher = new NestedMatcher($routeProvider, ...);

2. The Route Filters

The NestedMatcher can apply user provided RouteFilterInterface implementations to reduce the provided Route objects, e.g. for doing content negotiation. It is the responsibility of each filter to throw the ResourceNotFoundException if no more routes are left in the collection.

Filters are created by implementing Symfony\Cmf\Component\Routing\NestedMatcher\RouteFilterInterface. They can be registered with the addRouteFilter method, which has an optional second argument to set the priority.

Note

The filter step is optional and meant for special cases. The CmfRoutingBundle does not use any filters by default.

3. The Final Matcher

The FinalMatcherInterface implementation has to find exactly one Route or throw an exception if no adequate match could be found. The default implementation uses the UrlMatcher of the Symfony Routing Component and is called Symfony\Cmf\Component\Routing\NestedMatcher\UrlMatcher.

You can create your own final matcher by implementing Symfony\Cmf\Component\Routing\NestedMatcher\FinalMatcherInterface.

The final matcher is set using the second argument of the constructor of the NestedMatcher:

1
2
3
4
5
use Symfony\Cmf\Component\Routing\NestedMatcher\UrlMatcher
// ...

$finalMatcher  = new UrlMatcher(...);
$nestedMatcher = new NestedMatcher($routeProvider, $finalMatcher);

This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License .