l3pp4rd/DoctrineExtensions — pull request #176 by everzet (2011-10-23 11:47:10+00:00)
Title: Translatable refactoring

I've implemented another (alternative) way to do translations in
MongoDB and Doctrine2 projects. It's for sure more explicit than
current one during the setup stage, but it's way more predictive
and logical on usage stage.

### How to use

New translation way is just a single translator object, that can
translate specified entity properties with specific entity mapped
translations collection. In order to be able to use it, you should:

1. Add 1-to-M relation to the target entity (or document):

``` php
translations = new ArrayCollection();
}

...
}
```

2. Add `@ORM\HasLifecycleCallbacks` annotation to entity, add 2 hooks and modify constructor:

``` php
translations = new ArrayCollection();

$this->initializeTranslator();
}

/** @ORM\PrePersist */
public function translateEntityToDefaultLocale()
{
$this->translator->translate();
}

/** @ORM\PostLoad */
public function initializeTranslator()
{
if (null === $this->translator) {
$this->translator = new ObjectTranslator($this,
// List of translatable properties:
array('name'),
// Translation entity class:
'Translator\Fixture\PersonTranslation',
// Translations collection property:
$this->translations
);

return;
}

$this->translateEntityToDefaultLocale();
}

public function translate($locale = null)
{
return $this->translator->translate($locale);
}

...

}
```

3. And of course, define your translation entity:

```php
setName('Michael');
$person->setDescription('Superhuman');

```

And you can translate specified properties:

```php
translate()->setName('Michael');
$person->translate()->setDescription('Superhuman');
$enName = $person->translate()->getName();

// russian:
$person->translate('ru_RU')->setName('Михаил');
$person->translate('ru_RU')->setDescription('Суперчеловек');

echo $person->translate()->getName(); // => Michael
echo $person->translate('ru_RU')->getName(); // => Михаил

// Only properties, specified in ObjectTranslator constructor would be translated:
$person->translate()->getDescription() === $person->translate('ru_RU')->getDescription() === 'Суперчеловек';
```

Translations would be stored inside `$translations` collection and will
be persisted with entity automatically. Also, Doctrine2 will automatically
load them on demand:

```php
em->getRepository(self::PERSON)->findOneByName('Michael');

$this->assertSame('Michael', $person->getName());
$this->assertSame('Michael', $person->translate()->getName());
$this->assertSame('Михаил', $person->translate('ru_RU')->getName());
```

Or you can retrieve record *with* their translations through simple
fetch-join:

```php
em->getRepository(self::PERSON)
->createQueryBuilder('p')
->select('p, t')
->join('p.translations', 't')
->getQuery()
->getSingleResult();

$this->assertSame('Michael', $person->getName());
$this->assertSame('Michael', $person->translate()->getName());
$this->assertSame('Михаил', $person->translate('ru_RU')->getName());
```