phptwitter-bootstrapsymfonyknpmenubundleknpmenu

How to merge route parameters in MenuBuidler for language switcher functionality using KnpMenuBundle and Symfony3


Introduction

In my personal project I am using:

Setting up

To setup i used documentation in [2], [3] and code samples [4]. My menu is working, integration between Bootstrap and KnpMenuBundle also works.

Problem

In order to implement language switcher, i am using twig templates.

It works fine, but i would like to move to more scalable approach - namely - using dedicated bundle (KnpMenuBundle).

At the moment MenuBuilder produces ugly URLs (shown in results section of code sample 1). I would like it to generate links that are shown in results section of code sample 2.

I do not know how to achieve that.

Question

How can one produce pretty URLs using MenuBuilder?

How can one force merging of route parameters in MenuBuilder?

CODE: sample 1

sample of my MenuBuilder

$language['Language']->setChildrenAttribute("class", "dropdown-menu")
    ->addChild('Language LV', array('label' => 'language.lv', 'route' => 'homepage_lv', 'routeParameters' => array('_locale' => 'lv')))
    ->setExtra('translation_domain', 'language');
$language['Language']->setChildrenAttribute("class", "dropdown-menu")
    ->addChild('Language EN', array('label' => 'language.en', 'route' => 'homepage_en', 'routeParameters' => array('_locale' => 'en')))
    ->setExtra('translation_domain', 'language');
$language['Language']->setChildrenAttribute("class", "dropdown-menu")
    ->addChild('Language RU', array('label' => 'language.ru', 'route' => 'homepage_ru', 'routeParameters' => array('_locale' => 'ru')))
    ->setExtra('translation_domain', 'language');

produces following links:

locale change does not occurs

CODE: sample 2

conventional Menu twig template

<li><a href="{{ path(current_route, app.request.get('_route_params') | merge({'_locale': 'lv'})) }}">{{ "language.lv" | trans({}, "language") }}</a></li>
<li><a href="{{ path(current_route, app.request.get('_route_params') | merge({'_locale': 'en'})) }}">{{ "language.en" | trans({}, "language") }}</a></li>
<li><a href="{{ path(current_route, app.request.get('_route_params') | merge({'_locale': 'ru'})) }}">{{ "language.ru" | trans({}, "language") }}</a></li>

produces following links:

actually changes locale after clicking on them

CODE: sample 3

relevant part of my routing.yml file

# redirecting home
homepage:
    path: /
    defaults:
        _controller: 'FrameworkBundle:Redirect:redirect'
        route: home
        permanent: true

# redirecting home
homepage_lv:
    path: /lv/
    defaults:
        _controller: 'FrameworkBundle:Redirect:redirect'
        route: home
        permanent: true

# redirecting home
homepage_en:
    path: /en/
    defaults:
        _controller: 'FrameworkBundle:Redirect:redirect'
        route: home
        permanent: true

# redirecting home
homepage_ru:
    path: /ru/
    defaults:
        _controller: 'FrameworkBundle:Redirect:redirect'
        route: home
        permanent: true

home:
    path:     /{_locale}/home
    defaults: { _controller: 'AppBundle:Home:home' }
    requirements:
        _locale: lv|en|ru

Conclusion

Please advise.

Thank you for your time and knowledge.


Solution

  • So it looks like, that routes with parameters in MenuBuilder (as opposed to routes in twig templates) does not handle redirects in routing.yml

    That means that correct syntax for my case is:

    $language['Language']->setChildrenAttribute("class", "dropdown-menu")
        ->addChild('Language LV', array('label' => 'language.lv', 'route' => 'home', 'routeParameters' => array('_locale' => 'lv')))
        ->setExtra('translation_domain', 'language');
    $language['Language']->setChildrenAttribute("class", "dropdown-menu")
        ->addChild('Language EN', array('label' => 'language.en', 'route' => 'home', 'routeParameters' => array('_locale' => 'en')))
        ->setExtra('translation_domain', 'language');
    $language['Language']->setChildrenAttribute("class", "dropdown-menu")
        ->addChild('Language RU', array('label' => 'language.ru', 'route' => 'home', 'routeParameters' => array('_locale' => 'ru')))
        ->setExtra('translation_domain', 'language');
    

    And it results in pretty URLs.