Friday, November 8, 2013

Using Symfony's routing.yml file for different host names

I like extensions, but when they crap out on you, you're kind of a sitting duck. So rather than rely on them, I figured I might as well learn to handle multiple domain names the extension-free way. Did you know this is now available in Symfony? How to match a route based on the host.
I needed a language toggle for my website, so that when a user is on the English site, the link to the French is available, and vice versa. Between routing.yml, parameters.yml, and config.yml, I was able to create a decent (but still "wordy") toggle for the pages I needed. (And as I type this, I realize that the correct way might be annotations instead. I'll look into that in a bit.)
Step 1: parameters.yml (in app/config/)
This is the only file that will contain the domain names in English and French. Ergo, all other config files will pull from this file. Specify keys like “domain_locale_en” and “domain_locale_fr” to hold the domain names of your English and French sites.
Step 2: config.yml (in app/config/)
This is the file where you’ll make the domain names available to the Twig (template) files. Modify the twig section.
    # ...
            domain_en:    %domain_locale_en%
            domain_fr:    %domain_locale_fr%
If you ever need to print out the domain in a link, for example, you can just do this:
< a href="%domain_en%">English blog< /a>
(If you try to include "http://" in parameters.yml, you’re going to get a surprise. At least, I did… I ended up in the default Symfony welcome page.)
Step 3: routing.yml (in app/config/)
This is the part that I’m sure can use a little more polishing, so if you have suggestions, please let me know. But, anyway, given that I now have two domain names for the root, I can code routing.yml like this:
  path:     /
  host:     %domain_locale_en%
  defaults: { _controller: BlogPostsBundle:Default:index }

  path:     /
  host:     %domain_locale_fr%
  defaults: { _controller: BlogPostsBundle:Default:index }
So, yes, whether it detects or, it’ll go to the same controller. Ugly, no?
The not-so-fun part
Because of this hack, all the other pages and routes in my site need to be registered twice in the routing file. For example, and lead to the same page, but Symfony needs to know that. This is how they look like in my routing.yml file:
    pattern:   /help
    host:      %domain_locale_en%
    defaults:  { _controller: BlogPostsBundle:Default:help }

    pattern:   /aide
    host:      %domain_locale_fr%
    defaults:  { _controller: BlogPostsBundle:Default:help }
Notice host:? This restricts the path to that particular domain name. So is totally legit, but try and it’ll fail. But if you take out host:, you can totally do a crossover (the latter link). As for what locale will be served up, it’ll be whatever the domain name’s locale is.
The cute part
I didn’t know you could force Twig to translate a string to a particular locale!
Assume that the controller for this page passed on variable $lang as either 'fr' or 'en' and $lang_name as 'English' or 'Fran├žais':
{% if lang == 'en' %}
    < a href="http://{{domain_fr}}/{{ 'help'|trans(locale='fr')}}>{{lang_name}}< /a>
{% else %}
    < a href="http://{{domain_en}}/{{ 'help'|trans(locale='en')}}>{{lang_name}}< /a>
{% endif %}
If you’re on the English site, force 'help' to be translated to the French string, and do similar if you’re on the French site.
Happy coding!

No comments:

Post a Comment