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

Allow using PHP attributes for configuration #40

Merged
merged 4 commits into from
Mar 28, 2024
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/lock-symfony-version.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/bin/sh

sed --in-place --regexp-extended --expression='/symfony\/error-handler/b; /symfony\/phpunit-bridge/b; s/"(symfony\/.*)": ".*"/"\1": "'$VERSION'"/' composer.json
sed --in-place --regexp-extended --expression='/symfony\/deprecation-contracts/b; /symfony\/error-handler/b; /symfony\/phpunit-bridge/b; s/"(symfony\/.*)": ".*"/"\1": "'$VERSION'"/' composer.json
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

To get the diff for a specific change, go to https://github.com/webfactory/polyglot-bundle/commit/XXX where XXX is the change hash. To get the diff between two versions, go to https://github.com/webfactory/polyglot-bundle/compare/{oldversion}...{newversion}.

## Version 3.1.0

* The annotations `\Webfactory\Bundle\PolyglotBundle\Annotation\Locale`, `\Webfactory\Bundle\PolyglotBundle\Annotation\Translatable` and `\Webfactory\Bundle\PolyglotBundle\Annotation\TranslationCollection` have been deprecated. Replace them with the corresponding PHP attributes from the `\Webfactory\Bundle\PolyglotBundle\Attribute` namespace.
* Using annotations to configure entity classes for this bundle has been deprecated. Switch to PHP 8 attributes.
* Attribute classes will be made `final` in the next major release.

## Version 3.0.0

* Dropped support for PHP versions below 8.1, and for Symfony versions before 5.4.
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@
"php": "8.1.*|8.2.*|8.3.*",
"doctrine/annotations": "^1.12",
"doctrine/collections": "^1.0",
"doctrine/event-manager": "^1.0",
"doctrine/dbal": "^2.3|^3.0",
"doctrine/event-manager": "^1.0",
"doctrine/orm": "^2.10",
"doctrine/persistence": "^1.3.8 | ^2.1",
"psr/log": "^1.0",
"symfony/config": "^5.4|^6.4|^7.0",
"symfony/dependency-injection": "^5.4|^6.4|^7.0",
"symfony/deprecation-contracts": "^2.0|^3.0",
"symfony/event-dispatcher": "^5.4|^6.4|^7.0",
"symfony/http-kernel": "^5.4|^6.4|^7.0"
},
Expand Down
13 changes: 4 additions & 9 deletions src/Annotation/Locale.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,18 @@
namespace Webfactory\Bundle\PolyglotBundle\Annotation;

use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Webfactory\Bundle\PolyglotBundle\Attribute\Locale as Attribute;

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

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

public function getPrimary(): ?string
{
return $this->primary;
trigger_deprecation('webfactory/polyglot-bundle', '3.1.0', 'The %s annotation has been deprecated and will be removed in the 4.0 release. Use the %s attribute instead.', self::class, parent::class);
parent::__construct($primary);
}
}
13 changes: 4 additions & 9 deletions src/Annotation/Translatable.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,17 @@
namespace Webfactory\Bundle\PolyglotBundle\Annotation;

use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Webfactory\Bundle\PolyglotBundle\Attribute\Translatable as Attribute;

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

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

public function getTranslationFieldname(): ?string
{
return $this->translationFieldname;
trigger_deprecation('webfactory/polyglot-bundle', '3.1.0', 'The %s annotation has been deprecated and will be removed in the 4.0 release. Use the %s attribute instead.', self::class, parent::class);
parent::__construct($translationFieldname);
}
}
8 changes: 7 additions & 1 deletion src/Annotation/TranslationCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,15 @@

namespace Webfactory\Bundle\PolyglotBundle\Annotation;

use Webfactory\Bundle\PolyglotBundle\Attribute\TranslationCollection as Attribute;

/**
* @Annotation
*/
final class TranslationCollection
final class TranslationCollection extends Attribute
{
public function __construct()
{
trigger_deprecation('webfactory/polyglot-bundle', '3.1.0', 'The %s annotation has been deprecated and will be removed in the 4.0 release. Use the %s attribute instead.', self::class, parent::class);
}
}
29 changes: 29 additions & 0 deletions src/Attribute/Locale.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

