Skip to content

Commit

Permalink
Use PHP 8.1+ language features (#25)
Browse files Browse the repository at this point in the history
Mostly typed properties, return type and parameter type hints.

Typed properties force us not to overload `TranslatableClassMetadata`
fields with two possible kinds of values when serializing it. Instead,
use a dedicated (type-safe) class for serialized data.
  • Loading branch information
mpdude authored Jan 5, 2024
1 parent 1f8184e commit 44958a9
Show file tree
Hide file tree
Showing 16 changed files with 249 additions and 345 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

"require": {
"php": "8.1.*|8.2.*|8.3.*",
"doctrine/annotations": "^1.11",
"doctrine/annotations": "^1.12",
"doctrine/collections": "^1.0",
"doctrine/orm": "^2.2",
"doctrine/persistence": "^1.3.8 | ^2.1",
Expand Down
19 changes: 7 additions & 12 deletions src/Annotation/Locale.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,23 @@

namespace Webfactory\Bundle\PolyglotBundle\Annotation;

use Doctrine\Common\Annotations\Annotation;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;

/**
* @Annotation
* @NamedArgumentConstructor
* @Target({"CLASS","PROPERTY"})
*/
final class Locale extends Annotation
final class Locale
{
/**
* @var string
*/
protected $primary;
private ?string $primary;

public function setPrimary(string $value)
public function __construct(string $primary = null)
{
$this->primary = $value;
$this->primary = $primary;
}

/**
* @return string
*/
public function getPrimary()
public function getPrimary(): ?string
{
return $this->primary;
}
Expand Down
19 changes: 7 additions & 12 deletions src/Annotation/Translatable.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,22 @@

namespace Webfactory\Bundle\PolyglotBundle\Annotation;

use Doctrine\Common\Annotations\Annotation;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;

/**
* @Annotation
* @NamedArgumentConstructor
*/
final class Translatable extends Annotation
final class Translatable
{
/**
* @var string
*/
protected $translationFieldname;
private ?string $translationFieldname;

public function setTranslationFieldname(string $value)
public function __construct(string $translationFieldname = null)
{
$this->translationFieldname = $value;
$this->translationFieldname = $translationFieldname;
}

/**
* @return string
*/
public function getTranslationFieldname()
public function getTranslationFieldname(): ?string
{
return $this->translationFieldname;
}
Expand Down
122 changes: 33 additions & 89 deletions src/Doctrine/PersistentTranslatable.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,84 +30,65 @@ final class PersistentTranslatable implements TranslatableInterface
*
* @var array<string, array<string, object|null>>
*/
private static $_translations = [];
private static array $_translations = [];

/**
* Die Entität, in der sich dieser Proxy befindet (für die er Übersetzungen verwaltet).
*
* @var object
*/
private $entity;
private object $entity;

/**
* Der einzigartige Hash für die verwaltete Entität.
*
* @var string
*/
private $oid;
private string $oid;

/**
* @var string Sprache, die in der Entität direkt abgelegt ist ("originärer" Content)
* Sprache, die in der Entität direkt abgelegt ist ("originärer" Content).
*/
private $primaryLocale;
private ?string $primaryLocale;

/**
* @var mixed Der Wert in der primary locale (der Wert in der Entität, den der Proxy ersetzt hat)
* Der Wert in der primary locale (der Wert in der Entität, den der Proxy ersetzt hat).
*/
private $primaryValue;
private mixed $primaryValue;

/**
* Provider, über den der Proxy die Locale erhält, in der Werte zurückgeben soll, wenn keine andere Locale explizit gewünscht wird.
*
* @var DefaultLocaleProvider
*/
private $defaultLocaleProvider;
private DefaultLocaleProvider $defaultLocaleProvider;

/**
* ReflectionProperty für die Eigenschaft der Translation-Klasse, die den übersetzten Wert hält.
*
* @var ReflectionProperty
*/
private $translatedProperty;
private ReflectionProperty $translatedProperty;

/**
* ReflectionProperty für die Eigenschaft der Haupt-Klasse, in der die Übersetzungen als Doctrine Collection abgelegt sind.
*
* @var ReflectionProperty
*/
private $translationCollection;
private ReflectionProperty $translationCollection;

/**
* ReflectionClass für die Klasse, die die Übersetzungen aufnimmt.
*
* @var ReflectionClass
*/
private $translationClass;
private ReflectionClass $translationClass;

/**
* Das Feld in der Übersetzungs-Klasse, in dem die Locale einer Übersetzung abgelegt ist.
*
* @var ReflectionProperty
*/
private $localeField;
private ReflectionProperty $localeField;

/**
* Das Feld in der Übersetzungs-Klasse, in Many-to-one-Beziehung zur Entität abgelegt ist.
*
* @var ReflectionProperty
*/
private $translationMapping;
private ReflectionProperty $translationMapping;

/**
* @var LoggerInterface
*/
private $logger;
private LoggerInterface $logger;

/**
* Sammelt neu hinzugefügte Übersetzungen, damit wir sie explizit speichern können, wenn ein
* Objekt im ORM abgelegt wird.
*/
private $addedTranslations = [];
private array $addedTranslations = [];

public function __construct(
object $entity,
Expand All @@ -129,28 +110,20 @@ public function __construct(
$this->translationClass = $translationClass;
$this->localeField = $localeField;
$this->translationMapping = $translationMapping;
$this->logger = (null == $logger) ? new NullLogger() : $logger;
$this->logger = $logger ?? new NullLogger();
}

public function setPrimaryValue($value)
public function setPrimaryValue(mixed $value): void
{
$this->primaryValue = $value;
}

/**
* @return mixed|null
*/
public function getPrimaryValue()
public function getPrimaryValue(): mixed
{
return $this->primaryValue;
}

/**
* @param string $locale
*
* @return object|null
*/
private function getTranslationEntity($locale)
private function getTranslationEntity(string $locale): ?object
{
if (false === $this->isTranslationCached($locale)) {
$this->cacheTranslation($locale);
Expand All @@ -159,12 +132,7 @@ private function getTranslationEntity($locale)
return $this->getCachedTranslation($locale);
}

/**
* @param string $locale
*
* @return object
*/
private function createTranslationEntity($locale)
private function createTranslationEntity(string $locale): object
{
$className = $this->translationClass->name;
$entity = new $className();
Expand All @@ -180,10 +148,10 @@ private function createTranslationEntity($locale)
return $entity;
}

public function setTranslation($value, string $locale = null)
public function setTranslation(mixed $value, string $locale = null): void
{
$locale = $locale ?: $this->getDefaultLocale();
if ($locale == $this->primaryLocale) {
if ($locale === $this->primaryLocale) {
$this->primaryValue = $value;
} else {
$entity = $this->getTranslationEntity($locale);
Expand All @@ -197,7 +165,7 @@ public function setTranslation($value, string $locale = null)
/**
* @throws TranslationException
*/
public function translate(string $locale = null)
public function translate(string $locale = null): mixed
{
$locale = $locale ?: $this->getDefaultLocale();
try {
Expand All @@ -224,7 +192,7 @@ public function translate(string $locale = null)
}
}

public function isTranslatedInto(string $locale)
public function isTranslatedInto(string $locale): bool
{
if ($locale === $this->primaryLocale) {
return !empty($this->primaryValue);
Expand All @@ -235,10 +203,7 @@ public function isTranslatedInto(string $locale)
return $entity && null !== $this->translatedProperty->getValue($entity);
}

/**
* @return string
*/
public function __toString()
public function __toString(): string
{
try {
return (string) $this->translate();
Expand All @@ -252,30 +217,22 @@ public function __toString()
/**
* Clears the list of newly added translation entities, returning the old value.
*
* @return object[] The list of new entites holding translations (exact class depends on the entity containing this proxy), before being reset.
* @return list<object> The list of new entites holding translations (exact class depends on the entity containing this proxy), before being reset.
*/
public function getAndResetNewTranslations()
public function getAndResetNewTranslations(): array
{
$newTranslations = $this->addedTranslations;
$this->addedTranslations = [];

return $newTranslations;
}

/**
* @return string
*/
private function getDefaultLocale()
private function getDefaultLocale(): string
{
return $this->defaultLocaleProvider->getDefaultLocale();
}

/**
* @param string $locale
*
* @return bool
*/
private function isTranslationCached($locale)
private function isTranslationCached(string $locale): bool
{
return isset(self::$_translations[$this->oid][$locale]);
}
Expand All @@ -284,10 +241,8 @@ private function isTranslationCached($locale)
* The collection filtering API will issue a SQL query every time if the collection is not in memory; that is, it
* does not manage "partially initialized" collections. For this reason we cache the lookup results on our own
* (in-memory per-request) in a static member variable so they can be shared among all TranslationProxies.
*
* @param string $locale
*/
private function cacheTranslation($locale)
private function cacheTranslation(string $locale): void
{
/* @var $translationsInAllLanguages \Doctrine\Common\Collections\Selectable */
$translationsInAllLanguages = $this->translationCollection->getValue($this->entity);
Expand All @@ -299,31 +254,20 @@ private function cacheTranslation($locale)
self::$_translations[$this->oid][$locale] = $translationInLocale;
}

/**
* @return Criteria
*/
private function createLocaleCriteria($locale)
private function createLocaleCriteria($locale): Criteria
{
return Criteria::create()
->where(
Criteria::expr()->eq($this->localeField->getName(), $locale)
);
}

/**
* @param string $locale
*
* @return object|null
*/
private function getCachedTranslation($locale)
private function getCachedTranslation(string $locale): ?object
{
return self::$_translations[$this->oid][$locale];
}

/**
* @return string
*/
private function stringifyException(Exception $e)
private function stringifyException(Exception $e): string
{
$exceptionAsString = '';
while (null !== $e) {
Expand Down
Loading

0 comments on commit 44958a9

Please sign in to comment.