Skip to content

Instantly share code, notes, and snippets.

@jeroendesloovere
Last active August 4, 2022 12:29
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jeroendesloovere/0e339b0c90449e507066d84933411639 to your computer and use it in GitHub Desktop.
Save jeroendesloovere/0e339b0c90449e507066d84933411639 to your computer and use it in GitHub Desktop.
Doctrine Translatable

Doctrine Translatable

With Translatable you can translate the fields you like in your Doctrine Entity. Check out other Doctrine Extensions

  • Official Doctrine Extensions installation guide here.
  • Official Doctrine Translatable documentation over here.

Installation

composer.json

{
    "require": {
        "php": ">=5.3.2",
        "symfony/symfony": "2.3.*",
        "doctrine/orm": "~2.2,>=2.2.3",
        "doctrine/doctrine-bundle": "~1.2",

        "gedmo/doctrine-extensions": "dev-master",
    }
}

app/config/parameters.yml

parameters
    locale: nl

app/config/config.xml

imports:
    # ...
    - { resource: doctrine_extensions.yml }
doctrine:
    dbal:
    # your dbal config here

    orm:
        auto_generate_proxy_classes: %kernel.debug%
        auto_mapping: true
        # only these lines are added additionally
        mappings:
            translatable:
                type: annotation
                alias: Gedmo
                prefix: Gedmo\Translatable\Entity
                # make sure vendor library location is correct
                dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity"

app/config/doctrine_extensions.yml

# services to handle doctrine extensions
services:
    # KernelRequest listener
    extension.listener:
        class: Acme\DemoBundle\Listener\DoctrineExtensionListener
        calls:
            - [ setContainer, [ @service_container ] ]
        tags:
            # translatable sets locale after router processing
            - { name: kernel.event_listener, event: kernel.request, method: onLateKernelRequest, priority: -10 }
            # loggable hooks user username if one is in security context
            - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }

    gedmo.listener.translatable:
        class: Gedmo\Translatable\TranslatableListener
        tags:
            - { name: doctrine.event_subscriber, connection: default }
        calls:
            - [ setAnnotationReader, [ @annotation_reader ] ]
            - [ setDefaultLocale, [ %locale% ] ]
            - [ setTranslationFallback, [ false ] ]

src/Acme/DemoBundle/Listener/DoctrineExtensionListener.php

We must initialize translatable on kernel.request.

<?php
// file: src/Acme/DemoBundle/Listener/DoctrineExtensionListener.php
namespace Acme\DemoBundle\Listener;

use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

class DoctrineExtensionListener implements ContainerAwareInterface
{
    /**
     * @var ContainerInterface
     */
    protected $container;

    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
    }

    public function onLateKernelRequest(GetResponseEvent $event)
    {
        $translatable = $this->container->get('gedmo.listener.translatable');
        $translatable->setTranslatableLocale($event->getRequest()->getLocale());
    }

    public function onKernelRequest(GetResponseEvent $event)
    {
        $securityContext = $this->container->get('security.context', ContainerInterface::NULL_ON_INVALID_REFERENCE);
        if (null !== $securityContext && null !== $securityContext->getToken() && $securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
            $loggable = $this->container->get('gedmo.listener.loggable');
            $loggable->setUsername($securityContext->getToken()->getUsername());
        }
    }
}

Updating database schema

# you can check the entities
php app/console doctrine:mapping:info

# Updating database schema: this will create the ```ext_translations``` table
php app/console doctrine:schema:create

Example

Article Doctrine Entity

<?php
//filename: src/Backend/Modules/Blog/Entity/Article;
namespace Backend\Modules\Blog\Entity;

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

/**
 * @ORM\Table(name="articles")
 * @ORM\Entity
 */
class Article implements Translatable
{
    /** @ORM\Id @ORM\GeneratedValue @ORM\Column(type="integer") */
    private $id;

    /**
     * @Gedmo\Translatable
     * @ORM\Column(name="title", type="string", length=128)
     */
    private $title;

    /**
     * @Gedmo\Translatable
     * @ORM\Column(name="content", type="text")
     */
    private $content;

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

    public function getId()
    {
        return $this->id;
    }

    public function setTitle($title)
    {
        $this->title = $title;
    }

    public function getTitle()
    {
        return $this->title;
    }

    public function setContent($content)
    {
        $this->content = $content;
    }

    public function getContent()
    {
        return $this->content;
    }

    public function setTranslatableLocale($locale)
    {
        $this->locale = $locale;
    }
}

Insert Article with default language

$em = $this->get('doctrine.orm.entity_manager');

// will insert article in locale (= nl)
$article = new Backend\Modules\Blog\Entity\Article;
$article->setTitle('my title in nl');
$article->setContent('my content in nl');

$em->persist($article);
$em->flush();

Insert a translation for this Article

$em = $this->get('doctrine.orm.entity_manager');

// first load the article
$article = $em->find('Backend\Modules\Blog\Entity\Article', 1 /*article id*/);
$article->setTitle('my title in de');
$article->setContent('my content in de');
// change locale
$article->setTranslatableLocale('de_de');

$em->persist($article);
$em->flush();

Inserting multiple translations

$em = $this->get('doctrine.orm.entity_manager');

// persisting multiple translations, assume default locale is EN
$repository = $em->getRepository('Gedmo\\Translatable\\Entity\\Translation');

// it works for ODM also
$article = new Article();
$article->setTitle('My article nl');
$article->setContent('content nl');

$repository
    ->translate($article, 'title', 'en', 'my article en')
    ->translate($article, 'content', 'en', 'content en')
    ->translate($article, 'title', 'de', 'my article de')
    ->translate($article, 'content', 'de', 'content de')
    ->translate($article, 'title', 'ru', 'my article ru')
    ->translate($article, 'content', 'ru', 'content ru')
;

$em->persist($article);
$em->flush();

Database table articles

articles database table

Database table ext_translations

ext_translations database table

Updating same article also having one new translation

$em = $this->get('doctrine.orm.entity_manager');

$repo
    ->translate($article, 'title', 'lt', 'title lt')
    ->translate($article, 'content', 'lt', 'content lt')
    ->translate($article, 'title', 'ru', 'title ru change')
    ->translate($article, 'content', 'ru', 'content ru change')
    ->translate($article, 'title', 'en', 'title en (default locale) update')
    ->translate($article, 'content', 'en', 'content en (default locale) update')
;

$em->flush();

Get translations

$em = $this->get('doctrine.orm.entity_manager');

// reload in different language
$article = $em->find(BackendBlogModel::ENTITY_CLASS, 1 /*article id for the item you want all translations for*/);

if (empty($article)) {
    throw new \Exception('Article id not exists');
}
        
$article->setTranslatableLocale('en_us');
$em->refresh($article);

$article = $em->find(BackendBlogModel::ENTITY_CLASS, 1 /*article id for the item you want all translations for*/);
$repository = $em->getRepository('Gedmo\Translatable\Entity\Translation');
$translations = $repository->findTranslations($article);

More examples can be found in official documentation).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment