Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Doctrine Attribute Support #44

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
8 changes: 4 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@
"source": "https://github.com/prezent/doctrine-translatable"
},
"require": {
"php": ">=7.4.0",
"php": ">=8.2",
"doctrine/common": "^2.3|^3.0",
"doctrine/orm": ">=2.12.0",
"jms/metadata": "^1.1|^2.0",
"symfony/cache": "^5.0|^6.0",
"doctrine/annotations": "^1.13"
"symfony/cache": "^5.0|^6.0|^7.0",
"doctrine/annotations": "^2.0"
},
"require-dev": {
"symfony/yaml": "^5.0|6.0",
"symfony/yaml": "^5.0|^6.0|^7.0",
"phpunit/phpunit": "^8.5"
},
"autoload": {
Expand Down
4 changes: 3 additions & 1 deletion src/Annotation/CurrentLocale.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

namespace Prezent\Doctrine\Translatable\Annotation;
use Doctrine\ORM\Mapping\MappingAttribute;

/**
* CurrentTranslation annotation
Expand All @@ -18,6 +19,7 @@
* @Annotation
* @Target("PROPERTY")
*/
class CurrentLocale
#[\Attribute(\Attribute::TARGET_PROPERTY)]
class CurrentLocale implements MappingAttribute
{
}
4 changes: 3 additions & 1 deletion src/Annotation/FallbackLocale.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

namespace Prezent\Doctrine\Translatable\Annotation;
use Doctrine\ORM\Mapping\MappingAttribute;

/**
* CurrentTranslation annotation
Expand All @@ -18,6 +19,7 @@
* @Annotation
* @Target("PROPERTY")
*/
class FallbackLocale
#[\Attribute(\Attribute::TARGET_PROPERTY)]
class FallbackLocale implements MappingAttribute
{
}
7 changes: 6 additions & 1 deletion src/Annotation/Locale.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

namespace Prezent\Doctrine\Translatable\Annotation;

use Doctrine\ORM\Mapping\MappingAttribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;

/**
* CurrentTranslation annotation
*
Expand All @@ -17,7 +20,9 @@
*
* @Annotation
* @Target("PROPERTY")
* @NamedArgumentConstructor
*/
class Locale
#[\Attribute(\Attribute::TARGET_PROPERTY)]
class Locale implements MappingAttribute
{
}
15 changes: 14 additions & 1 deletion src/Annotation/Translatable.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
*/

namespace Prezent\Doctrine\Translatable\Annotation;
use Doctrine\ORM\Mapping\MappingAttribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;

/**
* Translatable annotation
Expand All @@ -16,8 +18,10 @@
*
* @Annotation
* @Target("PROPERTY")
* @NamedArgumentConstructor
*/
class Translatable
#[\Attribute(\Attribute::TARGET_PROPERTY)]
class Translatable implements MappingAttribute
{
/**
* @var string
Expand All @@ -28,4 +32,13 @@ class Translatable
* @var string
*/
public $referencedColumnName = 'id';


public function __construct(
?string $targetEntity,
?string $referencedColumnName = 'id'
) {
$this->targetEntity = $targetEntity;
$this->referencedColumnName = $referencedColumnName;
}
}
16 changes: 15 additions & 1 deletion src/Annotation/Translations.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,32 @@

namespace Prezent\Doctrine\Translatable\Annotation;

use Attribute;
use Doctrine\ORM\Mapping\MappingAttribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
use Doctrine\ODM\MongoDB\Utility\CollectionHelper;

/**
* Translations annotation
*
* This annotation indicates the one-to-many relation to the translations.
*
* @Annotation
* @Target("PROPERTY")
* @NamedArgumentConstructor
*/
class Translations
#[Attribute(Attribute::TARGET_PROPERTY)]
class Translations implements MappingAttribute
{
/**
* @var string
*/
public $targetEntity;

public function __construct(
?string $targetEntity = null
) {
$this->targetEntity = $targetEntity;
}
}
16 changes: 7 additions & 9 deletions src/Entity/TranslationTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,15 @@

trait TranslationTrait
{
/**
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
* @ORM\Column(name="id", type="integer")
*/

#[ORM\Column(name: 'id', type: 'integer', nullable: false)]
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'IDENTITY')]
protected $id;

/**
* @ORM\Column(name="locale", type="string")
* @Prezent\Locale
*/

#[ORM\Column(name: 'locale', type: 'string')]
#[Prezent\Locale]
protected $locale;

/**
Expand Down
129 changes: 129 additions & 0 deletions src/Mapping/Driver/AttributeDriver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?php

/*
* (c) Prezent Internet B.V. <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Prezent\Doctrine\Translatable\Mapping\Driver;

use Doctrine\ORM\Mapping\Driver\AttributeReader;
use Doctrine\Persistence\Mapping\ClassMetadataFactory;
use Metadata\ClassMetadata;
use Metadata\Driver\DriverInterface;
use Prezent\Doctrine\Translatable\Mapping\PropertyMetadata;
use Prezent\Doctrine\Translatable\Mapping\TranslatableMetadata;
use Prezent\Doctrine\Translatable\Mapping\TranslationMetadata;

/**
* Load translation metadata from annotations
*/
class AttributeDriver implements DriverInterface
{
/**
* @var AttributeReader
*/
private $reader;

/**
* Constructor
*
* @param AttributeReader $reader
* @param ClassMetadataFactory $factory Doctrine's metadata factory
*/
public function __construct(AttributeReader $reader)
{
$this->reader = $reader;
}

/**
* {@inheritdoc}
*/
public function loadMetadataForClass(\ReflectionClass $class): ?ClassMetadata
{
if ($class->implementsInterface('Prezent\\Doctrine\\Translatable\\TranslatableInterface')) {
return $this->loadTranslatableMetadata($class);
}

if ($class->implementsInterface('Prezent\\Doctrine\\Translatable\\TranslationInterface')) {
return $this->loadTranslationMetadata($class);
}

return null;
}

/**
* Load metadata for a translatable class
*
* @param \ReflectionClass $class
* @return TranslatableMetadata
*/
private function loadTranslatableMetadata(\ReflectionClass $class)
{
$classMetadata = new TranslatableMetadata($class->name);

foreach ($class->getProperties() as $property) {

if ($property->class !== $class->name) {
continue;
}

$propertyMetadata = new PropertyMetadata($class->name, $property->getName());
$targetEntity = $class->name . 'Translation';

if ($this->reader->getPropertyAttribute($property, 'Prezent\\Doctrine\\Translatable\\Annotation\\CurrentLocale')) {
$classMetadata->currentLocale = $propertyMetadata;
$classMetadata->addPropertyMetadata($propertyMetadata);
}

if ($this->reader->getPropertyAttribute($property, 'Prezent\\Doctrine\\Translatable\\Annotation\\FallbackLocale')) {
$classMetadata->fallbackLocale = $propertyMetadata;
$classMetadata->addPropertyMetadata($propertyMetadata);
}

if ($annot = $this->reader->getPropertyAttribute($property, 'Prezent\\Doctrine\\Translatable\\Annotation\\Translations')) {
$classMetadata->targetEntity = $annot->targetEntity ?? $targetEntity;
$classMetadata->translations = $propertyMetadata;
$classMetadata->addPropertyMetadata($propertyMetadata);
}
}

return $classMetadata;
}

/**
* Load metadata for a translation class
*
* @param \ReflectionClass $class
* @return TranslationMetadata
*/
private function loadTranslationMetadata(\ReflectionClass $class)
{
$classMetadata = new TranslationMetadata($class->name);

foreach ($class->getProperties() as $property) {
if ($property->class !== $class->name) {
continue;
}

$propertyMetadata = new PropertyMetadata($class->name, $property->getName());
$targetEntity = 'Translation' === substr($class->name, -11) ? substr($class->name, 0, -11) : null;

if ($annot = $this->reader->getPropertyAttribute($property, 'Prezent\\Doctrine\\Translatable\\Annotation\\Translatable')) {
$classMetadata->targetEntity = $annot->targetEntity ?? $targetEntity;
$classMetadata->referencedColumnName = $annot->referencedColumnName;
$classMetadata->translatable = $propertyMetadata;
$classMetadata->addPropertyMetadata($propertyMetadata);
}

if ($this->reader->getPropertyAttribute($property, 'Prezent\\Doctrine\\Translatable\\Annotation\\Locale')) {
$classMetadata->locale = $propertyMetadata;
$classMetadata->addPropertyMetadata($propertyMetadata);
}
}

return $classMetadata;
}
}
6 changes: 5 additions & 1 deletion src/Mapping/Driver/DoctrineAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
use Doctrine\ORM\Mapping\Driver\SimplifiedXmlDriver;
use Doctrine\ORM\Mapping\Driver\SimplifiedYamlDriver;
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\ORM\Mapping\Driver\AnnotationDriver as DoctrineAnnotationDriver;
use Doctrine\ORM\Mapping\Driver\AttributeDriver as DoctrineAttributeDriver;
use Doctrine\Persistence\Mapping\Driver\AnnotationDriver as DoctrineAnnotationDriver;
use Doctrine\Persistence\Mapping\Driver\FileDriver as DoctrineFileDriver;
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Persistence\Mapping\Driver\MappingDriverChain;
Expand Down Expand Up @@ -88,6 +89,9 @@ public static function fromMetadataDriver(MappingDriver $omDriver)
if ($omDriver instanceof DoctrineAnnotationDriver) {
return new AnnotationDriver($omDriver->getReader());
}
if ($omDriver instanceof DoctrineAttributeDriver) {
return new AttributeDriver($omDriver->getReader());
}

if ($omDriver instanceof DoctrineFileDriver) {
$reflClass = new \ReflectionClass($omDriver);
Expand Down