I
I
Igor2020-01-21 00:20:37
symfony
Igor, 2020-01-21 00:20:37

Symfony database content in multiple languages?

Colleagues, hello!
I want to choose the best solution for the current task.
Task.
Content in the database in three languages.
ru, cn, en
Found several solutions.
1. Translatable Extension
2. Doctrine behaviors
Both have significant drawbacks, I hope they are not.
I tried to work with these extensions and realized that they are far from ideal.
Some of them are completely outdated.
In the documentation, the last mention of Symfony 2
Tried to re-use them.
Can't get the desired result.
Deadlines are tight.
Decided to go to extremes

/**
     * @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"};
    }

As you can see, it will work.
I don't see any particular problems.
Disadvantages:
The introduction of a new language requires intervention in all entities, this is a huge disadvantage.
But there are only 3 languages ​​on the horizon, Spanish is not planned.
Advise working strategies.
Or if my extreme version has no crime.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
D
Denis, 2020-01-21
@sidni

As an option, make a table of languages, and in your version leave the name and add the language_id, a little more complicated than your version but more extensible

I
Igor, 2020-01-21
@IgorPI

Found a solution for myself.
Not sure if this is good practice.
However, it seemed to me that this is what I need.
I describe the logic.

<?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"};
    }

}

The listener, in order to be able to switch the language property, which we will inherit from AbstractEntity, is a kind of contract.
<?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 }

It is clear that this solution is hard to scale.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question