/*
* (c) webfactory GmbH <info@webfactory.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Webfactory\Bundle\PolyglotBundle\Attribute;

use Attribute;

/** @final */
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_PROPERTY)]
class Locale
{
private ?string $primary;

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

public function getPrimary(): ?string
{
return $this->primary;
}
}
29 changes: 29 additions & 0 deletions src/Attribute/Translatable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

/*
* (c) webfactory GmbH <info@webfactory.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Webfactory\Bundle\PolyglotBundle\Attribute;

use Attribute;

/** @final */
#[Attribute]
class Translatable
{
private ?string $translationFieldname;

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

public function getTranslationFieldname(): ?string
{
return $this->translationFieldname;
}
}
18 changes: 18 additions & 0 deletions src/Attribute/TranslationCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

/*
* (c) webfactory GmbH <info@webfactory.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Webfactory\Bundle\PolyglotBundle\Attribute;

use Attribute;

/** @final */
#[Attribute]
class TranslationCollection
{
}
60 changes: 42 additions & 18 deletions src/Doctrine/TranslatableClassMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use ReflectionProperty;
use RuntimeException;
use Webfactory\Bundle\PolyglotBundle\Annotation;
use Webfactory\Bundle\PolyglotBundle\Attribute;
use Webfactory\Bundle\PolyglotBundle\Locale\DefaultLocaleProvider;
use Webfactory\Bundle\PolyglotBundle\Translatable;

Expand Down Expand Up @@ -193,15 +194,22 @@ private function findTranslatedProperties(ClassMetadataInfo $cm, Reader $reader,
continue;
}

$foundAttributeOrAnnotation = null;
$reflectionProperty = $cm->getReflectionClass()->getProperty($fieldName);
$attributes = $reflectionProperty->getAttributes(Attribute\Translatable::class);

$annotation = $reader->getPropertyAnnotation(
$reflectionProperty,
Annotation\Translatable::class
);
if ($attributes) {
$foundAttributeOrAnnotation = $attributes[0]->newInstance();
} else {
$foundAttributeOrAnnotation = $reader->getPropertyAnnotation($reflectionProperty, Annotation\Translatable::class);

if ($foundAttributeOrAnnotation) {
trigger_deprecation('webfactory/polyglot-bundle', '3.1.0', 'Using the %s annotation on the %s::%s property is deprecated. Use the %s attribute instead.', Annotation\Translatable::class, $reflectionProperty->class, $reflectionProperty->name, Attribute\Translatable::class);
}
}

