Antoine Viau
Antoine Viau

Reputation: 11

Doctrine : Translatable won't deliver translations for entities linked by @ManyToOne (or others associations)

Say you have a Category entity :

class Category 
{
    /**
     * @Gedmo\Translatable
     */
    private $categoryName;
}

And a Module entity.
Each Module belongs to one Category :

class Module 
{
    /**
     * @Gedmo\Translatable
     */
    private $moduleName;

    /**
     * @ManyToOne(targetEntity="Module")
     */
    private $category;
}

Using the query hint I can get a Module translated to a specific locale :

function getModule($id, $locale) 
{
    $query = $em->createQuery('select m from AppBundle\Entity\Module m where m.id=' . $id);
    $query->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE, $locale);
    $query->setHint(
        \Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER,
        'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'
    );
    $module = $query->getSingleResult();
    return $module;
}

Testing :

$module = getModule(1234, 'en');
// SUCCEED
$this->assertEquals('module name in english', $module->getModuleName();
$category = $module->getCategory();
// FAIL !
$this->assertEquals('category name in english', $category->getModuleName();
// SUCCEED (but one more request)
$category->setTranslatableLocale('en');
$em->refresh($category);
$this->assertEquals('category name in english', $category->getModuleName();

In few words : the query hint is able to insert a JOIN to the SELECT statement for the Module entity. Call to $module->getCategory() will trigger lazy loading. But this time, there will be no translation JOINed. Meaning I have to explicitly ask for the english version of the category.

Question : is it possible to have associated entities translated when querying the owner entity ? (having the FAILed test to succeed)

I already tried eager fetching on the ManyToOne association. Won't work because I am querying through DQL.

UPDATE :

To make this specific example to work (and have a better code) I can JOIN the Category in my DQL :

select m,c from Module join m.category where m.id=id

This will load the module and its category with the correct translations.

But in a perfect world I would love to have a generic code like this one :

protected function getEntityById($className, $id, $locale = null)
{
    $dql = 'select e from AppBundle\Entity\\' . $className . ' e where e.id=' . $id;
    $query = $this->em->createQuery($dql);
    $query->setHint(
        \Gedmo\Translatable\TranslatableListener::HINT_TRANSLATABLE_LOCALE,
        $locale
    );
    $query->setHint(
        \Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER,
        'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'
    );
    $entity = $query->getSingleResult();
    return $entity;
}

How to update this piece of code to have the associated entities to be loaded with the correct locale ?

Upvotes: 1

Views: 373

Answers (1)

Stepashka
Stepashka

Reputation: 2698

I'm afraid there is no way to affect the behaviour of $module->getCategory(). Association's loading can only be affected by using doctrine filters. Unfortunately these filters can only add to WHERE part of request, so it is not possible to add join.

I'd create a function in category repository to get category with the proper translation like you did in the getModule(). I don't think there is another way. Ex:

$category = $categoryRepository->findByModule18n($module, $locale);

Upvotes: 0

Related Questions