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

switch($path) {
    case '/':
        return $controller->renderHomepage();
    case '/about':
        return $controller->renderAbout();
    default:
        return $controller->render404();
}
            


What about /product/{id} ?


Regular Expressions!


What about flexibility and efficiency?


...


Use an existing library!

The Symfony Routing component

public interface RequestMatcherInterface
{
    /**
     * @param Request $request request to match
     *
     * @return array An array of parameters
     *
     * @throws ResourceNotFoundException
     * @throws MethodNotAllowedException
     */
    public function matchRequest(Request $request);
}

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

$context = $this->router->getContext();

$context->setHost('example.com');
$context->setScheme('https');
$context->setBaseUrl('my/path');

$this->router->generate(...);
            
Symfony documentation

Custom router implementation

Lets go full stack!

Not only configuration files

                # 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

function onKernelRequest(GetResponseEvent $event) {
  $accept = $event->getRequest()
      ->headers->get('accept');
  if ('user-context-hash' !== $accept) return;
  $hash = $this->hashGenerator->generateHash();
  $response = new Response('', 200, array(
    $this->hashHeader => $hash,
    'Content-Type' => 'user-context-hash',
  ));
  $event->setResponse($response);
}

LiipThemeBundle theme specific controllers

my_route:
    path: /welcome
    defaults:
        _controller: my_service:fooAction
        theme_controllers:
            a: my_other_service:fooAction
            b: App:Other:foo
function onKernelRequest(GetResponseEvent $event) {
    $request = $event->getRequest();
    $theme = $this->activeTheme->getName();
    $controllers = $request->attributes
        ->get('theme_controllers');
    if (isset($controllers[$theme])) {
        $request->attributes->set(
            '_controller',
            $controllers[$theme]
        );
    }
}
        

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