Задать вопрос

Symfony контент в базе данных на нескольких языках?

Коллеги, здравствуйте!

Хочу выбрать оптимально подходящее решение, для текущей задачи.

Задача.
Контент в базе данных на трёх языках.
ru, cn, en

Нашёл несколько решений.

1. Translatable Extension
2. Doctrine behaviors

Оба имеют существенные недостатки, надеюсь что это не так.
Попробовал поработать с этими расширениями и понял, они далеки от идеала.
Некоторые из них, вообще устарели.
В документации последнее упоминание о Symfony 2

Попробовал повторно заюзать их же.
Не могу получить желаемый результат.

Сроки жмут.

Решил пойти на крайности

/**
     * @ORM\Column(name="name", length=64)
     */
    private $name_ru;

    /**
     * @ORM\Column(length=64, nullable=true)
     */
    private $name_cn;

    /**
     * @ORM\Column(length=64, nullable=true)
     */
    private $name_en;

/**
     * @param $name
     * @param string $lang
     */
    public function setName($name, $lang = "ru")
    {
        $this->{"name_$lang"} = $name;
    }

    /**
     * @param string $lang
     * @return mixed
     */
    public function getName($lang = "ru")
    {
        return $this->{"name_$lang"};
    }


На глаз видно, работать будет.
Особых проблем не вижу.

Недостатки:
Внедрение нового языка требует вмешательство во все сущности, это огромный минус.
Но на горизонте только 3 языка, испанский не планируем.

Посоветуйте рабочие стратегии.
Или если мой крайний вариант не имеет криминала.
  • Вопрос задан
  • 122 просмотра
Подписаться 2 Простой Комментировать
Пригласить эксперта
Ответы на вопрос 2
@sidni
Php Developer
Как вариант сделать таблицу языков, а в вашем варианте оставить name и добавить language_id, немного усложненный чем Ваш вариант но более расширяемый
Ответ написан
IgorPI
@IgorPI Автор вопроса
Нашёл для себя решение.
Не уверен в том, что это адекватная практика.
Тем не менее, как мне показалось, это то что мне нужно.

Описываю логику.

<?php


namespace App\Classes\Entity;

/**
 * Class AbstractEntity
 * @package App\Classes\Entity
 */
abstract class AbstractEntity
{
    /** @var string  */
    protected $language = "ru";

    /**
     * @param string $language
     */
    public function setLanguage(string $language): void
    {
        $this->language = $language;
    }
}


<?php


namespace App\Entity;


use App\Classes\Entity\AbstractEntity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints\NotNull;
use Symfony\Component\Validator\Mapping\ClassMetadata;

/**
 * @ORM\Entity(repositoryClass="App\Repository\CategoryRepository")
 * @ORM\Table(name="categories")
 */
class Category extends AbstractEntity
{

    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue
     */
    private $id;

    /**
     * @ORM\Column(name="name", length=64)
     */
    private $name_ru;

    /**
     * @ORM\Column(length=64, nullable=true)
     */
    private $name_cn;

    /**
     * @ORM\Column(length=64, nullable=true)
     */
    private $name_en;

    /**
     * @return mixed
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param $name
     * @param string $lang
     */
    public function setName($name, $lang)
    {
        $this->{"name_$lang"} = $name;
    }

    /**
     * @return string
     */
    public function getName()
    {
        return $this->{"name_$this->language"};
    }

}


Слушатель, для того что бы можно было переключать свойство language, которые мы будем наследовать от AbstractEntity, своего рода контракт.

<?php


namespace App\Listeners;

use App\Classes\Entity\AbstractEntity;
use Doctrine\Persistence\Event\LifecycleEventArgs;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;


/**
 * Class LanguageEntityListener
 * @package App\Listeners
 */
class LanguageEntityListener
{

    /** @var string  */
    private $language = "ru";
    /** @var Request */
    private $request;

    /**
     * LanguageEntityListener constructor.
     * @param RequestStack $requestStack
     */
    public function __construct(RequestStack $requestStack)
    {
        $this->request = $requestStack->getCurrentRequest();
        $this->language = $this->request->get("lang", "ru");
    }


    public function postLoad(LifecycleEventArgs $event)
    {
        $entity = $event->getObject();

        if (is_a($entity, AbstractEntity::class)) {
            $entity->setLanguage($this->language);
        }
    }
}


services.yaml
services:
   
    app.listeners.language_entity_listener:
        class: App\Listeners\LanguageEntityListener
        arguments: ['@request_stack']
        tags:
            - { name: doctrine.event_listener, event: postLoad, method: postLoad }


5e264de82c98a283903729.gif

Понятное дело, что это решение тяжело масштабируется.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы