From 6aca7ff1c712bd727930e4f2c2ec720a45654307 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Thu, 24 Sep 2020 16:46:48 +0200 Subject: [PATCH 1/5] monorepob-builder: add v prefix --- monorepo-builder.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/monorepo-builder.php b/monorepo-builder.php index 93b75a75992f..aa0b5932720f 100644 --- a/monorepo-builder.php +++ b/monorepo-builder.php @@ -8,6 +8,9 @@ use Symplify\MonorepoBuilder\ValueObject\Option; return static function (ContainerConfigurator $containerConfigurator): void { + $parameters = $containerConfigurator->parameters(); + $parameters->set(Option::PACKAGE_ALIAS_FORMAT, 'v..x-dev'); + $services = $containerConfigurator->services(); // release workers - in order to execute From b574711b4a2b5b5ff2a7193a4a5b0a5132a5cbf2 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Thu, 24 Sep 2020 16:59:50 +0200 Subject: [PATCH 2/5] monorepob-builder: add v prefix --- monorepo-builder.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/monorepo-builder.php b/monorepo-builder.php index aa0b5932720f..93b75a75992f 100644 --- a/monorepo-builder.php +++ b/monorepo-builder.php @@ -8,9 +8,6 @@ use Symplify\MonorepoBuilder\ValueObject\Option; return static function (ContainerConfigurator $containerConfigurator): void { - $parameters = $containerConfigurator->parameters(); - $parameters->set(Option::PACKAGE_ALIAS_FORMAT, 'v..x-dev'); - $services = $containerConfigurator->services(); // release workers - in order to execute From 3743193559f83aeebfc3c921423615968dab1a25 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Thu, 24 Sep 2020 21:37:53 +0200 Subject: [PATCH 3/5] [PHP 8.0] Add Annotation to Attribute rule based on php-parser --- .../src/PhpDocNode/AbstractTagValueNode.php | 31 ++--- .../Doctrine/Class_/EntityTagValueNode.php | 28 +---- .../Doctrine/Property_/ColumnTagValueNode.php | 27 +---- .../Property_/GeneratedValueTagValueNode.php | 14 +-- .../Doctrine/Property_/IdTagValueNode.php | 10 +- .../Property_/JoinColumnTagValueNode.php | 25 +--- .../Property_/JoinTableTagValueNode.php | 54 ++++++--- .../Property_/ManyToManyTagValueNode.php | 15 +-- .../Constraints/AssertEmailTagValueNode.php | 14 +-- .../Constraints/AssertRangeTagValueNode.php | 10 +- .../src/AnnotationToAttributeConverter.php | 27 ++--- .../Collector/PlaceholderToValueCollector.php | 27 ----- .../ManyPhpAttributableTagNodeInterface.php | 13 ++ .../PhpAttributableTagNodeInterface.php | 7 +- .../PhpAttributePhpDocNodePrintTrait.php | 73 ------------ ...ContentPhpAttributePlaceholderReplacer.php | 60 ---------- .../src/Printer/PhpAttributteGroupFactory.php | 111 ++++++++++++++++++ .../src/Printer/PlaceholderNodeFactory.php | 67 ----------- .../Fixture/RFC/assert_range.php.inc | 2 +- .../entity_column_and_assert_email.php.inc | 4 +- .../RFC/id_column_generated_value.php.inc | 6 +- .../Fixture/RFC/join_table.php.inc | 34 ++++++ .../Fixture/RFC/just_id.php.inc | 29 +++++ .../Fixture/RFC/many_to_many.php.inc | 9 +- .../Fixture/entity_with_repository.php.inc | 3 +- .../Fixture/fixture.php.inc | 3 +- .../Printer/BetterStandardPrinter.php | 22 +--- 27 files changed, 304 insertions(+), 421 deletions(-) delete mode 100644 packages/php-attribute/src/Collector/PlaceholderToValueCollector.php create mode 100644 packages/php-attribute/src/Contract/ManyPhpAttributableTagNodeInterface.php delete mode 100644 packages/php-attribute/src/PhpDocNode/PhpAttributePhpDocNodePrintTrait.php delete mode 100644 packages/php-attribute/src/Printer/ContentPhpAttributePlaceholderReplacer.php create mode 100644 packages/php-attribute/src/Printer/PhpAttributteGroupFactory.php delete mode 100644 packages/php-attribute/src/Printer/PlaceholderNodeFactory.php create mode 100644 rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/join_table.php.inc create mode 100644 rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/just_id.php.inc diff --git a/packages/better-php-doc-parser/src/PhpDocNode/AbstractTagValueNode.php b/packages/better-php-doc-parser/src/PhpDocNode/AbstractTagValueNode.php index ab034a1551b6..cf9823b2aa09 100644 --- a/packages/better-php-doc-parser/src/PhpDocNode/AbstractTagValueNode.php +++ b/packages/better-php-doc-parser/src/PhpDocNode/AbstractTagValueNode.php @@ -64,6 +64,22 @@ public function changeItem(string $key, $value): void $this->items[$key] = $value; } + /** + * @param mixed[] $contentItems + * @return mixed[] + */ + public function filterOutMissingItems(array $contentItems): array + { + if ($this->tagValueNodeConfiguration->getOrderedVisibleItems() === null) { + return $contentItems; + } + + return ArrayItemStaticHelper::filterAndSortVisibleItems( + $contentItems, + $this->tagValueNodeConfiguration->getOrderedVisibleItems() + ); + } + protected function printItems(array $items): string { $items = $this->completeItemsQuotes($items); @@ -155,21 +171,6 @@ protected function resolveOriginalContentSpacingAndOrder(?string $originalConten ); } - /** - * @return mixed[]|string[] - */ - protected function filterOutMissingItems(array $contentItems): array - { - if ($this->tagValueNodeConfiguration->getOrderedVisibleItems() === null) { - return $contentItems; - } - - return ArrayItemStaticHelper::filterAndSortVisibleItems( - $contentItems, - $this->tagValueNodeConfiguration->getOrderedVisibleItems() - ); - } - private function shouldPrintEmptyBrackets(): bool { // @todo decouple diff --git a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Class_/EntityTagValueNode.php b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Class_/EntityTagValueNode.php index 7ea765aa2ada..8869edd3ded4 100644 --- a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Class_/EntityTagValueNode.php +++ b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Class_/EntityTagValueNode.php @@ -6,22 +6,14 @@ use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\AbstractDoctrineTagValueNode; use Rector\PhpAttribute\Contract\PhpAttributableTagNodeInterface; -use Rector\PhpAttribute\PhpDocNode\PhpAttributePhpDocNodePrintTrait; final class EntityTagValueNode extends AbstractDoctrineTagValueNode implements PhpAttributableTagNodeInterface { - use PhpAttributePhpDocNodePrintTrait; - /** * @var string */ private const REPOSITORY_CLASS = 'repositoryClass'; - /** - * @var string - */ - private const READ_ONLY = 'readOnly'; - public function removeRepositoryClass(): void { $this->items[self::REPOSITORY_CLASS] = null; @@ -32,27 +24,11 @@ public function getShortName(): string return '@ORM\Entity'; } - public function toAttributeString(): string - { - $items = $this->createAttributeItems(); - return $this->printItemsToAttributeString($items); - } - /** * @return mixed[] */ - private function createAttributeItems(): array + public function getAttributableItems(): array { - $items = $this->items; - - if ($items[self::REPOSITORY_CLASS] !== null) { - $items[self::REPOSITORY_CLASS] .= '::class'; - } - - if ($items[self::READ_ONLY] !== null) { - $items[self::READ_ONLY] = $items[self::READ_ONLY] ? 'ORM\Entity::READ_ONLY' : ''; - } - - return $items; + return $this->filterOutMissingItems($this->items); } } diff --git a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/ColumnTagValueNode.php b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/ColumnTagValueNode.php index 59723a83cb15..48b1d124d150 100644 --- a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/ColumnTagValueNode.php +++ b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/ColumnTagValueNode.php @@ -6,12 +6,9 @@ use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\AbstractDoctrineTagValueNode; use Rector\PhpAttribute\Contract\PhpAttributableTagNodeInterface; -use Rector\PhpAttribute\PhpDocNode\PhpAttributePhpDocNodePrintTrait; final class ColumnTagValueNode extends AbstractDoctrineTagValueNode implements PhpAttributableTagNodeInterface { - use PhpAttributePhpDocNodePrintTrait; - public function changeType(string $type): void { $this->items['type'] = $type; @@ -40,31 +37,11 @@ public function getOptions(): array return $this->items['options'] ?? []; } - public function toAttributeString(): string - { - $items = $this->createAttributeItems(); - return $this->printItemsToAttributeString($items); - } - /** * @return mixed[] */ - private function createAttributeItems(): array + public function getAttributableItems(): array { - $items = $this->items; - - foreach ($items as $key => $value) { - if ($key !== 'unique') { - continue; - } - - if ($value !== true) { - continue; - } - - $items[$key] = 'ORM\Column::UNIQUE'; - } - - return $items; + return $this->filterOutMissingItems($this->items); } } diff --git a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/GeneratedValueTagValueNode.php b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/GeneratedValueTagValueNode.php index 61c213e7a205..6a14f4a4e9f9 100644 --- a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/GeneratedValueTagValueNode.php +++ b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/GeneratedValueTagValueNode.php @@ -7,27 +7,27 @@ use Rector\BetterPhpDocParser\Contract\PhpDocNode\SilentKeyNodeInterface; use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\AbstractDoctrineTagValueNode; use Rector\PhpAttribute\Contract\PhpAttributableTagNodeInterface; -use Rector\PhpAttribute\PhpDocNode\PhpAttributePhpDocNodePrintTrait; /** * @see \Rector\BetterPhpDocParser\Tests\PhpDocParser\TagValueNodeReprint\TagValueNodeReprintTest */ final class GeneratedValueTagValueNode extends AbstractDoctrineTagValueNode implements PhpAttributableTagNodeInterface, SilentKeyNodeInterface { - use PhpAttributePhpDocNodePrintTrait; - public function getShortName(): string { return '@ORM\GeneratedValue'; } - public function toAttributeString(): string + public function getSilentKey(): string { - return $this->printItemsToAttributeString($this->items); + return 'strategy'; } - public function getSilentKey(): string + /** + * @return mixed[] + */ + public function getAttributableItems(): array { - return 'strategy'; + return $this->filterOutMissingItems($this->items); } } diff --git a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/IdTagValueNode.php b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/IdTagValueNode.php index ea83e6999412..4d9644430d9c 100644 --- a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/IdTagValueNode.php +++ b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/IdTagValueNode.php @@ -6,19 +6,19 @@ use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\AbstractDoctrineTagValueNode; use Rector\PhpAttribute\Contract\PhpAttributableTagNodeInterface; -use Rector\PhpAttribute\PhpDocNode\PhpAttributePhpDocNodePrintTrait; final class IdTagValueNode extends AbstractDoctrineTagValueNode implements PhpAttributableTagNodeInterface { - use PhpAttributePhpDocNodePrintTrait; - public function getShortName(): string { return '@ORM\Id'; } - public function toAttributeString(): string + /** + * @return mixed[] + */ + public function getAttributableItems(): array { - return $this->printItemsToAttributeString($this->items); + return $this->filterOutMissingItems($this->items); } } diff --git a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/JoinColumnTagValueNode.php b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/JoinColumnTagValueNode.php index 5a891367ba8f..3c1476446e20 100644 --- a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/JoinColumnTagValueNode.php +++ b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/JoinColumnTagValueNode.php @@ -7,12 +7,9 @@ use Rector\BetterPhpDocParser\Contract\PhpDocNode\TagAwareNodeInterface; use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\AbstractDoctrineTagValueNode; use Rector\PhpAttribute\Contract\PhpAttributableTagNodeInterface; -use Rector\PhpAttribute\PhpDocNode\PhpAttributePhpDocNodePrintTrait; final class JoinColumnTagValueNode extends AbstractDoctrineTagValueNode implements TagAwareNodeInterface, PhpAttributableTagNodeInterface { - use PhpAttributePhpDocNodePrintTrait; - /** * @var string */ @@ -55,29 +52,11 @@ public function changeShortName(string $shortName): void $this->shortName = $shortName; } - public function toAttributeString(): string - { - return $this->printItemsToAttributeString($this->createAttributeItems()); - } - /** * @return mixed[] */ - private function createAttributeItems(): array + public function getAttributableItems(): array { - $items = $this->items; - - // specific for attributes - foreach ($items as $key => $value) { - if ($key !== 'unique') { - continue; - } - if ($value !== true) { - continue; - } - $items[$key] = 'ORM\JoinColumn::UNIQUE'; - } - - return $items; + return $this->filterOutMissingItems($this->items); } } diff --git a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/JoinTableTagValueNode.php b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/JoinTableTagValueNode.php index f9b5c1d2a59b..d2513f2cfe59 100644 --- a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/JoinTableTagValueNode.php +++ b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/JoinTableTagValueNode.php @@ -6,13 +6,11 @@ use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\AbstractDoctrineTagValueNode; use Rector\BetterPhpDocParser\ValueObject\OpeningAndClosingSpace; +use Rector\PhpAttribute\Contract\ManyPhpAttributableTagNodeInterface; use Rector\PhpAttribute\Contract\PhpAttributableTagNodeInterface; -use Rector\PhpAttribute\PhpDocNode\PhpAttributePhpDocNodePrintTrait; -final class JoinTableTagValueNode extends AbstractDoctrineTagValueNode implements PhpAttributableTagNodeInterface +final class JoinTableTagValueNode extends AbstractDoctrineTagValueNode implements PhpAttributableTagNodeInterface, ManyPhpAttributableTagNodeInterface { - use PhpAttributePhpDocNodePrintTrait; - /** * @var string */ @@ -88,25 +86,38 @@ public function getShortName(): string return '@ORM\JoinTable'; } - public function toAttributeString(): string + /** + * @return mixed[] + */ + public function getAttributableItems(): array { - $items = $this->createItems(); - unset($items[self::JOIN_COLUMNS], $items[self::INVERSE_JOIN_COLUMNS]); + $items = []; + + $items['name'] = $this->name; - $content = $this->printPhpAttributeItems($items); + if ($this->schema !== null) { + $items['schema'] = $this->schema; + } - $joinTableAttributeContent = $this->printPhpAttributeContent($content); + return $items; + } + + /** + * @return array + */ + public function provide(): array + { + $items = []; foreach ($this->joinColumns as $joinColumn) { - $joinTableAttributeContent .= PHP_EOL . $joinColumn->toAttributeString(); + $items[$joinColumn->getShortName()] = $joinColumn->getAttributableItems(); } - foreach ($this->inverseJoinColumns as $inverseJoinColumnAttributeContent) { - $inverseJoinColumnAttributeContent->changeShortName('ORM\InverseJoinColumn'); - $joinTableAttributeContent .= PHP_EOL . $inverseJoinColumnAttributeContent->toAttributeString(); + foreach ($this->inverseJoinColumns as $inverseJoinColumn) { + $items['@ORM\InverseJoinColumn'] = $inverseJoinColumn->getAttributableItems(); } - return $joinTableAttributeContent; + return $items; } /** @@ -122,8 +133,19 @@ private function createItems(): array $items['schema'] = sprintf('"%s"', $this->schema); } + $joinColumnItems = $this->createJoinColumnItems(self::JOIN_COLUMNS, self::INVERSE_JOIN_COLUMNS); + return array_merge($items, $joinColumnItems); + } + + /** + * @return array + */ + private function createJoinColumnItems(string $joinColumnsKey, string $inverseJoinColumnsKey): array + { + $items = []; + if ($this->joinColumns !== []) { - $items[self::JOIN_COLUMNS] = $this->printNestedTag( + $items[$joinColumnsKey] = $this->printNestedTag( $this->joinColumns, false, $this->joinColumnsOpeningAndClosingSpace->getOpeningSpace(), @@ -132,7 +154,7 @@ private function createItems(): array } if ($this->inverseJoinColumns !== []) { - $items[self::INVERSE_JOIN_COLUMNS] = $this->printNestedTag( + $items[$inverseJoinColumnsKey] = $this->printNestedTag( $this->inverseJoinColumns, false, $this->inverseJoinColumnsOpeningAndClosingSpace->getOpeningSpace(), diff --git a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/ManyToManyTagValueNode.php b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/ManyToManyTagValueNode.php index e969f1a8d82e..6358f87202b3 100644 --- a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/ManyToManyTagValueNode.php +++ b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/ManyToManyTagValueNode.php @@ -9,12 +9,9 @@ use Rector\BetterPhpDocParser\Contract\Doctrine\ToManyTagNodeInterface; use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\AbstractDoctrineTagValueNode; use Rector\PhpAttribute\Contract\PhpAttributableTagNodeInterface; -use Rector\PhpAttribute\PhpDocNode\PhpAttributePhpDocNodePrintTrait; final class ManyToManyTagValueNode extends AbstractDoctrineTagValueNode implements ToManyTagNodeInterface, MappedByNodeInterface, InversedByNodeInterface, PhpAttributableTagNodeInterface { - use PhpAttributePhpDocNodePrintTrait; - /** * @var string */ @@ -75,19 +72,11 @@ public function getShortName(): string return '@ORM\ManyToMany'; } - public function toAttributeString(): string - { - return $this->printItemsToAttributeString($this->createAttributeItems()); - } - /** * @return mixed[] */ - private function createAttributeItems(): array + public function getAttributableItems(): array { - $items = $this->items; - $items[self::TARGET_ENTITY] .= '::class'; - - return $items; + return $this->filterOutMissingItems($this->items); } } diff --git a/packages/better-php-doc-parser/src/PhpDocNode/Symfony/Validator/Constraints/AssertEmailTagValueNode.php b/packages/better-php-doc-parser/src/PhpDocNode/Symfony/Validator/Constraints/AssertEmailTagValueNode.php index 0d295313d9a1..18a56a6ceca0 100644 --- a/packages/better-php-doc-parser/src/PhpDocNode/Symfony/Validator/Constraints/AssertEmailTagValueNode.php +++ b/packages/better-php-doc-parser/src/PhpDocNode/Symfony/Validator/Constraints/AssertEmailTagValueNode.php @@ -9,27 +9,27 @@ use Rector\BetterPhpDocParser\Contract\PhpDocNode\TypeAwareTagValueNodeInterface; use Rector\BetterPhpDocParser\PhpDocNode\AbstractTagValueNode; use Rector\PhpAttribute\Contract\PhpAttributableTagNodeInterface; -use Rector\PhpAttribute\PhpDocNode\PhpAttributePhpDocNodePrintTrait; /** * @see \Rector\BetterPhpDocParser\Tests\PhpDocParser\TagValueNodeReprint\TagValueNodeReprintTest */ final class AssertEmailTagValueNode extends AbstractTagValueNode implements TypeAwareTagValueNodeInterface, ShortNameAwareTagInterface, PhpAttributableTagNodeInterface, SilentKeyNodeInterface { - use PhpAttributePhpDocNodePrintTrait; - public function getShortName(): string { return '@Assert\Email'; } - public function toAttributeString(): string + public function getSilentKey(): string { - return $this->printItemsToAttributeAsArrayString($this->items); + return 'choices'; } - public function getSilentKey(): string + /** + * @return mixed[] + */ + public function getAttributableItems(): array { - return 'choices'; + return $this->filterOutMissingItems($this->items); } } diff --git a/packages/better-php-doc-parser/src/PhpDocNode/Symfony/Validator/Constraints/AssertRangeTagValueNode.php b/packages/better-php-doc-parser/src/PhpDocNode/Symfony/Validator/Constraints/AssertRangeTagValueNode.php index 529c6aaa3e62..e5546544c430 100644 --- a/packages/better-php-doc-parser/src/PhpDocNode/Symfony/Validator/Constraints/AssertRangeTagValueNode.php +++ b/packages/better-php-doc-parser/src/PhpDocNode/Symfony/Validator/Constraints/AssertRangeTagValueNode.php @@ -8,19 +8,19 @@ use Rector\BetterPhpDocParser\Contract\PhpDocNode\TypeAwareTagValueNodeInterface; use Rector\BetterPhpDocParser\PhpDocNode\AbstractTagValueNode; use Rector\PhpAttribute\Contract\PhpAttributableTagNodeInterface; -use Rector\PhpAttribute\PhpDocNode\PhpAttributePhpDocNodePrintTrait; final class AssertRangeTagValueNode extends AbstractTagValueNode implements TypeAwareTagValueNodeInterface, ShortNameAwareTagInterface, PhpAttributableTagNodeInterface { - use PhpAttributePhpDocNodePrintTrait; - public function getShortName(): string { return '@Assert\Range'; } - public function toAttributeString(): string + /** + * @return mixed[] + */ + public function getAttributableItems(): array { - return $this->printItemsToAttributeAsArrayString($this->items); + return $this->filterOutMissingItems($this->items); } } diff --git a/packages/php-attribute/src/AnnotationToAttributeConverter.php b/packages/php-attribute/src/AnnotationToAttributeConverter.php index e3b7ca4378f9..69b403eb9b49 100644 --- a/packages/php-attribute/src/AnnotationToAttributeConverter.php +++ b/packages/php-attribute/src/AnnotationToAttributeConverter.php @@ -5,33 +5,31 @@ namespace Rector\PhpAttribute; use PhpParser\Node; +use PhpParser\Node\Stmt\Class_; +use PhpParser\Node\Stmt\ClassMethod; +use PhpParser\Node\Stmt\Property; use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\PhpAttribute\Contract\PhpAttributableTagNodeInterface; -use Rector\PhpAttribute\Printer\PlaceholderNodeFactory; -use Rector\PostRector\Collector\NodesToAddCollector; +use Rector\PhpAttribute\Printer\PhpAttributteGroupFactory; final class AnnotationToAttributeConverter { /** - * @var NodesToAddCollector + * @var PhpAttributteGroupFactory */ - private $nodesToAddCollector; - - /** - * @var PlaceholderNodeFactory - */ - private $placeholderNodeFactory; + private $phpAttributableTagNodeToAttributeGroupsConverter; public function __construct( - NodesToAddCollector $nodesToAddCollector, - PlaceholderNodeFactory $placeholderNodeFactory + PhpAttributteGroupFactory $phpAttributableTagNodeToAttributeGroupsConverter ) { - $this->nodesToAddCollector = $nodesToAddCollector; - $this->placeholderNodeFactory = $placeholderNodeFactory; + $this->phpAttributableTagNodeToAttributeGroupsConverter = $phpAttributableTagNodeToAttributeGroupsConverter; } + /** + * @param Class_|ClassMethod|Property $node + */ public function convertNode(Node $node): ?Node { /** @var PhpDocInfo|null $phpDocInfo */ @@ -53,8 +51,7 @@ public function convertNode(Node $node): ?Node } // 2. convert annotations to attributes - $placeholderNop = $this->placeholderNodeFactory->create($phpAttributableTagNodes); - $this->nodesToAddCollector->addNodeBeforeNode($placeholderNop, $node); + $node->attrGroups = $this->phpAttributableTagNodeToAttributeGroupsConverter->create($phpAttributableTagNodes); return $node; } diff --git a/packages/php-attribute/src/Collector/PlaceholderToValueCollector.php b/packages/php-attribute/src/Collector/PlaceholderToValueCollector.php deleted file mode 100644 index 4daba77bce12..000000000000 --- a/packages/php-attribute/src/Collector/PlaceholderToValueCollector.php +++ /dev/null @@ -1,27 +0,0 @@ -placeholderToValue[$placeholder . PHP_EOL] = $value; - } - - /** - * @return string[] - */ - public function getMap(): array - { - return $this->placeholderToValue; - } -} diff --git a/packages/php-attribute/src/Contract/ManyPhpAttributableTagNodeInterface.php b/packages/php-attribute/src/Contract/ManyPhpAttributableTagNodeInterface.php new file mode 100644 index 000000000000..ab2a4e8cbb26 --- /dev/null +++ b/packages/php-attribute/src/Contract/ManyPhpAttributableTagNodeInterface.php @@ -0,0 +1,13 @@ + + */ + public function provide(): array; +} diff --git a/packages/php-attribute/src/Contract/PhpAttributableTagNodeInterface.php b/packages/php-attribute/src/Contract/PhpAttributableTagNodeInterface.php index e02c448eb43d..d330d1293f4d 100644 --- a/packages/php-attribute/src/Contract/PhpAttributableTagNodeInterface.php +++ b/packages/php-attribute/src/Contract/PhpAttributableTagNodeInterface.php @@ -6,7 +6,10 @@ interface PhpAttributableTagNodeInterface { - public function toAttributeString(): string; + public function getShortName(): string; - public function printPhpAttributeItems(array $items): string; + /** + * @return mixed[] + */ + public function getAttributableItems(): array; } diff --git a/packages/php-attribute/src/PhpDocNode/PhpAttributePhpDocNodePrintTrait.php b/packages/php-attribute/src/PhpDocNode/PhpAttributePhpDocNodePrintTrait.php deleted file mode 100644 index 17c28af37efc..000000000000 --- a/packages/php-attribute/src/PhpDocNode/PhpAttributePhpDocNodePrintTrait.php +++ /dev/null @@ -1,73 +0,0 @@ - $item) { - if (! is_array($item)) { - continue; - } - - $items[$key] = $this->printPhpAttributeItems($item); - } - - return '(' . implode(', ', $items) . ')'; - } - - public function printItemsToAttributeAsArrayString(array $items): string - { - $items = $this->filterOutMissingItems($items); - $items = $this->completeItemsQuotes($items); - - $content = $this->printPhpAttributeItemsAsArray($items); - - return $this->printPhpAttributeContent($content); - } - - public function printItemsToAttributeString(array $items): string - { - $items = $this->filterOutMissingItems($items); - $items = $this->completeItemsQuotes($items); - - $content = $this->printPhpAttributeItems($items); - return $this->printPhpAttributeContent($content); - } - - protected function printPhpAttributeContent(string $content = ''): string - { - $attributeStart = '<<' . ltrim($this->getShortName(), '@'); - - return $attributeStart . $content . '>>'; - } - - /** - * @param string[] $items - */ - protected function printPhpAttributeItemsAsArray(array $items): string - { - if ($items === []) { - return ''; - } - - foreach ($items as $key => $value) { - $items[$key] = sprintf('"%s" => %s', $key, $value); - } - - return '([' . implode(', ', $items) . '])'; - } -} diff --git a/packages/php-attribute/src/Printer/ContentPhpAttributePlaceholderReplacer.php b/packages/php-attribute/src/Printer/ContentPhpAttributePlaceholderReplacer.php deleted file mode 100644 index aa0472da41e0..000000000000 --- a/packages/php-attribute/src/Printer/ContentPhpAttributePlaceholderReplacer.php +++ /dev/null @@ -1,60 +0,0 @@ ->\n\n#'; - - /** - * @var PlaceholderToValueCollector - */ - private $placeholderToValueCollector; - - public function __construct(PlaceholderToValueCollector $placeholderToValueCollector) - { - $this->placeholderToValueCollector = $placeholderToValueCollector; - } - - public function decorateContent(string $content): string - { - // nothing to replace - if ($this->placeholderToValueCollector->getMap() === []) { - return $content; - } - - $map = $this->placeholderToValueCollector->getMap(); - - foreach ($map as $placeholder => $value) { - $quotedPlaceholder = preg_quote($placeholder, '#'); - if (! Strings::match($content, '#' . $quotedPlaceholder . '#')) { - continue; - } - - $value = $this->addLeftIndent($content, $quotedPlaceholder, $value); - $content = Strings::replace($content, '#' . $quotedPlaceholder . '#', $value); - } - - // remove extra newline between attributes and node - return Strings::replace($content, self::ATTRIBUTE_END_REGEX, '>>' . PHP_EOL); - } - - private function addLeftIndent(string $content, string $quotedPlaceholder, string $value): string - { - $matches = Strings::match($content, '#^(?\s+)' . $quotedPlaceholder . '#ms'); - if (! isset($matches['indent'])) { - return $value; - } - - $values = explode(PHP_EOL, $value); - return implode(PHP_EOL . $matches['indent'], $values); - } -} diff --git a/packages/php-attribute/src/Printer/PhpAttributteGroupFactory.php b/packages/php-attribute/src/Printer/PhpAttributteGroupFactory.php new file mode 100644 index 000000000000..e7ca8b173197 --- /dev/null +++ b/packages/php-attribute/src/Printer/PhpAttributteGroupFactory.php @@ -0,0 +1,111 @@ +printPhpAttributableTagNode($phpAttributableTagNode); + $attributeGroups = array_merge($attributeGroups, $currentAttributeGroups); + } + + return $attributeGroups; + } + + /** + * @return Arg[] + */ + public function printItemsToAttributeArgs(PhpAttributableTagNodeInterface $phpAttributableTagNode): array + { + $items = $phpAttributableTagNode->getAttributableItems(); + return $this->createArgsFromItems($items); + } + + /** + * @return AttributeGroup[] + */ + private function printPhpAttributableTagNode(PhpAttributableTagNodeInterface $phpAttributableTagNode): array + { + $args = $this->printItemsToAttributeArgs($phpAttributableTagNode); + + $attributeGroups = []; + $attributeGroups[] = $this->createAttributeGroupFromShortNameAndArgs( + $phpAttributableTagNode->getShortName(), + $args + ); + + if ($phpAttributableTagNode instanceof ManyPhpAttributableTagNodeInterface) { + foreach ($phpAttributableTagNode->provide() as $shortName => $items) { + $args = $this->createArgsFromItems($items); + $attributeGroups[] = $this->createAttributeGroupFromShortNameAndArgs($shortName, $args); + } + } + + return $attributeGroups; + } + + /** + * @return Arg[] + */ + private function createArgsFromItems(array $items): array + { + $args = []; + + if ($this->isArrayArguments($items)) { + $arrayItems = []; + foreach ($items as $key => $value) { + $key = BuilderHelpers::normalizeValue($key); + $value = BuilderHelpers::normalizeValue($value); + $arrayItems[] = new ArrayItem($value, $key); + } + + $args[] = new Arg(new Array_($arrayItems)); + } else { + foreach ($items as $value) { + $value = BuilderHelpers::normalizeValue($value); + $args[] = new Arg($value); + } + } + + return $args; + } + + /** + * @param Arg[] $args + */ + private function createAttributeGroupFromShortNameAndArgs(string $shortName, array $args): AttributeGroup + { + $attribute = new Attribute(new Name($shortName), $args); + return new AttributeGroup([$attribute]); + } + + private function isArrayArguments(array $items): bool + { + foreach (array_keys($items) as $key) { + if (! is_int($key)) { + return true; + } + } + + return false; + } +} diff --git a/packages/php-attribute/src/Printer/PlaceholderNodeFactory.php b/packages/php-attribute/src/Printer/PlaceholderNodeFactory.php deleted file mode 100644 index ee11b8cdd520..000000000000 --- a/packages/php-attribute/src/Printer/PlaceholderNodeFactory.php +++ /dev/null @@ -1,67 +0,0 @@ -placeholderToValueCollector = $placeholderToValueCollector; - } - - /** - * @param PhpAttributableTagNodeInterface[] $phpAttributableTagNodes - */ - public function create(array $phpAttributableTagNodes): Nop - { - // 1. change attributable tags to string - $phpAttributesString = $this->createPhpAttributesString($phpAttributableTagNodes); - - // 2. create placeholder node - $placeholderNop = new Nop(); - $placeholderName = $this->createPlaceholderName(); - $placeholderNop->setAttribute(AttributeKey::COMMENTS, [new Comment($placeholderName)]); - - // 3. store key/value placeholder - $this->placeholderToValueCollector->add($placeholderName, $phpAttributesString); - ++$this->phpAttributePlaceholderCounter; - - return $placeholderNop; - } - - /** - * @param PhpAttributableTagNodeInterface[] $phpAttributableTagNodes - */ - private function createPhpAttributesString(array $phpAttributableTagNodes): string - { - $phpAttributesStrings = []; - foreach ($phpAttributableTagNodes as $phpAttributableTagNode) { - $phpAttributesStrings[] = $phpAttributableTagNode->toAttributeString(); - } - - return implode(PHP_EOL, $phpAttributesStrings); - } - - private function createPlaceholderName(): string - { - return '__PHP_ATTRIBUTE_PLACEHOLDER_' . $this->phpAttributePlaceholderCounter . '__'; - } -} diff --git a/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/assert_range.php.inc b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/assert_range.php.inc index 34ce40628262..4973643a1110 100644 --- a/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/assert_range.php.inc +++ b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/assert_range.php.inc @@ -27,7 +27,7 @@ use Symfony\Component\Validator\Constraints as Assert; class AssertRange { - < 120, "max" => 180, "minMessage" => "You must be at least {{ limit }}cm tall to enter", "maxMessage" => "You cannot be taller than {{ limit }}cm to enter"])>> + #[@Assert\Range(['min' => 120, 'max' => 180, 'minMessage' => 'You must be at least {{ limit }}cm tall to enter', 'maxMessage' => 'You cannot be taller than {{ limit }}cm to enter'])] protected $height; } diff --git a/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/entity_column_and_assert_email.php.inc b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/entity_column_and_assert_email.php.inc index 689eda2dd1cb..46049ddcdf18 100644 --- a/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/entity_column_and_assert_email.php.inc +++ b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/entity_column_and_assert_email.php.inc @@ -25,8 +25,8 @@ use Symfony\Component\Validator\Constraints as Assert; class EntityColumnAndAssertEmail { - <> - < "This value is not a valid email address."])>> + #[@ORM\Column(['type' => 'string', 'unique' => true])] + #[@Assert\Email(['message' => 'This value is not a valid email address.'])] public $name; } diff --git a/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/id_column_generated_value.php.inc b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/id_column_generated_value.php.inc index fe6b7323ce71..2e61378c1dd1 100644 --- a/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/id_column_generated_value.php.inc +++ b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/id_column_generated_value.php.inc @@ -7,7 +7,6 @@ use Doctrine\ORM\Mapping as ORM; class IdColumnGeneratedvalue { /** - * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue */ @@ -24,9 +23,8 @@ use Doctrine\ORM\Mapping as ORM; class IdColumnGeneratedvalue { - <> - <> - <> + #[@ORM\Column(['type' => 'integer'])] + #[@ORM\GeneratedValue] public $name; } diff --git a/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/join_table.php.inc b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/join_table.php.inc new file mode 100644 index 000000000000..32229b13ddd4 --- /dev/null +++ b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/join_table.php.inc @@ -0,0 +1,34 @@ + +----- + 'users_phonenumbers'])] + #[@ORM\JoinColumn(['name' => 'user_id', 'referencedColumnName' => 'id'])] + #[@ORM\InverseJoinColumn(['name' => 'phonenumber_id', 'referencedColumnName' => 'id', 'unique' => true])] + public $name; +} + +?> diff --git a/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/just_id.php.inc b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/just_id.php.inc new file mode 100644 index 000000000000..fb73fe98a5be --- /dev/null +++ b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/just_id.php.inc @@ -0,0 +1,29 @@ + +----- + diff --git a/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/many_to_many.php.inc b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/many_to_many.php.inc index 27da397385a9..29dd601bb190 100644 --- a/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/many_to_many.php.inc +++ b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/RFC/many_to_many.php.inc @@ -8,10 +8,6 @@ class ManyToMany { /** * @ORM\ManyToMany(targetEntity="Phonenumber") - * @ORM\JoinTable(name="users_phonenumbers", - * joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")}, - * inverseJoinColumns={@ORM\JoinColumn(name="phonenumber_id", referencedColumnName="id", unique=true)} - * ) */ public $name; } @@ -26,10 +22,7 @@ use Doctrine\ORM\Mapping as ORM; class ManyToMany { - <> - <> - <> - <> + #[@ORM\ManyToMany(['targetEntity' => 'Phonenumber'])] public $name; } diff --git a/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/entity_with_repository.php.inc b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/entity_with_repository.php.inc index 12c4be10a5f3..0c707efed386 100644 --- a/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/entity_with_repository.php.inc +++ b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/entity_with_repository.php.inc @@ -18,7 +18,8 @@ class EntityWithRepository namespace Rector\Php80\Tests\Rector\Class_\AnnotationToAttributeRector\Fixture; use Doctrine\ORM\Mapping as ORM; -<> + +#[@ORM\Entity(['repositoryClass' => 'MyProject\UserRepository', 'readOnly' => true])] class EntityWithRepository { } diff --git a/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/fixture.php.inc b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/fixture.php.inc index e01b02c6ab9d..dc8ed7436515 100644 --- a/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/fixture.php.inc +++ b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/fixture.php.inc @@ -18,7 +18,8 @@ class SomeClass namespace Rector\Php80\Tests\Rector\Class_\AnnotationToAttributeRector\Fixture; use Doctrine\ORM\Mapping as ORM; -<> + +#[@ORM\Entity] class SomeClass { } diff --git a/src/PhpParser/Printer/BetterStandardPrinter.php b/src/PhpParser/Printer/BetterStandardPrinter.php index 0a9bb7cb5f55..74e1f3bc4210 100644 --- a/src/PhpParser/Printer/BetterStandardPrinter.php +++ b/src/PhpParser/Printer/BetterStandardPrinter.php @@ -22,7 +22,6 @@ use PhpParser\PrettyPrinter\Standard; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator; -use Rector\PhpAttribute\Printer\ContentPhpAttributePlaceholderReplacer; use Symplify\SmartFileSystem\SmartFileInfo; /** @@ -81,18 +80,11 @@ final class BetterStandardPrinter extends Standard */ private $docBlockManipulator; - /** - * @var ContentPhpAttributePlaceholderReplacer - */ - private $contentPhpAttributePlaceholderReplacer; - /** * @param mixed[] $options */ - public function __construct( - ContentPhpAttributePlaceholderReplacer $contentPhpAttributePlaceholderReplacer, - array $options = [] - ) { + public function __construct(array $options = []) + { parent::__construct($options); // print return type double colon right after the bracket "function(): string" @@ -100,8 +92,6 @@ public function __construct( $this->insertionMap['Stmt_ClassMethod->returnType'] = [')', false, ': ', null]; $this->insertionMap['Stmt_Function->returnType'] = [')', false, ': ', null]; $this->insertionMap['Expr_Closure->returnType'] = [')', false, ': ', null]; - - $this->contentPhpAttributePlaceholderReplacer = $contentPhpAttributePlaceholderReplacer; } /** @@ -124,8 +114,7 @@ public function printFormatPreserving(array $stmts, array $origStmts, array $ori $content .= $this->nl; } - // php attributes - return $this->contentPhpAttributePlaceholderReplacer->decorateContent($content); + return $content; } /** @@ -361,10 +350,7 @@ protected function pStmts(array $nodes, bool $indent = true): string { $this->moveCommentsFromAttributeObjectToCommentsAttribute($nodes); - $content = parent::pStmts($nodes, $indent); - - // php attributes - return $this->contentPhpAttributePlaceholderReplacer->decorateContent($content); + return parent::pStmts($nodes, $indent); } /** From 07070b8c1ffb372b8f82012a5853e6ff07358663 Mon Sep 17 00:00:00 2001 From: rector-bot Date: Fri, 25 Sep 2020 08:09:20 +0000 Subject: [PATCH 4/5] [rector] [PHP 8.0] Add Annotation to Attribute rule based on php-parser --- .../php-attribute/src/AnnotationToAttributeConverter.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/php-attribute/src/AnnotationToAttributeConverter.php b/packages/php-attribute/src/AnnotationToAttributeConverter.php index 69b403eb9b49..b4c9669033f6 100644 --- a/packages/php-attribute/src/AnnotationToAttributeConverter.php +++ b/packages/php-attribute/src/AnnotationToAttributeConverter.php @@ -19,12 +19,12 @@ final class AnnotationToAttributeConverter /** * @var PhpAttributteGroupFactory */ - private $phpAttributableTagNodeToAttributeGroupsConverter; + private $phpAttributteGroupFactory; public function __construct( - PhpAttributteGroupFactory $phpAttributableTagNodeToAttributeGroupsConverter + PhpAttributteGroupFactory $phpAttributteGroupFactory ) { - $this->phpAttributableTagNodeToAttributeGroupsConverter = $phpAttributableTagNodeToAttributeGroupsConverter; + $this->phpAttributteGroupFactory = $phpAttributteGroupFactory; } /** @@ -51,7 +51,7 @@ public function convertNode(Node $node): ?Node } // 2. convert annotations to attributes - $node->attrGroups = $this->phpAttributableTagNodeToAttributeGroupsConverter->create($phpAttributableTagNodes); + $node->attrGroups = $this->phpAttributteGroupFactory->create($phpAttributableTagNodes); return $node; } From 5bffae45d8175ecaec2829233221ea4cc637af11 Mon Sep 17 00:00:00 2001 From: rector-bot Date: Fri, 25 Sep 2020 08:10:45 +0000 Subject: [PATCH 5/5] [cs] [PHP 8.0] Add Annotation to Attribute rule based on php-parser --- .../php-attribute/src/AnnotationToAttributeConverter.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/php-attribute/src/AnnotationToAttributeConverter.php b/packages/php-attribute/src/AnnotationToAttributeConverter.php index b4c9669033f6..9c5099c4ae38 100644 --- a/packages/php-attribute/src/AnnotationToAttributeConverter.php +++ b/packages/php-attribute/src/AnnotationToAttributeConverter.php @@ -21,9 +21,8 @@ final class AnnotationToAttributeConverter */ private $phpAttributteGroupFactory; - public function __construct( - PhpAttributteGroupFactory $phpAttributteGroupFactory - ) { + public function __construct(PhpAttributteGroupFactory $phpAttributteGroupFactory) + { $this->phpAttributteGroupFactory = $phpAttributteGroupFactory; }