Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/Doctrine/TranslatableClassMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,10 @@ private function findTranslatedProperties(ClassMetadata $cm, ClassMetadataFactor
private function findTranslationsCollection(ClassMetadata $cm, ClassMetadataFactory $classMetadataFactory): void
{
foreach ($cm->associationMappings as $fieldName => $mapping) {
if (isset($mapping['declared'])) {
// The association is inherited from a parent class
if (isset($mapping['inherited'])) {
// "inherited" means that there is another (inheritance parent) entity class containing this
// field (https://github.com/doctrine/orm/blob/580a95ce3f5f016547d15ecc6cc94dd85453bed5/src/Mapping/AssociationMapping.php#L34-L46).
// Since PolyglotListener::getTranslationMetadatas() loops over these parent classes as well, we can skip the field here.
continue;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Webfactory\Bundle\PolyglotBundle\Tests\Fixtures\Entity\EntityInheritance;

use Doctrine\ORM\Mapping as ORM;
use Webfactory\Bundle\PolyglotBundle\Attribute as Polyglot;

#[ORM\Entity]
#[Polyglot\Locale(primary: 'en_GB')]
class EntityInheritance_MappedSuperclassTranslation
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private ?int $id = null;

#[Polyglot\Locale]
#[ORM\Column]
private string $locale;

#[ORM\ManyToOne(targetEntity: EntityInheritance_MappedSuperclassWithTranslationsInterface::class, inversedBy: 'translations')]
private EntityInheritance_MappedSuperclassWithTranslationsInterface $entity;

#[ORM\Column]
private string $text;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace Webfactory\Bundle\PolyglotBundle\Tests\Fixtures\Entity\EntityInheritance;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Webfactory\Bundle\PolyglotBundle\Attribute as Polyglot;
use Webfactory\Bundle\PolyglotBundle\TranslatableInterface;

/**
* A mapped superclass that carries a translatable property, including translations.
* Since translations are a one-to-many relationship, the ResolveTargetEntityListener
* must be used to make the translation class ::$entity field reference back to this
* class here, see https://www.doctrine-project.org/projects/doctrine-orm/en/3.6/reference/inheritance-mapping.html#:~:text=ResolveTargetEntityListener.
*/
#[ORM\MappedSuperclass]
abstract class EntityInheritance_MappedSuperclassWithTranslations implements EntityInheritance_MappedSuperclassWithTranslationsInterface
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private ?int $id = null;

#[Polyglot\TranslationCollection]
#[ORM\OneToMany(targetEntity: EntityInheritance_MappedSuperclassTranslation::class, mappedBy: 'entity')]
private Collection $translations;

#[ORM\Column(type: 'string', nullable: true)]
#[Polyglot\Translatable]
protected TranslatableInterface|string|null $text = null;

public function __construct()
{
$this->translations = new ArrayCollection();
}

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

public function setText(TranslatableInterface $text): void
{
$this->text = $text;
}

public function getText(): TranslatableInterface|string|null
{
return $this->text;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Webfactory\Bundle\PolyglotBundle\Tests\Fixtures\Entity\EntityInheritance;

interface EntityInheritance_MappedSuperclassWithTranslationsInterface
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace Webfactory\Bundle\PolyglotBundle\Tests\Fixtures\Entity\EntityInheritance;

use Doctrine\ORM\Mapping as ORM;
use Webfactory\Bundle\PolyglotBundle\Attribute as Polyglot;

#[Polyglot\Locale(primary: 'en_GB')]
#[ORM\Entity]
class EntityInheritance_MappedSuperclassWithTranslations_Entity extends EntityInheritance_MappedSuperclassWithTranslations
{
}
89 changes: 89 additions & 0 deletions tests/Functional/MappedSuperclassWithTranslationsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

namespace Webfactory\Bundle\PolyglotBundle\Tests\Functional;

use Doctrine\ORM\Tools\ResolveTargetEntityListener;
use Webfactory\Bundle\PolyglotBundle\Tests\Fixtures\Entity\EntityInheritance\EntityInheritance_MappedSuperclassTranslation;
use Webfactory\Bundle\PolyglotBundle\Tests\Fixtures\Entity\EntityInheritance\EntityInheritance_MappedSuperclassWithTranslations;
use Webfactory\Bundle\PolyglotBundle\Tests\Fixtures\Entity\EntityInheritance\EntityInheritance_MappedSuperclassWithTranslations_Entity;
use Webfactory\Bundle\PolyglotBundle\Tests\Fixtures\Entity\EntityInheritance\EntityInheritance_MappedSuperclassWithTranslationsInterface;
use Webfactory\Bundle\PolyglotBundle\Translatable;

class MappedSuperclassWithTranslationsTest extends DatabaseFunctionalTestCase
{
protected function setUp(): void
{
parent::setUp();

$resolveTargetEntity = new ResolveTargetEntityListener();
$resolveTargetEntity->addResolveTargetEntity(
EntityInheritance_MappedSuperclassWithTranslationsInterface::class,
EntityInheritance_MappedSuperclassWithTranslations_Entity::class,
[]
);

$this->entityManager->getEventManager()->addEventSubscriber($resolveTargetEntity);

self::setupSchema([
EntityInheritance_MappedSuperclassWithTranslations::class,
EntityInheritance_MappedSuperclassWithTranslations_Entity::class,
EntityInheritance_MappedSuperclassTranslation::class,
]);
}

public function testPersistAndReloadEntity(): void
{
$entity = new EntityInheritance_MappedSuperclassWithTranslations_Entity();
$t = new Translatable('base text');
$t->setTranslation('Basistext', 'de_DE');
$entity->setText($t);

self::import([$entity]);

$loaded = $this->entityManager->find(EntityInheritance_MappedSuperclassWithTranslations_Entity::class, $entity->getId());

self::assertSame('base text', $loaded->getText()->translate('en_GB'));
self::assertSame('Basistext', $loaded->getText()->translate('de_DE'));
}

public function testAddTranslation(): void
{
$entityManager = $this->entityManager;

$entity = new EntityInheritance_MappedSuperclassWithTranslations_Entity();
$entity->setText(new Translatable('base text'));
self::import([$entity]);

$loaded = $entityManager->find(EntityInheritance_MappedSuperclassWithTranslations_Entity::class, $entity->getId());
$loaded->getText()->setTranslation('Basistext', 'de_DE');
$entityManager->flush();

$entityManager->clear();
$reloaded = $entityManager->find(EntityInheritance_MappedSuperclassWithTranslations_Entity::class, $entity->getId());

self::assertSame('base text', $reloaded->getText()->translate('en_GB'));
self::assertSame('Basistext', $reloaded->getText()->translate('de_DE'));
}

public function testUpdateTranslations(): void
{
$entityManager = $this->entityManager;

$entity = new EntityInheritance_MappedSuperclassWithTranslations_Entity();
$t = new Translatable('old text');
$t->setTranslation('alter Text', 'de_DE');
$entity->setText($t);
self::import([$entity]);

$loaded = $entityManager->find(EntityInheritance_MappedSuperclassWithTranslations_Entity::class, $entity->getId());
$loaded->getText()->setTranslation('new text');
$loaded->getText()->setTranslation('neuer Text', 'de_DE');
$entityManager->flush();

$entityManager->clear();
$reloaded = $entityManager->find(EntityInheritance_MappedSuperclassWithTranslations_Entity::class, $entity->getId());

self::assertSame('new text', $reloaded->getText()->translate('en_GB'));
self::assertSame('neuer Text', $reloaded->getText()->translate('de_DE'));
}
}