Skip to content

Commit

Permalink
[PHP 8.0] Add NestedAnnotationToAttributeRector (#2781)
Browse files Browse the repository at this point in the history
* [PHP 8.0] Add NestedAnnotationToAttributeRector

* remove unused class-string

* [PHP 8.0] Add NestedAnnotationToAttribute

* move JoinColumns to NestedAnnotationToAttributeRector

* [ci-review] Rector Rectify

Co-authored-by: GitHub Action <action@github.com>
  • Loading branch information
TomasVotruba and actions-user committed Aug 18, 2022
1 parent f41acb3 commit b8549f5
Show file tree
Hide file tree
Showing 23 changed files with 620 additions and 109 deletions.
1 change: 0 additions & 1 deletion packages-tests/PhpAttribute/UseAliasNameMatcherTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ public function test(

// uses
$useAliasMetadata = $this->useAliasNameMatcher->match($uses, $shortAnnotationName, $annotationToAttribute);

$this->assertInstanceOf(UseAliasMetadata::class, $useAliasMetadata);

// test new use import
Expand Down
4 changes: 2 additions & 2 deletions packages/PhpAttribute/NodeFactory/AttributeNameFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Use_;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
use Rector\Php80\ValueObject\AnnotationToAttribute;
use Rector\Php80\Contract\ValueObject\AnnotationToAttributeInterface;
use Rector\PhpAttribute\UseAliasNameMatcher;
use Rector\PhpAttribute\ValueObject\UseAliasMetadata;

Expand All @@ -23,7 +23,7 @@ public function __construct(
* @param Use_[] $uses
*/
public function create(
AnnotationToAttribute $annotationToAttribute,
AnnotationToAttributeInterface $annotationToAttribute,
DoctrineAnnotationTagValueNode $doctrineAnnotationTagValueNode,
array $uses
): FullyQualified|Name {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ public function createArgsFromItems(array $items, string $attributeClass): array
}

/**
* @todo deprecated
*
* @param mixed[] $items
* @return mixed[]
*/
Expand Down
141 changes: 141 additions & 0 deletions packages/PhpAttribute/NodeFactory/PhpNestedAttributeGroupFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?php

declare(strict_types=1);

namespace Rector\PhpAttribute\NodeFactory;

use Nette\Utils\Strings;
use PhpParser\Node\Arg;
use PhpParser\Node\Attribute;
use PhpParser\Node\AttributeGroup;
use PhpParser\Node\Expr;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Use_;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
use Rector\BetterPhpDocParser\ValueObject\PhpDoc\DoctrineAnnotation\CurlyListNode;
use Rector\Php80\ValueObject\NestedAnnotationToAttribute;
use Rector\PhpAttribute\AnnotationToAttributeMapper;
use Rector\PhpAttribute\AttributeArrayNameInliner;
use Rector\PhpAttribute\NodeAnalyzer\ExprParameterReflectionTypeCorrector;

final class PhpNestedAttributeGroupFactory
{
/**
* @var string
* @see https://regex101.com/r/g3d9jy/1
*/
private const SHORT_ORM_ALIAS_REGEX = '#^@ORM#';

public function __construct(
private readonly AnnotationToAttributeMapper $annotationToAttributeMapper,
private readonly AttributeNameFactory $attributeNameFactory,
private readonly NamedArgsFactory $namedArgsFactory,
private readonly ExprParameterReflectionTypeCorrector $exprParameterReflectionTypeCorrector,
private readonly AttributeArrayNameInliner $attributeArrayNameInliner
) {
}

/**
* @param Use_[] $uses
*/
public function create(
DoctrineAnnotationTagValueNode $doctrineAnnotationTagValueNode,
NestedAnnotationToAttribute $nestedAnnotationToAttribute,
array $uses
): AttributeGroup {
$values = $doctrineAnnotationTagValueNode->getValuesWithExplicitSilentAndWithoutQuotes();

$args = $this->createArgsFromItems($values, $nestedAnnotationToAttribute);
$args = $this->attributeArrayNameInliner->inlineArrayToArgs($args);

$attributeName = $this->attributeNameFactory->create(
$nestedAnnotationToAttribute,
$doctrineAnnotationTagValueNode,
$uses
);

$attribute = new Attribute($attributeName, $args);
return new AttributeGroup([$attribute]);
}

/**
* @return AttributeGroup[]
*/
public function createNested(
DoctrineAnnotationTagValueNode $doctrineAnnotationTagValueNode,
NestedAnnotationToAttribute $nestedAnnotationToAttribute,
): array {
$attributeGroups = [];

$values = $doctrineAnnotationTagValueNode->getValuesWithExplicitSilentAndWithoutQuotes();

foreach ($nestedAnnotationToAttribute->getAnnotationPropertiesToAttributeClasses() as $itemName => $nestedAttributeClass) {
$nestedValues = $values[$itemName] ?? null;
if ($nestedValues === null) {
continue;
}

if ($nestedValues instanceof CurlyListNode) {
foreach ($nestedValues->getValues() as $nestedDoctrineAnnotationTagValueNode) {
/** @var DoctrineAnnotationTagValueNode $nestedDoctrineAnnotationTagValueNode */
$args = $this->createArgsFromItems(
$nestedDoctrineAnnotationTagValueNode->getValuesWithExplicitSilentAndWithoutQuotes(),
$nestedAnnotationToAttribute
);

$args = $this->attributeArrayNameInliner->inlineArrayToArgs($args);

$originalIdentifier = $nestedDoctrineAnnotationTagValueNode->identifierTypeNode->name;

$attributeName = $this->resolveAliasedAttributeName($originalIdentifier, $nestedAttributeClass);

$attribute = new Attribute($attributeName, $args);
$attributeGroups[] = new AttributeGroup([$attribute]);
}
}
}

return $attributeGroups;
}

/**
* @param mixed[] $items
* @return Arg[]
*/
private function createArgsFromItems(array $items, NestedAnnotationToAttribute $nestedAnnotationToAttribute): array
{
// remove nested items
foreach (array_keys($nestedAnnotationToAttribute->getAnnotationPropertiesToAttributeClasses()) as $itemName) {
unset($items[$itemName]);
}

/** @var Expr[]|Expr\Array_ $items */
$items = $this->annotationToAttributeMapper->map($items);

$items = $this->exprParameterReflectionTypeCorrector->correctItemsByAttributeClass(
$items,
$nestedAnnotationToAttribute->getTag()
);

return $this->namedArgsFactory->createFromValues($items);
}

/**
* @todo improve this hardcoded approach later
*/
private function resolveAliasedAttributeName(
string $originalIdentifier,
string $nestedAttributeClass
): FullyQualified|Name {
$matches = Strings::match($originalIdentifier, self::SHORT_ORM_ALIAS_REGEX);

if ($matches !== null) {
// or alias
$shortDoctrineAttributeName = Strings::after($nestedAttributeClass, '\\', -1);
return new Name('ORM\\' . $shortDoctrineAttributeName);
}

return new FullyQualified($nestedAttributeClass);
}
}
63 changes: 0 additions & 63 deletions packages/PhpAttribute/RemovableAnnotationAnalyzer.php

This file was deleted.

4 changes: 2 additions & 2 deletions packages/PhpAttribute/UseAliasNameMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use PhpParser\Node\Stmt\Use_;
use PhpParser\Node\Stmt\UseUse;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Php80\ValueObject\AnnotationToAttribute;
use Rector\Php80\Contract\ValueObject\AnnotationToAttributeInterface;
use Rector\PhpAttribute\ValueObject\UseAliasMetadata;

/**
Expand All @@ -21,7 +21,7 @@ final class UseAliasNameMatcher
public function match(
array $uses,
string $shortAnnotationName,
AnnotationToAttribute $annotationToAttribute
AnnotationToAttributeInterface $annotationToAttribute
): ?UseAliasMetadata {
$shortAnnotationName = trim($shortAnnotationName, '@');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

namespace Rector\Tests\Php80\Rector\Class_\AnnotationToAttributeRector\Fixture\Doctrine;

use Doctrine\ORM\Mapping as ORM;
use Rector\Tests\Php80\Rector\Class_\AnnotationToAttributeRector\Source\GenericAnnotation;

final class TrailingComma
{
/**
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id", nullable=true, )
**/
* @GenericAnnotation(key="value", )
*/
protected $someColumn;
}

Expand All @@ -18,11 +18,11 @@ final class TrailingComma

namespace Rector\Tests\Php80\Rector\Class_\AnnotationToAttributeRector\Fixture\Doctrine;

use Doctrine\ORM\Mapping as ORM;
use Rector\Tests\Php80\Rector\Class_\AnnotationToAttributeRector\Source\GenericAnnotation;

final class TrailingComma
{
#[ORM\JoinColumn(name: 'parent_id', referencedColumnName: 'id', nullable: true)]
#[GenericAnnotation(key: 'value')]
protected $someColumn;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@
new AnnotationToAttribute('Doctrine\ORM\Mapping\Table'),
new AnnotationToAttribute('Doctrine\ORM\Mapping\Index'),
new AnnotationToAttribute('Doctrine\ORM\Mapping\UniqueConstraint'),
new AnnotationToAttribute('Doctrine\ORM\Mapping\JoinColumns'),
new AnnotationToAttribute('Doctrine\ORM\Mapping\JoinColumn'),
new AnnotationToAttribute('Doctrine\ORM\Mapping\DiscriminatorMap'),

// validation
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Rector\Tests\Php80\Rector\Class_\AnnotationToAttributeRector\Fixture\Doctrine;
namespace Rector\Tests\Php80\Rector\Property\NestedAnnotationToAttributeRector\Fixture;

use Doctrine\ORM\Mapping as ORM;

Expand All @@ -19,7 +19,7 @@ final class DoctrineNestedJoinColumns
-----
<?php

namespace Rector\Tests\Php80\Rector\Class_\AnnotationToAttributeRector\Fixture\Doctrine;
namespace Rector\Tests\Php80\Rector\Property\NestedAnnotationToAttributeRector\Fixture;

use Doctrine\ORM\Mapping as ORM;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Rector\Tests\Php80\Rector\Property\NestedAnnotationToAttributeRector\Fixture;

use Doctrine\ORM\Mapping as ORM;

final class MultipleInversedJoinColumns
{
/**
* @ORM\JoinTable(name="join_table_name",
* inverseJoinColumns={
* @ORM\JoinColumn(name="target_id"),
* @ORM\JoinColumn(name="another_id")
* }
* )
*/
private $collection;
}

?>
-----
<?php

namespace Rector\Tests\Php80\Rector\Property\NestedAnnotationToAttributeRector\Fixture;

use Doctrine\ORM\Mapping as ORM;

final class MultipleInversedJoinColumns
{
#[ORM\JoinTable(name: 'join_table_name')]
#[ORM\InverseJoinColumn(name: 'target_id')]
#[ORM\InverseJoinColumn(name: 'another_id')]
private $collection;
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Rector\Tests\Php80\Rector\Property\NestedAnnotationToAttributeRector\Fixture;

use Doctrine\ORM\Mapping as ORM;

final class SomeEntity
{
/**
* @ORM\JoinTable(name="join_table_name",
* joinColumns={@ORM\JoinColumn(name="origin_id")},
* inverseJoinColumns={@ORM\JoinColumn(name="target_id")}
* )
*/
private $collection;
}

?>
-----
<?php

namespace Rector\Tests\Php80\Rector\Property\NestedAnnotationToAttributeRector\Fixture;

use Doctrine\ORM\Mapping as ORM;

final class SomeEntity
{
#[ORM\JoinTable(name: 'join_table_name')]
#[ORM\JoinColumn(name: 'origin_id')]
#[ORM\InverseJoinColumn(name: 'target_id')]
private $collection;
}

?>

0 comments on commit b8549f5

Please sign in to comment.