Как получить объект в разных переводах с Doctrine и Gedmo Transurable Extension

Я застрял со следующей проблемой: я хочу получить сущности доктрины определенной локали, не нарушая поведение моего приложения Symfony по умолчанию.

Вот пример одной из моих сущностей:

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;

/**
* @ORM\Entity(repositoryClass="ProductRepository")
* @ORM\Table(name="product")
* @ORM\InheritanceType("SINGLE_TABLE")
* @ORM\DiscriminatorColumn(name="discr", type="string")
*/
class Product
{
/**
* @var integer $id
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;

/**
* @var string
* @ORM\Column(name="name", type="string")
* @Gedmo\Translatable
*/
protected $name;

// ...
}

Часть связанного хранилища доктрины:

class ProductRepository extends \Doctrine\ORM\EntityRepository
{
public function findOneProductInLocale($id, $locale)
{
$qb = $this->createQueryBuilder('p')
->select('p')
->where('p.id = :id')
->setMaxResults(1)
->setParameter('id', $id);
;

$query = $qb->getQuery();

$query->setHint(
\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER,
'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'
);

// force Gedmo Translatable to not use current locale
$query->setHint(
\Gedmo\Translatable\TranslatableListener::HINT_TRANSLATABLE_LOCALE,
$locale
);

$query->setHint(
\Gedmo\Translatable\TranslatableListener::HINT_FALLBACK,
1
);

return $query->getOneOrNullResult();
}
}

и часть моих сценариев:

// default Locale: en
// request Locale: de
$repo = $em->getRepository('Acme\\Entity\\Product');

$product1 = $repo->findOneById($id);
echo $product1->getName(); // return 'Name (DE)'

$product_de = $repo->findOneProductInLocale($id, 'de');
echo $product_de->getName(); // return 'Name (DE)';

$product_en = $repo->findOneProductInLocale($id, 'en');
echo $product_en->getName(); // return 'Name (EN)'

echo $product1->getName(); // return 'Name (EN)' instead of 'Name (DE)' !! <-- What is wrong?

// even if I refetch a product
$product2 = $repo->findOneById($id);
echo $product2->getName(); // return 'Name (EN)' without taking anymore in account the current locale

Кто-то сейчас почему это не сработало, как ожидалось?
Что-то не так в моей реализации ProductRepository::findOneProductInLocale() ?

Любая помощь или подсказка приветствуется.

3

Решение

Я знаю, что опаздываю с ответом, но сталкиваюсь с той же проблемой & нашел решение. Надеюсь, это поможет другим разработчикам.

  1. Ваш findOneProductInLocale если прекрасно

    Это работает как дизайн — когда вы будете использовать findOneProductInLocale, запрос будет искать в данной локали, но конечный объект всегда будет загружен в текущей локали, ты не можешь это изменить.

  2. Однажды сущность была найдена с помощью findOneProductInLocale & загружен в текущей локали, Вы можете получить нужный вам вариант локали, используя setTranslatableLocale метод Гедмо & обновляя вашу сущность, как объясняют @umadesign

    // Reload the entity in different languages.
    $entity->setTranslatableLocale($locale);
    $em->refresh($entity);
    
  3. (Необязательно) Вам может понадобиться добавить setTranslatableLocale метод & свойство компаньона $local к вашей переводимой сущности

    class Product {
    // ...
    
    /**
    * @Gedmo\Locale
    * Used locale to override Translation listener`s locale
    * this is not a mapped field of entity metadata, just a simple property
    */
    private $locale;
    
    /**
    * Set the locale to use for translation listener
    *
    * @param string $locale
    *
    * @return static
    */
    public function setTranslatableLocale($locale) {
    $this->locale = $locale;
    return $this;
    }
    
    // ...
    }
    

Вы можете найти полное объяснение в Документация Gedmo в подразделе «Основные примеры использования».

0

Другие решения

Обновление сущности должно восстановить текущую локаль:

$em->refresh($product1);
0

Проблема в том, что ваш $product1, $product_de, $product_en а также $product2 все одинаковые. если ты var_dump у них они одинаковые object #id, Они относятся к одному и тому же Product Entity, Если вы изменяете что-либо в одном, оно изменяется во всех. Чтобы они отличались друг от друга, вы должны clone их.

$product_de = clone $repo->findOneProductInLocale($id, 'de');
$product_en = clone $repo->findOneProductInLocale($id, 'en');
0
По вопросам рекламы [email protected]