if ($annotation) {
$translationFieldname = $annotation->getTranslationFieldname() ?: $fieldName;
if ($foundAttributeOrAnnotation) {
$translationFieldname = $foundAttributeOrAnnotation->getTranslationFieldname() ?: $fieldName;
$translationFieldReflectionProperty = $translationClassMetadata->getReflectionProperty($translationFieldname);

$this->translatedProperties[$fieldName] = $reflectionProperty;
Expand All @@ -212,19 +220,24 @@ private function findTranslatedProperties(ClassMetadataInfo $cm, Reader $reader,

private function findTranslationsCollection(ClassMetadataInfo $cm, Reader $reader, ClassMetadataFactory $classMetadataFactory): void
{
$found = false;
foreach ($cm->associationMappings as $fieldName => $mapping) {
if (isset($mapping['declared'])) {
// The association is inherited from a parent class
continue;
}

$annotation = $reader->getPropertyAnnotation(
$cm->getReflectionProperty($fieldName),
Annotation\TranslationCollection::class
);
$reflectionProperty = $cm->getReflectionProperty($fieldName);

if ($annotation) {
$this->translationsCollectionProperty = $cm->getReflectionClass()->getProperty($fieldName);
if ($reflectionProperty->getAttributes(Attribute\TranslationCollection::class)) {
$found = true;
} elseif ($reader->getPropertyAnnotation($reflectionProperty, Annotation\TranslationCollection::class)) {
trigger_deprecation('webfactory/polyglot-bundle', '3.1.0', 'Using the %s annotation on the %s::%s property is deprecated. Use the %s attribute instead.', Annotation\TranslationCollection::class, $reflectionProperty->class, $reflectionProperty->name, Attribute\TranslationCollection::class);
$found = true;
}

if ($found) {
$this->translationsCollectionProperty = $reflectionProperty;

$translationEntityMetadata = $classMetadataFactory->getMetadataFor($mapping['targetEntity']);
$this->translationClass = $translationEntityMetadata->getReflectionClass();
Expand All @@ -239,8 +252,17 @@ private function findTranslationsCollection(ClassMetadataInfo $cm, Reader $reade
private function findPrimaryLocale(ClassMetadataInfo $cm, Reader $reader): void
{
foreach (array_merge([$cm->name], $cm->parentClasses) as $class) {
$annotation = $reader->getClassAnnotation(new ReflectionClass($class), Annotation\Locale::class);
$reflectionClass = new ReflectionClass($class);

foreach ($reflectionClass->getAttributes(Attribute\Locale::class) as $attribute) {
$this->primaryLocale = $attribute->newInstance()->getPrimary();

return;
}

$annotation = $reader->getClassAnnotation($reflectionClass, Annotation\Locale::class);
if (null !== $annotation) {
trigger_deprecation('webfactory/polyglot-bundle', '3.1.0', 'Using the %s annotation on the %s class is deprecated. Use the %s attribute instead.', Annotation\Locale::class, $reflectionClass->name, Attribute\Locale::class);
$this->primaryLocale = $annotation->getPrimary();

return;
Expand All @@ -253,13 +275,15 @@ private function parseTranslationsEntity(Reader $reader, ClassMetadataInfo $cm):
foreach ($cm->fieldMappings as $fieldName => $mapping) {
$reflectionProperty = $cm->getReflectionProperty($fieldName);

$annotation = $reader->getPropertyAnnotation(
$reflectionProperty,
Annotation\Locale::class
);
if ($reflectionProperty->getAttributes(Attribute\Locale::class)) {
$this->translationLocaleProperty = $reflectionProperty;

return;
}

if ($annotation) {
if ($reader->getPropertyAnnotation($reflectionProperty, Annotation\Locale::class)) {
$this->translationLocaleProperty = $reflectionProperty;
trigger_deprecation('webfactory/polyglot-bundle', '3.1.0', 'Using the %s annotation on the %s::%s property is deprecated. Use the %s attribute instead.', Annotation\Locale::class, $reflectionProperty->class, $reflectionProperty->name, Attribute\Locale::class);

return;
}
Expand Down
3 changes: 1 addition & 2 deletions src/TranslatableChain.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ public static function firstTranslation(TranslatableInterface ...$translatables)
private function __construct(
private readonly Closure $comparator,
TranslatableInterface ...$translatables,
)
{
) {
$this->translatables = $translatables;
}

Expand Down
14 changes: 5 additions & 9 deletions tests/Functional/CascadePersistTranslationsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Webfactory\Bundle\PolyglotBundle\Annotation as Polyglot;
use Webfactory\Bundle\PolyglotBundle\Attribute as Polyglot;
use Webfactory\Bundle\PolyglotBundle\Translatable;
use Webfactory\Bundle\PolyglotBundle\TranslatableInterface;

Expand Down Expand Up @@ -46,9 +46,8 @@ public function adding_and_persisting_translations(): void

/**
* @ORM\Entity
*
* @Polyglot\Locale(primary="en_GB")
*/
#[Polyglot\Locale(primary: 'en_GB')]
class CascadePersistTranslationsTest_Entity
{
/**
Expand All @@ -64,16 +63,14 @@ class CascadePersistTranslationsTest_Entity
* (!) There is *not* cascade="persist" configuration here.
*
* @ORM\OneToMany(targetEntity="CascadePersistTranslationsTest_Translation", mappedBy="entity")
*
* @Polyglot\TranslationCollection
*/
#[Polyglot\TranslationCollection]
protected Collection $translations;

/**
* @ORM\Column(type="string")
*
* @Polyglot\Translatable
*/
#[Polyglot\Translatable]
protected string|TranslatableInterface $text;

public function __construct()
Expand Down Expand Up @@ -104,9 +101,8 @@ class CascadePersistTranslationsTest_Translation

/**
* @ORM\Column
*
* @Polyglot\Locale
*/
#[Polyglot\Locale]
private string $locale;

/**
Expand Down
Loading
Loading