[Translateable] + Doctrine Table Inheritance: wrong object class in table "ext_translations"
klemens-u opened this issue · 0 comments
The environment is the same as in #2849.
When using [Translateable] + Doctrine Table Inheritance the wrong class name is saved in the translation database table.
Example: (Sorry Gedmo attributes are missing, we use a trait for that)
#[ORM\InheritanceType('SINGLE_TABLE')] // 'JOINED' does not make much of a difference as most fields are in custom_translations anyways
#[ORM\DiscriminatorColumn(name: 'discr', type: 'string')]
// Automatically generating the discriminator map is very expensive computation-wise
#[ORM\DiscriminatorMap([
AbstractPage::class => AbstractPage::class,
Page::class => Page::class,
])]
class AbstractPage
{
...
#[ORM\Entity(repositoryClass: PageRepository::class)]
class Page extends AbstractPage
{
...
Now when creating a new "Page" object, the "object_class" field in "ext_translations" reads "App\Entity\AbstractPage" instead of "App\Entity\Page" .
The problem lies somewhere in TranslateableListener::handleTranslatableObjectUpdate() in this section:
if ($persistNewTranslation) {
$translation = $translationMetadata->newInstance();
$translation->setLocale($locale);
$translation->setField($field);
if ($ea->usesPersonalTranslation($translationClass)) {
$translation->setObject($object);
} else {
$translation->setObjectClass($config['useObjectClass']);
$translation->setForeignKey($objectId);
}
}
This traces further back to loadMetadataForObjectClass()
where the wrong (base class name) is used.
Workaround: overwrite loadMetadataForObjectClass() in a custom TranslatableListener.
config/services.yaml:
App\EventListener\CustomTranslatableListener:
decorates: 'stof_doctrine_extensions.listener.translatable'
src/EventListener/CustomTranslatableListener.php
<?php
namespace App\EventListener;
use Doctrine\Persistence\ObjectManager;
use Gedmo\Translatable\TranslatableListener;
class CustomTranslatableListener extends TranslatableListener
{
public function loadMetadataForObjectClass(ObjectManager $objectManager, $metadata)
{
parent::loadMetadataForObjectClass($objectManager, $metadata);
$className = $metadata->getName();
if (isset(self::$configurations[$this->name][$className])) {
// Always use the actual class name for useObjectClass
self::$configurations[$this->name][$className]['useObjectClass'] = $className;
}
}
}
Anyone knows why the actual class name is not used? This looks like an easy fix.
Thanks & have a nice day.