Skip to content

Commit

Permalink
[Translatable] fix Type error for non-nullable getter upon a missing …
Browse files Browse the repository at this point in the history
…translation
  • Loading branch information
Florian Bogey authored and franmomu committed Mar 17, 2022
1 parent 529fdb3 commit d7e52a8
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ a release.
---

## [Unreleased]
### Added
- Translatable: Add defaultTranslationValue option to allow null or string value (#2167). TranslatableListener can hydrate object properties with null value, but it may cause a Type error for non-nullable getter upon a missing translation.

### Fixed
- Uploadable: `FileInfoInterface::getSize()` return type declaration (#2413).
- Tree: Setting a new Tree Root when Tree Parent is `null`.
Expand Down
9 changes: 9 additions & 0 deletions doc/translatable.md
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,15 @@ $translatableListener->setPersistDefaultLocaleTranslation(true); // default is f
This would always store translations in all locales, also keeping original record
translated field values in default locale set.

To set a default translation value upon a missing translation:

``` php
<?php
$translatableListener->setDefaultTranslationValue(''); // default is null
```

**Note**: By default the value is null, but it may cause a Type error for non-nullable getter upon a missing translation.

### Translation Entity

In some cases if there are thousands of records or even more.. we would like to
Expand Down
24 changes: 22 additions & 2 deletions src/Translatable/TranslatableListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,13 @@ class TranslatableListener extends MappedEventSubscriber
*/
private $translationInDefaultLocale = [];

/**
* Default translation value upon missing translation
*
* @var string|null
*/
private $defaultTranslationValue;

/**
* Specifies the list of events to listen
*
Expand Down Expand Up @@ -257,6 +264,17 @@ public function setTranslatableLocale($locale)
return $this;
}

/**
* Set the default translation value on missing translation
*
* @deprecated usage of a non nullable value for defaultTranslationValue is deprecated
* and will be removed on the next major release which will rely on the expected types
*/
public function setDefaultTranslationValue(?string $defaultTranslationValue): void
{
$this->defaultTranslationValue = $defaultTranslationValue;
}

/**
* Sets the default locale, this changes behavior
* to not update the original record field if locale
Expand Down Expand Up @@ -483,16 +501,18 @@ public function postLoad(EventArgs $args)
);
// translate object's translatable properties
foreach ($config['fields'] as $field) {
$translated = null;
$translated = $this->defaultTranslationValue;

foreach ($result as $entry) {
if ($entry['field'] == $field) {
$translated = $entry['content'] ?? null;

break;
}
}

// update translation
if (null !== $translated
if ($this->defaultTranslationValue !== $translated
|| (!$this->translationFallback && (!isset($config['fallback'][$field]) || !$config['fallback'][$field]))
|| ($this->translationFallback && isset($config['fallback'][$field]) && !$config['fallback'][$field])
) {
Expand Down
78 changes: 78 additions & 0 deletions tests/Gedmo/Translatable/Fixture/Issue2167/Article.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Doctrine Behavioral Extensions package.
* (c) Gediminas Morkevicius <gediminas.morkevicius@gmail.com> http://www.gediminasm.org
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Gedmo\Tests\Translatable\Fixture\Issue2167;

use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;

/**
* @ORM\Entity
*/
#[ORM\Entity]
class Article
{
/**
* @var int
*
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: Types::INTEGER)]
private $id;

/**
* @var string
*
* @Gedmo\Translatable
* @ORM\Column(name="title", type="string", length=128)
*/
#[Gedmo\Translatable]
#[ORM\Column(name: 'title', type: Types::STRING, length: 128)]
private $title;

/**
* @var string
*
* @Gedmo\Locale()
*/
#[Gedmo\Locale]
private $locale;

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

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

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

public function getLocale(): string
{
return $this->locale;
}

public function setLocale(string $locale): void
{
$this->locale = $locale;
}
}
111 changes: 111 additions & 0 deletions tests/Gedmo/Translatable/Issue/Issue2167Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Doctrine Behavioral Extensions package.
* (c) Gediminas Morkevicius <gediminas.morkevicius@gmail.com> http://www.gediminasm.org
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Gedmo\Translatable\Issue;

use Doctrine\Common\EventManager;
use Gedmo\Tests\Tool\BaseTestCaseORM;
use Gedmo\Tests\Translatable\Fixture\Issue2167\Article;
use Gedmo\Translatable\Entity\Translation;
use Gedmo\Translatable\TranslatableListener;

class Issue2167Test extends BaseTestCaseORM
{
private const TRANSLATION = Translation::class;
private const ENTITY = Article::class;

/**
* @var TranslatableListener
*/
private $translatableListener;

protected function setUp(): void
{
parent::setUp();

$evm = new EventManager();

$this->translatableListener = new TranslatableListener();
$this->translatableListener->setTranslatableLocale('en');
$this->translatableListener->setDefaultLocale('en');
$this->translatableListener->setTranslationFallback(false);
$evm->addEventSubscriber($this->translatableListener);

$this->getDefaultMockSqliteEntityManager($evm);
}

public function testShouldFindInheritedClassTranslations(): void
{
$enTitle = 'My english title';
$deTitle = 'My german title';

// English
$entity = new Article();
$entity->setTitle($enTitle);
$entity->setLocale('en');
$this->em->persist($entity);
$this->em->flush();

// German
$entity->setLocale('de');
$entity->setTitle($deTitle);
$this->em->flush();

// Find with default translation value as null value (default setting)
$entityInEn = $this->findUsingQueryBuilder('en');
$entityInDe = $this->findUsingQueryBuilder('de');
$entityInFr = $this->findUsingQueryBuilder('fr');

static::assertSame($enTitle, $entityInEn->getTitle());
static::assertSame($deTitle, $entityInDe->getTitle());
static::assertNull($entityInFr->getTitle());

// Find with default translation value as empty string
$this->translatableListener->setDefaultTranslationValue('');

$entityInEn = $this->findUsingQueryBuilder('en');
$entityInDe = $this->findUsingQueryBuilder('de');
$entityInFr = $this->findUsingQueryBuilder('fr');

static::assertSame($enTitle, $entityInEn->getTitle());
static::assertSame($deTitle, $entityInDe->getTitle());
static::assertSame('', $entityInFr->getTitle());

// Find with default translation value as not empty string
$this->translatableListener->setDefaultTranslationValue('no_translated');

$entityInEn = $this->findUsingQueryBuilder('en');
$entityInDe = $this->findUsingQueryBuilder('de');
$entityInFr = $this->findUsingQueryBuilder('fr');

static::assertSame($enTitle, $entityInEn->getTitle());
static::assertSame($deTitle, $entityInDe->getTitle());
static::assertSame('no_translated', $entityInFr->getTitle());
}

protected function getUsedEntityFixtures(): array
{
return [
self::TRANSLATION,
self::ENTITY,
];
}

private function findUsingQueryBuilder(string $locale): ?Article
{
$this->em->clear();
$this->translatableListener->setTranslatableLocale($locale);

$qb = $this->em->createQueryBuilder()->select('e')->from(self::ENTITY, 'e');

return $qb->getQuery()->getSingleResult();
}
}

0 comments on commit d7e52a8

Please sign in to comment.