1/40

Symfony Routing

Under the hood


Symfony Con, Paris,
December 3rd, 2015


© David Buchmann

var
`-- www
    `-- htdocs
        |-- index.htm
        |-- about.htm
        `-- news.htm

What about...

Front controller

RewriteRule ^(.*)$ app.php [QSA,L]

Routing

1switch($path) {
2    case '/':
3        return $controller->renderHomepage();
4    case '/about':
5        return $controller->renderAbout();
6    default:
7        return $controller->render404();
8}


What about /product/{id} ?


Regular Expressions!


What about flexibility and efficiency?


...


Use an existing library!

The Symfony Routing component

01public interface RequestMatcherInterface
02{
03    /**
04     * @param Request $request request to match
05     *
06     * @return array An array of parameters
07     *
08     * @throws ResourceNotFoundException
09     * @throws MethodNotAllowedException
10     */
11    public function matchRequest(Request $request);
12}

The default router

Pop Quiz!

What is the fastest routing?

YML, XML, PHP or Annotations?

Correct: It does not matter!

Routing is compiled to PHP code

Caching

Optimizations

Optimizations: Group routes

/foo/x/{id}


/foo/y/{id}

/bar/baz
/foo
+---/x/
|   `--{id}
`---/y/
    `--{id}
/bar/baz

Tweaks in your application

Providing Context

1$context = $this->router->getContext();
2 
3$context->setHost('example.com');
4$context->setScheme('https');
5$context->setBaseUrl('my/path');
6 
7$this->router->generate(...);
Symfony documentation

Custom router implementation

Lets go full stack!

Not only configuration files

  • Since 2.8: Service as route resource:
# app/config/routing.yml
admin_routes:
    type: service
    resource: "admin_route_loader:loadRoutes"

Custom loader: FOSRestBundle

# app/config/routing.yml
product:
    type: rest
    resource: AppBundle\Controller\ProductController

Custom Routers: Multilanguage

JMSI18nRoutingBundle

# routing.yml
homepage:
    path:  /welcome
    defaults: { _controller: MyWebsiteBundle:Frontend:index }

# translations/routes.de.yml
homepage: /willkommen

BeSimpleI18nRoutingBundle

type: be_simple_i18n
...
homepage:
    locales:
        en: /welcome
        de: /willkommen
    defaults: { _controller: MyWebsiteBundle:Frontend:index }

Editable routes with CMF DynamicRouter

ChainRouter

Combine several routers

Look Beyond the Horizon

Beyond Request to Controller mapping

http://symfony.com/doc/current/components/http_kernel/introduction.html

ParamConverter

FOSHttpCacheBundle hash listener

01function onKernelRequest(GetResponseEvent $event) {
02  $accept = $event->getRequest()
03      ->headers->get('accept');
04  if ('user-context-hash' !== $accept) return;
05  $hash = $this->hashGenerator->generateHash();
06  $response = new Response('', 200, array(
07    $this->hashHeader => $hash,
08    'Content-Type' => 'user-context-hash',
09  ));
10  $event->setResponse($response);
11}

LiipThemeBundle theme specific controllers

my_route:
    path: /welcome
    defaults:
        _controller: my_service:fooAction
        theme_controllers:
            a: my_other_service:fooAction
            b: App:Other:foo
01function onKernelRequest(GetResponseEvent $event) {
02    $request = $event->getRequest();
03    $theme = $this->activeTheme->getName();
04    $controllers = $request->attributes
05        ->get('theme_controllers');
06    if (isset($controllers[$theme])) {
07        $request->attributes->set(
08            '_controller',
09            $controllers[$theme]
10        );
11    }
12}

ThormeierBreadcrumbBundle

acme_demo_home:
    path: /
    options:
        breadcrumb:
            label: Home
acme_demo_contact:
    path: /contact
    options:
        breadcrumb:
            label: Contact
            parent_route: acme_demo_home


Questions / Input / Feedback ?


Twitter: @dbu