Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/3.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
mpdude committed Apr 26, 2024
2 parents 4f71ad7 + 9c3420b commit 7d87596
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 9 deletions.
23 changes: 14 additions & 9 deletions src/Doctrine/TranslatableClassMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -185,27 +185,32 @@ private function findTranslatedProperties(ClassMetadata $cm, ClassMetadataFactor
return;
}

$reflectionService = $classMetadataFactory->getReflectionService();
$translationClassMetadata = $classMetadataFactory->getMetadataFor($this->translationClass->getName());

foreach ($cm->fieldMappings as $fieldName => $mapping) {
if (isset($mapping['declared'])) {
// The association is inherited from a parent class
/* Iterate all properties of the class, not only those mapped by Doctrine */
foreach ($cm->getReflectionClass()->getProperties() as $reflectionProperty) {
$propertyName = $reflectionProperty->name;

/*
If the property is inherited from a parent class, and our parent entity class
already contains that declaration, we need not include it.
*/
$declaringClass = $reflectionProperty->getDeclaringClass()->name;
if ($declaringClass !== $cm->name && $cm->parentClasses && is_a($cm->parentClasses[0], $declaringClass, true)) {
continue;
}

$reflectionProperty = $cm->getReflectionProperty($fieldName);
$attributes = $reflectionProperty->getAttributes(Attribute\Translatable::class);

if (!$attributes) {
continue;
}

$attribute = $attributes[0]->newInstance();
$translationFieldname = $attribute->getTranslationFieldname() ?: $fieldName;
$translationFieldReflectionProperty = $translationClassMetadata->getReflectionProperty($translationFieldname);

$this->translatedProperties[$fieldName] = $reflectionProperty;
$this->translationFieldMapping[$fieldName] = $translationFieldReflectionProperty;
$this->translatedProperties[$propertyName] = $reflectionService->getAccessibleProperty($cm->name, $propertyName);
$translationFieldname = $attribute->getTranslationFieldname() ?: $propertyName;
$this->translationFieldMapping[$propertyName] = $reflectionService->getAccessibleProperty($translationClassMetadata->name, $translationFieldname);
}
}

Expand Down
117 changes: 117 additions & 0 deletions tests/Functional/TranslatingUnmappedPropertiesTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php

namespace Webfactory\Bundle\PolyglotBundle\Tests\Functional;

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\Translatable;

/**
* This test covers that also properties which are not mapped Doctrine fields
* can be marked as translatable and will be handled by the PolyglotListener.
*
* This is useful when these fields are managed or updated by e. g. lifecycle callbacks
* or other Doctrine event listeners.
*/
class TranslatingUnmappedPropertiesTest extends FunctionalTestBase
{
protected function setUp(): void
{
parent::setUp();
$this->setupOrmInfrastructure([
TranslatingUnmappedPropertiesTest_Entity::class,
TranslatingUnmappedPropertiesTest_Translation::class,
]);
}

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

$this->infrastructure->import($entity);

$loaded = $this->infrastructure->getEntityManager()->find(TranslatingUnmappedPropertiesTest_Entity::class, $entity->id);

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

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

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

#[ORM\Column(type: "string")]
public $mappedText;

// (!) This field is unmapped from the ORM point of view
#[Polyglot\Translatable]
public $text;

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

#[ORM\PreFlush]
public function copyToMappedField(): void
{
$this->mappedText = $this->text;
}

#[ORM\PostLoad]
public function copyFromMappedField(): void
{
$this->text = $this->mappedText;
}
}

#[ORM\Entity]
#[ORM\HasLifecycleCallbacks]
class TranslatingUnmappedPropertiesTest_Translation
{
#[ORM\Column(type: 'integer')]
#[ORM\Id]
#[ORM\GeneratedValue]
private ?int $id = null;

#[ORM\Column(type: "string")]
#[Polyglot\Locale]
private string $locale;

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

#[ORM\Column(type: "string")]
private $mappedText;

// (!) This field is unmapped from the ORM point of view
private $text;

#[ORM\PreFlush]
public function copyToMappedField(): void
{
$this->mappedText = $this->text;
}

#[ORM\PostLoad]
public function copyFromMappedField(): void
{
$this->text = $this->mappedText;
}
}

0 comments on commit 7d87596

Please sign in to comment.