Custom i18n routing in Symfony

Solution 1:

In your controller, you have to override method used in entity repository:

/**
 * @Template
 * @ParamConverter(
 *     "category",
 *     class = "AcmeSiteBundle:Category",
 *     options = {
 *         "repository_method" = "findByTranslatedSlug"
 *     }
 *  )
 */
public function detailAction(Category $category)
{}

 

namespace Acme\Bundle\SiteBundle\Entity;

use Doctrine\ORM\EntityRepository;

class CategoryRepository extends EntityRepository
{
    public function findByTranslatedSlug($slug)
    {
        $qb = $this->createQueryBuilder('c')
            ->where('c.slug = :slug')
            ->setParameters($slug);

        $query = $qb->getQuery();
        // set the translation query hint
        $query->setHint(
            \Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER,
            'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'
        );

        return $query->getOneOrNullResult();
    }
}

Solution 2:

As i see you are using the ParamConverter to automatically fetch your category.

If slug-in-englishis an existing slug in your database but doctrine refuses to fetch it.

You probably don't have the TranslatableListener added to your EntityManager at that point.

Example:

$translatableListener = new \Gedmo\Translatable\TranslationListener();
$translatableListener->setTranslatableLocale('en_us');
$em->addEventSubscriber($translatableListener);

If you're using StofDoctrineExtensionsBundle:

stof_doctrine_extensions:
    default_locale: en_US
    orm:
        default:
            # ...
            translatable: true

Solution 3:

I had the same issue and as suggested by jkucharovic, you can use the Doctrine ParamConverter to convert your request parameters to an object

To fetch an object from the database, the Doctrine converter uses by default find() method. But since we use Translatable, therefore multiple tables, it is not enough to manage translations, that's why we need to define our own. Here comes findByTranslatedSlug.

/**
 * @Template
 * @ParamConverter(
 *     "category",
 *     class = "AcmeSiteBundle:Category",
 *     options = {
 *         "id" = "slug",
 *         "repository_method" = "findByTranslatedSlug"
 *     }
 *  )
 */
public function detailAction(Category $category)
{}

Some details about ParamConverter parameters:

  • First parameter "category" refers to the name of the method argument (here $category)
  • "id" option refers to the route placeholder you want to pass(here {slug}) to the customised repository method (findByTranslatedSlug()). Without setting this option, it would throw a PDO exception.

 

namespace Acme\Bundle\SiteBundle\Entity;

use Doctrine\ORM\EntityRepository;

class CategoryRepository extends EntityRepository
{
    public function findByTranslatedSlug($slug)
    {
        $qb = $this->createQueryBuilder('c')
            ->where('c.slug = :slug')
            ->setParameter('slug',$slug);

        $query = $qb->getQuery();
        // set the translation query hint
        $query->setHint(
            \Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER,
            'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'
        );
        // If you need to set manually the locale to en_US, you can set this query hint
        //$query->setHint(\Gedmo\Translatable\TranslatableListener::HINT_TRANSLATABLE_LOCALE, 'en_US');

        return $query->getOneOrNullResult();
    }
}

I hope this can help

Docs:

  • Doctrine ParamConverter
  • Translatable ORM Query Hint