Skip to content

Commit

Permalink
[PHP 8.0] Add NestedAnnotationToAttribute
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Aug 18, 2022
1 parent 7e866bb commit 9213cb9
Show file tree
Hide file tree
Showing 15 changed files with 421 additions and 40 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
127 changes: 127 additions & 0 deletions packages/PhpAttribute/NodeFactory/PhpNestedAttributeGroupFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<?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
{
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]);
}

/**
* @param Use_[] $uses
* @return AttributeGroup[]
*/
public function createNested(
DoctrineAnnotationTagValueNode $doctrineAnnotationTagValueNode,
NestedAnnotationToAttribute $nestedAnnotationToAttribute,
array $uses
): 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;

// @todo improve this hardcoded approach later
if (Strings::match($originalIdentifier, '#^@ORM#')) {
// or alias
$shortDoctrineAttributeName = Strings::after($nestedAttributeClass, '\\', -1);
$attributeName = new Name('ORM\\' . $shortDoctrineAttributeName);
} else {
// @todo improve aliasing
$attributeName = new FullyQualified($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);
}
}
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
@@ -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
Expand Up @@ -4,13 +4,12 @@ namespace Rector\Tests\Php80\Rector\Property\NestedAnnotationToAttributeRector\F

use Doctrine\ORM\Mapping as ORM;

class SomeEntity
final class SomeEntity
{
/**
* @ORM\ManyToMany(targetEntity="App\Entity\Example", inversedBy="backLink")
* @ORM\JoinTable(name="join_table_name",
* joinColumns={@ORM\JoinColumn(name="origin_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="target_id", referencedColumnName="id")}
* joinColumns={@ORM\JoinColumn(name="origin_id")},
* inverseJoinColumns={@ORM\JoinColumn(name="target_id")}
* )
*/
private $collection;
Expand All @@ -24,12 +23,11 @@ namespace Rector\Tests\Php80\Rector\Property\NestedAnnotationToAttributeRector\F

use Doctrine\ORM\Mapping as ORM;

class SomeEntity
final class SomeEntity
{
#[ORM\ManyToMany(targetEntity: 'App\Entity\Example', inversedBy: 'backLink')]
#[ORM\JoinTable(name: 'join_table_name')]
#[ORM\JoinColumn(name: 'origin_id', referencedColumnName: 'id')]
#[ORM\InverseJoinColumn(name: 'target_id', referencedColumnName: 'id')]
#[ORM\JoinColumn(name: 'origin_id')]
#[ORM\InverseJoinColumn(name: 'target_id')]
private $collection;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,24 @@

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

use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;

final class NestedAnnotationToAttributeRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(\Symplify\SmartFileSystem\SmartFileInfo $fileInfo): void
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}

/**
* @return \Iterator<\Symplify\SmartFileSystem\SmartFileInfo>
* @return Iterator<SmartFileInfo>
*/
public function provideData(): \Iterator
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Php80\Rector\Property\NestedAnnotationToAttributeRector;
use Rector\Php80\ValueObject\NestedAnnotationToAttribute;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->ruleWithConfiguration(
\Rector\Php80\Rector\Property\NestedAnnotationToAttributeRector::class,
[
'old_value' => 'newValue',
]
);
$rectorConfig->ruleWithConfiguration(NestedAnnotationToAttributeRector::class, [
new NestedAnnotationToAttribute('Doctrine\ORM\Mapping\JoinTable', [
'joinColumns' => 'Doctrine\ORM\Mapping\JoinColumn',
'inverseJoinColumns' => 'Doctrine\ORM\Mapping\InverseJoinColumn',
]),
]);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Rector\Php80\Contract\ValueObject;

interface AnnotationToAttributeInterface
{
public function getTag(): string;

public function getAttributeClass(): string;
}
49 changes: 49 additions & 0 deletions rules/Php80/NodeFactory/NestedAttrGroupsFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace Rector\Php80\NodeFactory;

use PhpParser\Node\AttributeGroup;
use PhpParser\Node\Stmt\Use_;
use Rector\Php80\ValueObject\NestedDoctrineTagAndAnnotationToAttribute;
use Rector\PhpAttribute\NodeFactory\PhpNestedAttributeGroupFactory;

final class NestedAttrGroupsFactory
{
public function __construct(
private readonly PhpNestedAttributeGroupFactory $phpNestedAttributeGroupFactory
) {
}

/**
* @param NestedDoctrineTagAndAnnotationToAttribute[] $nestedDoctrineTagAndAnnotationToAttributes
* @param Use_[] $uses
* @return AttributeGroup[]
*/
public function create(array $nestedDoctrineTagAndAnnotationToAttributes, array $uses): array
{
$attributeGroups = [];

foreach ($nestedDoctrineTagAndAnnotationToAttributes as $nestedDoctrineTagAndAnnotationToAttribute) {
$doctrineAnnotationTagValueNode = $nestedDoctrineTagAndAnnotationToAttribute->getDoctrineAnnotationTagValueNode();

// add attributes
$attributeGroups[] = $this->phpNestedAttributeGroupFactory->create(
$doctrineAnnotationTagValueNode,
$nestedDoctrineTagAndAnnotationToAttribute->getNestedAnnotationToAttribute(),
$uses
);

$nestedAttributeGroups = $this->phpNestedAttributeGroupFactory->createNested(
$doctrineAnnotationTagValueNode,
$nestedDoctrineTagAndAnnotationToAttribute->getNestedAnnotationToAttribute(),
$uses
);

$attributeGroups = array_merge($attributeGroups, $nestedAttributeGroups);
}

return $attributeGroups;
}
}

0 comments on commit 9213cb9

Please sign in to comment.