From d074d5169ab98d4eb1d384f9a7393c4996b8b633 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Sun, 23 Feb 2020 23:24:10 +0100 Subject: [PATCH] Fix FinalizeClassesWithoutChildrenRector for embedable --- .../Class_/EmbeddableTagValueNode.php | 25 ++++++++ .../Class_/EmbeddablePhpDocNodeFactory.php | 39 ++++++++++++ phpstan.neon | 3 +- .../PhpDocParser/DoctrineDocBlockResolver.php | 59 +++++++++++++------ .../Fixture/skip_embedable.php.inc | 12 ++++ .../{entity.php.inc => skip_entity.php.inc} | 2 +- stubs/Doctrine/ORM/Mapping/Embeddable.php | 17 ++++++ 7 files changed, 135 insertions(+), 22 deletions(-) create mode 100644 packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Class_/EmbeddableTagValueNode.php create mode 100644 packages/better-php-doc-parser/src/PhpDocNodeFactory/Doctrine/Class_/EmbeddablePhpDocNodeFactory.php create mode 100644 rules/solid/tests/Rector/Class_/FinalizeClassesWithoutChildrenRector/Fixture/skip_embedable.php.inc rename rules/solid/tests/Rector/Class_/FinalizeClassesWithoutChildrenRector/Fixture/{entity.php.inc => skip_entity.php.inc} (90%) create mode 100644 stubs/Doctrine/ORM/Mapping/Embeddable.php diff --git a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Class_/EmbeddableTagValueNode.php b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Class_/EmbeddableTagValueNode.php new file mode 100644 index 000000000000..da18b9769d58 --- /dev/null +++ b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Class_/EmbeddableTagValueNode.php @@ -0,0 +1,25 @@ +resolveOriginalContentSpacingAndOrder($originalContent); + } + + public function __toString(): string + { + return $this->originalContent; + } + + public function getShortName(): string + { + return '@ORM\Embeddable'; + } +} diff --git a/packages/better-php-doc-parser/src/PhpDocNodeFactory/Doctrine/Class_/EmbeddablePhpDocNodeFactory.php b/packages/better-php-doc-parser/src/PhpDocNodeFactory/Doctrine/Class_/EmbeddablePhpDocNodeFactory.php new file mode 100644 index 000000000000..693bc13254ed --- /dev/null +++ b/packages/better-php-doc-parser/src/PhpDocNodeFactory/Doctrine/Class_/EmbeddablePhpDocNodeFactory.php @@ -0,0 +1,39 @@ +nodeAnnotationReader->readClassAnnotation($node, $this->getClass()); + if ($entity === null) { + return null; + } + + $annotationContent = $this->resolveContentFromTokenIterator($tokenIterator); + + return new EmbeddableTagValueNode($annotationContent); + } +} diff --git a/phpstan.neon b/phpstan.neon index 08e78594872a..0a7448837346 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -246,8 +246,7 @@ parameters: - '#Right side of && is always true#' - '#Parameter \#(.*?) (.*?) of class PhpParser\\Node\\Expr\\BinaryOp\\(.*?) constructor expects PhpParser\\Node\\Expr, PhpParser\\Node given#' - - '#Method Rector\\BetterPhpDocParser\\PhpDocNode\\JMS\\JMSInjectParamsTagValueNode\:\:__toString\(\) should return string but returns string\|null#' - - '#Method Rector\\BetterPhpDocParser\\PhpDocNode\\JMS\\JMSServiceValueNode\:\:__toString\(\) should return string but returns string\|null#' + - '#Method Rector\\(.*?)\:\:__toString\(\) should return string but returns string\|null#' - '#Strict comparison using \=\=\= between mixed and (.*?) will always evaluate to false#' - '#Parameter \#1 \$c of method Rector\\Php70\\EregToPcreTransformer\:\:_ere2pcre_escape\(\) expects string, mixed given#' diff --git a/rules/doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php b/rules/doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php index 46dc9c3ff464..8933a0ada2da 100644 --- a/rules/doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php +++ b/rules/doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php @@ -10,6 +10,7 @@ use PhpParser\Node\Stmt\ClassLike; use PhpParser\Node\Stmt\Property; use Rector\BetterPhpDocParser\Contract\Doctrine\DoctrineRelationTagValueNodeInterface; +use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Class_\EmbeddableTagValueNode; use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Class_\EntityTagValueNode; use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Property_\ColumnTagValueNode; use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Property_\IdTagValueNode; @@ -37,28 +38,11 @@ public function __construct(ParsedNodeCollector $parsedNodeCollector) public function isDoctrineEntityClass($class): bool { if ($class instanceof Class_) { - $phpDocInfo = $class->getAttribute(AttributeKey::PHP_DOC_INFO); - if ($phpDocInfo === null) { - return false; - } - - return $phpDocInfo->hasByType(EntityTagValueNode::class); + return $this->isDoctrineEntityClassNode($class); } if (is_string($class)) { - if (ClassExistenceStaticHelper::doesClassLikeExist($class)) { - $classNode = $this->parsedNodeCollector->findClass($class); - if ($classNode !== null) { - return $this->isDoctrineEntityClass($classNode); - } - - $reflectionClass = new ReflectionClass($class); - - // dummy check of 3rd party code without running it - return Strings::contains((string) $reflectionClass->getDocComment(), '@ORM\Entity'); - } - - return false; + return $this->isStringClassEntity($class); } throw new ShouldNotHappenException(); @@ -137,4 +121,41 @@ public function isInDoctrineEntityClass(Node $node): bool return $this->isDoctrineEntityClass($classNode); } + + private function isDoctrineEntityClassNode(Class_ $class): bool + { + $phpDocInfo = $class->getAttribute(AttributeKey::PHP_DOC_INFO); + if ($phpDocInfo === null) { + return false; + } + + if ($phpDocInfo->hasByType(EntityTagValueNode::class)) { + return true; + } + + return $phpDocInfo->hasByType(EmbeddableTagValueNode::class); + } + + private function isStringClassEntity(string $class): bool + { + if (! ClassExistenceStaticHelper::doesClassLikeExist($class)) { + return false; + } + + $classNode = $this->parsedNodeCollector->findClass($class); + if ($classNode !== null) { + return $this->isDoctrineEntityClass($classNode); + } + + $reflectionClass = new ReflectionClass($class); + + // dummy check of 3rd party code without running it + $docCommentContent = (string) $reflectionClass->getDocComment(); + + if (Strings::contains($docCommentContent, '@ORM\Entity')) { + return true; + } + + return Strings::contains($docCommentContent, '@ORM\Embeddable'); + } } diff --git a/rules/solid/tests/Rector/Class_/FinalizeClassesWithoutChildrenRector/Fixture/skip_embedable.php.inc b/rules/solid/tests/Rector/Class_/FinalizeClassesWithoutChildrenRector/Fixture/skip_embedable.php.inc new file mode 100644 index 000000000000..49718d589b20 --- /dev/null +++ b/rules/solid/tests/Rector/Class_/FinalizeClassesWithoutChildrenRector/Fixture/skip_embedable.php.inc @@ -0,0 +1,12 @@ +