Search code examples
symfonyroutestranslationslug

How to implement a nice solution for multilang entity slug based routes in Symfony2


I'd like to create a simple bundle to handle some multilingual pages in a website with translated slugs.

Based on translatable, sluggable and i18nrouting

  1. implemented an entity (Page) with title, content, slug fields + locale property as the doc says
  2. created a new Page set its title and content then translated it by $page->setTranslatableLocale('de'); and set those fields again with the german values, so that the data in the tables looks fine, they are all there
  3. implemented the controller with type hinting signature: public function showAction(Page $page)
  4. generated some urls in the template by: {{ path("page_show", {"slug": "test", "_locale": "en"}) }} and {{ path("page_show", {"slug": "test-de", "_locale": "de"}) }}, routes are generated fine, they look correct (/en/test and /de/test-de)
  5. clicking on them:

Only the "en" translation works, the "de" one fails:

MyBundle\Entity\Page object not found.

How to tell Symfony or the Doctrine or whatever bundle to use the current locale when retrieving the Page? Do I have to create a ParamConverter then put a custom DQL into it the do the job manually? Thanks!


Solution

  • Just found another solution which I think is much nicer and i'm going to use that one!

    Implemented a repository method and use that in the controller's annotation:

    @ParamConverter("page", class="MyBundle:Page", options={"repository_method" = "findTranslatedOneBy"})

    public function findTranslatedOneBy(array $criteria, array $orderBy = null)
    {
        $page = $this->findOneBy($criteria, $orderBy);
    
        if (!is_null($page)) {
            return $page;
        }
    
        $qb = $this->getEntityManager()
            ->getRepository('Gedmo\Translatable\Entity\Translation')
            ->createQueryBuilder('t');
    
        $i = 0;
        foreach ($criteria as $name => $value) {
            $qb->orWhere('t.field = :n'. $i .' AND t.content = :v'. $i);
            $qb->setParameter('n'. $i, $name);
            $qb->setParameter('v'. $i, $value);
            $i++;
        }
    
        /** @var \Gedmo\Translatable\Entity\Translation[] $trs */
        $trs = $qb->groupBy('t.locale', 't.foreignKey')->getQuery()->getResult();
    
        return count($trs) == count($criteria) ? $this->find($trs[0]->getForeignKey()) : null;
    }
    

    It has one disadvantage there is no protection against same translated values ...