Wednesday, September 14, 2011

Symfony2 - Add subdomain requirement in routing

I was reading a lot about ability to add routing requirement in Symfony2.

Couldn't find any good answer so I tried to write my own.

Basically what we want:

blog.example.com -> goes to some controller
example.com -> goes to different controllers

Solutions is quite simple:

We overwrite class that generates routing cache (even in dev env).

1. In your bundle (or somewhere in project) create routing cache dumper class:

eg. Acme\BlogBundle\Lib\PhpMatcherDumper.php

2. Add your class with overriding compileRoute function

Copy code from: http://pastie.org/2533804
Change namespace and class name

3. Overwrite default class in config.yml

parameters:
    router.options.matcher_dumper_class: Acme\BlogBundle\Lib\PhpMatcherDumper

4. Add requirements in routing
// Acme\BlogBundle\Controller\PostController.php

/**
 * Post controller.
 *
 * @Route(requirements={"_host" = "blog.example.com"})
 */

class PostController extends Controller
{
    /**
     * @Route("/"
)
     * @Template()
     */
    public function indexAction()
    {
        // some code
       
        return array();
    }


    /**
     * @Route("/smth"
, requirements={"_host" = "example.com"})
     * @Template()
     */
    public function someOtherAction()
    {
        // some code
       
        return array();
    }


Other controller:

// Acme\BlogBundle\Controller\DefaultController.php

/**
 * Default controller.
 *
 * @Route(requirements={"_host" = "example.com"})
 */

class DefaultController extends Controller
{

    /**
     * @Route("/"
)
     * @Template()
     */
    public function indexAction()
    {
        // some code
       
        return array();
    }


    /**
     * @Route("/smth"
, requirements={"_host" = "blog.example.com"})
     * @Template()
     */
    public function someOtherAction()
    {
        // some code
       
        return array();
    }


This gives us:
example.comDefaultController:indexAction
blog.example.comBlogController:indexAction
example.com/smthBlogController:someOtherAction
blog.example.com/smthDefaultController:someOtherAction

This should work with all types of routing (yaml, xml, php, annotations).

Why this only works in controllers?
In order to use "_host" in importing routes we would have to change couple of classes that parse, load and create classes from routing files.

~jpass

3 comments:

  1. Are this working with Twig? E.g. {{ path() }}, {{ url() }}

    ReplyDelete
  2. This code doesn't change the way path and url works.

    If you want to change domain/subdomain you need to call it explicitly href="http://example.com/{{path ('my_route') }}". Otherwise you stay in the same domain.

    ReplyDelete
  3. i dont get the 3 point.


    this is my config.yml.. did i put parameters: correctly?


    imports:
    - { resource: parameters.yml }
    - { resource: security.yml }

    framework:
    #esi: ~
    #translator: { fallback: %locale% }
    secret: %secret%
    router:
    resource: "%kernel.root_dir%/config/routing.yml"
    strict_requirements: %kernel.debug%
    form: true
    csrf_protection: true
    validation: { enable_annotations: true }
    templating: { engines: ['twig'] } #assets_version: SomeVersionScheme
    default_locale: %locale%
    trust_proxy_headers: false # Should Request object should trust proxy headers (X_FORWARDED_FOR/HTTP_CLIENT_IP)
    session: ~

    parameters:
    router.options.matcher_dumper_class: Landing\LandingBundle\Lib\PhpMatcherDumper

    # Twig Configuration
    twig:
    debug: %kernel.debug%
    strict_variables: %kernel.debug%

    # Assetic Configuration
    assetic:
    debug: %kernel.debug%
    use_controller: false
    bundles: [ ]
    #java: /usr/bin/java
    filters:
    cssrewrite: ~
    #closure:
    # jar: %kernel.root_dir%/Resources/java/compiler.jar
    #yui_css:
    # jar: %kernel.root_dir%/Resources/java/yuicompressor-2.4.7.jar

    # Doctrine Configuration
    doctrine:
    dbal:
    driver: %database_driver%
    host: %database_host%
    port: %database_port%
    dbname: %database_name%
    user: %database_user%
    password: %database_password%
    charset: UTF8

    orm:
    auto_generate_proxy_classes: %kernel.debug%
    auto_mapping: true

    # Swiftmailer Configuration
    swiftmailer:
    transport: %mailer_transport%
    host: %mailer_host%
    username: %mailer_user%
    password: %mailer_password%
    spool: { type: memory }

    ReplyDelete