Updated Rector to commit 2ff0f08bd7f7f6c848821bcabf0872f81a9c440b

2ff0f08bd7 [PHP 8.0] Add always class to AnnotationToAttribute to include string to ::class reference conversion (#5619)
This commit is contained in:
Tomas Votruba 2024-02-14 19:28:57 +00:00
parent a022b931b8
commit 055cd31f66
24 changed files with 147 additions and 180 deletions

View File

@ -5,6 +5,7 @@ namespace Rector\Php80\ValueObject;
use Rector\Php80\Contract\ValueObject\AnnotationToAttributeInterface;
use Rector\Validation\RectorAssert;
use RectorPrefix202402\Webmozart\Assert\Assert;
final class AnnotationToAttribute implements AnnotationToAttributeInterface
{
/**
@ -17,14 +18,24 @@ final class AnnotationToAttribute implements AnnotationToAttributeInterface
* @var string|null
*/
private $attributeClass;
public function __construct(string $tag, ?string $attributeClass = null)
/**
* @var string[]
* @readonly
*/
private $classReferenceFields = [];
/**
* @param string[] $classReferenceFields
*/
public function __construct(string $tag, ?string $attributeClass = null, array $classReferenceFields = [])
{
$this->tag = $tag;
$this->attributeClass = $attributeClass;
$this->classReferenceFields = $classReferenceFields;
RectorAssert::className($tag);
if (\is_string($attributeClass)) {
RectorAssert::className($attributeClass);
}
Assert::allString($classReferenceFields);
}
public function getTag() : string
{
@ -37,4 +48,11 @@ final class AnnotationToAttribute implements AnnotationToAttributeInterface
}
return $this->attributeClass;
}
/**
* @return string[]
*/
public function getClassReferenceFields() : array
{
return $this->classReferenceFields;
}
}

View File

@ -19,12 +19,12 @@ final class VersionResolver
* @api
* @var string
*/
public const PACKAGE_VERSION = '435d125053eed8764652ccf8565bde1660ee08ce';
public const PACKAGE_VERSION = '2ff0f08bd7f7f6c848821bcabf0872f81a9c440b';
/**
* @api
* @var string
*/
public const RELEASE_DATE = '2024-02-14 15:37:49';
public const RELEASE_DATE = '2024-02-14 19:26:45';
/**
* @var int
*/

View File

@ -32,7 +32,7 @@ final class AnnotationToAttributeMapper
Assert::notEmpty($annotationToAttributeMappers);
}
/**
* @return Expr|DocTagNodeState::REMOVE_ARRAY
* @return mixed|DocTagNodeState::REMOVE_ARRAY
* @param mixed $value
*/
public function map($value)

View File

@ -16,9 +16,10 @@ final class AttributeArrayNameInliner
{
/**
* @param Array_|Arg[] $array
* @param string[] $classReferenceFields
* @return Arg[]
*/
public function inlineArrayToArgs($array) : array
public function inlineArrayToArgs($array, array $classReferenceFields = []) : array
{
if (\is_array($array)) {
return $this->inlineArray($array);

View File

@ -1,103 +0,0 @@
<?php
declare (strict_types=1);
namespace Rector\PhpAttribute\NodeAnalyzer;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Scalar\String_;
use PHPStan\Reflection\ParameterReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\TypeCombinator;
use Rector\PhpParser\Node\NodeFactory;
use Rector\StaticTypeMapper\StaticTypeMapper;
final class ExprParameterReflectionTypeCorrector
{
/**
* @readonly
* @var \Rector\StaticTypeMapper\StaticTypeMapper
*/
private $staticTypeMapper;
/**
* @readonly
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
/**
* @readonly
* @var \Rector\PhpParser\Node\NodeFactory
*/
private $nodeFactory;
public function __construct(StaticTypeMapper $staticTypeMapper, ReflectionProvider $reflectionProvider, NodeFactory $nodeFactory)
{
$this->staticTypeMapper = $staticTypeMapper;
$this->reflectionProvider = $reflectionProvider;
$this->nodeFactory = $nodeFactory;
}
/**
* @param array<string|int, Expr|mixed> $items
* @return array<string|int, Expr|mixed>
*/
public function correctItemsByAttributeClass($items, string $attributeClass) : array
{
if ($items instanceof Array_) {
$items = $items->items;
}
if (!$this->reflectionProvider->hasClass($attributeClass)) {
return $items;
}
$attributeClassReflection = $this->reflectionProvider->getClass($attributeClass);
// nothing to retype by constructor
if (!$attributeClassReflection->hasConstructor()) {
return $items;
}
$extendedMethodReflection = $attributeClassReflection->getConstructor();
$parametersAcceptorWithPhpDocs = ParametersAcceptorSelector::selectSingle($extendedMethodReflection->getVariants());
foreach ($items as $name => $item) {
foreach ($parametersAcceptorWithPhpDocs->getParameters() as $parameterReflection) {
$correctedItem = $this->correctItemByParameterReflection($name, $item, $parameterReflection);
if (!$correctedItem instanceof Expr) {
continue;
}
$items[$name] = $correctedItem;
continue 2;
}
}
return $items;
}
/**
* @param string|int $name
* @param mixed $item
*/
private function correctItemByParameterReflection($name, $item, ParameterReflection $parameterReflection) : ?\PhpParser\Node\Expr
{
if (!$item instanceof Expr) {
return null;
}
if ($name !== $parameterReflection->getName()) {
return null;
}
$parameterType = $parameterReflection->getType();
$currentType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($item);
// all good
if ($parameterType->accepts($currentType, \false)->yes()) {
return null;
}
$clearParameterType = TypeCombinator::removeNull($parameterType);
// correct type
if ($clearParameterType->isInteger()->yes() && $item instanceof String_) {
return new LNumber((int) $item->value);
}
if ($clearParameterType->isBoolean()->yes() && $item instanceof String_) {
if (\strtolower($item->value) === 'true') {
return $this->nodeFactory->createTrue();
}
if (\strtolower($item->value) === 'false') {
return $this->nodeFactory->createFalse();
}
}
return null;
}
}

View File

@ -7,7 +7,11 @@ use PhpParser\Node\Arg;
use PhpParser\Node\Attribute;
use PhpParser\Node\AttributeGroup;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Use_;
use Rector\BetterPhpDocParser\PhpDoc\ArrayItemNode;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
@ -15,7 +19,6 @@ use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Php80\ValueObject\AnnotationToAttribute;
use Rector\PhpAttribute\AnnotationToAttributeMapper;
use Rector\PhpAttribute\AttributeArrayNameInliner;
use Rector\PhpAttribute\NodeAnalyzer\ExprParameterReflectionTypeCorrector;
/**
* @see \Rector\Tests\PhpAttribute\Printer\PhpAttributeGroupFactoryTest
*/
@ -36,22 +39,16 @@ final class PhpAttributeGroupFactory
* @var \Rector\PhpAttribute\NodeFactory\NamedArgsFactory
*/
private $namedArgsFactory;
/**
* @readonly
* @var \Rector\PhpAttribute\NodeAnalyzer\ExprParameterReflectionTypeCorrector
*/
private $exprParameterReflectionTypeCorrector;
/**
* @readonly
* @var \Rector\PhpAttribute\AttributeArrayNameInliner
*/
private $attributeArrayNameInliner;
public function __construct(AnnotationToAttributeMapper $annotationToAttributeMapper, \Rector\PhpAttribute\NodeFactory\AttributeNameFactory $attributeNameFactory, \Rector\PhpAttribute\NodeFactory\NamedArgsFactory $namedArgsFactory, ExprParameterReflectionTypeCorrector $exprParameterReflectionTypeCorrector, AttributeArrayNameInliner $attributeArrayNameInliner)
public function __construct(AnnotationToAttributeMapper $annotationToAttributeMapper, \Rector\PhpAttribute\NodeFactory\AttributeNameFactory $attributeNameFactory, \Rector\PhpAttribute\NodeFactory\NamedArgsFactory $namedArgsFactory, AttributeArrayNameInliner $attributeArrayNameInliner)
{
$this->annotationToAttributeMapper = $annotationToAttributeMapper;
$this->attributeNameFactory = $attributeNameFactory;
$this->namedArgsFactory = $namedArgsFactory;
$this->exprParameterReflectionTypeCorrector = $exprParameterReflectionTypeCorrector;
$this->attributeArrayNameInliner = $attributeArrayNameInliner;
}
public function createFromSimpleTag(AnnotationToAttribute $annotationToAttribute) : AttributeGroup
@ -81,7 +78,7 @@ final class PhpAttributeGroupFactory
public function create(DoctrineAnnotationTagValueNode $doctrineAnnotationTagValueNode, AnnotationToAttribute $annotationToAttribute, array $uses) : AttributeGroup
{
$values = $doctrineAnnotationTagValueNode->getValuesWithSilentKey();
$args = $this->createArgsFromItems($values, $annotationToAttribute->getAttributeClass());
$args = $this->createArgsFromItems($values, $annotationToAttribute->getAttributeClass(), $annotationToAttribute->getClassReferenceFields());
$args = $this->attributeArrayNameInliner->inlineArrayToArgs($args);
$attributeName = $this->attributeNameFactory->create($annotationToAttribute, $doctrineAnnotationTagValueNode, $uses);
// keep FQN in the attribute, so it can be easily detected later
@ -93,14 +90,43 @@ final class PhpAttributeGroupFactory
* @api tests
*
* @param ArrayItemNode[]|mixed[] $items
* @param string[] $classReferencedFields
* @return Arg[]
*/
public function createArgsFromItems(array $items, string $attributeClass) : array
public function createArgsFromItems(array $items, string $attributeClass, array $classReferencedFields = []) : array
{
/** @var Expr[]|Expr\Array_ $mappedItems */
$mappedItems = $this->annotationToAttributeMapper->map($items);
$mappedItems = $this->exprParameterReflectionTypeCorrector->correctItemsByAttributeClass($mappedItems, $attributeClass);
$this->mapClassReferences($mappedItems, $classReferencedFields);
$values = $mappedItems instanceof Array_ ? $mappedItems->items : $mappedItems;
// the key here should contain the named argument
return $this->namedArgsFactory->createFromValues($mappedItems);
return $this->namedArgsFactory->createFromValues($values);
}
/**
* @param string[] $classReferencedFields
* @param \PhpParser\Node\Expr|string $expr
*/
private function mapClassReferences($expr, array $classReferencedFields) : void
{
if (!$expr instanceof Array_) {
return;
}
foreach ($expr->items as $arrayItem) {
if (!$arrayItem instanceof ArrayItem) {
continue;
}
if (!$arrayItem->key instanceof String_) {
continue;
}
if (!\in_array($arrayItem->key->value, $classReferencedFields)) {
continue;
}
if ($arrayItem->value instanceof ClassConstFetch) {
continue;
}
if (!$arrayItem->value instanceof String_) {
continue;
}
$arrayItem->value = new ClassConstFetch(new FullyQualified($arrayItem->value->value), 'class');
}
}
}

View File

@ -7,7 +7,7 @@ use RectorPrefix202402\Nette\Utils\Strings;
use PhpParser\Node\Arg;
use PhpParser\Node\Attribute;
use PhpParser\Node\AttributeGroup;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Nop;
@ -26,7 +26,6 @@ use Rector\Php80\ValueObject\AnnotationPropertyToAttributeClass;
use Rector\Php80\ValueObject\NestedAnnotationToAttribute;
use Rector\PhpAttribute\AnnotationToAttributeMapper;
use Rector\PhpAttribute\AttributeArrayNameInliner;
use Rector\PhpAttribute\NodeAnalyzer\ExprParameterReflectionTypeCorrector;
use RectorPrefix202402\Webmozart\Assert\Assert;
final class PhpNestedAttributeGroupFactory
{
@ -45,11 +44,6 @@ final class PhpNestedAttributeGroupFactory
* @var \Rector\PhpAttribute\NodeFactory\NamedArgsFactory
*/
private $namedArgsFactory;
/**
* @readonly
* @var \Rector\PhpAttribute\NodeAnalyzer\ExprParameterReflectionTypeCorrector
*/
private $exprParameterReflectionTypeCorrector;
/**
* @readonly
* @var \Rector\PhpAttribute\AttributeArrayNameInliner
@ -65,12 +59,11 @@ final class PhpNestedAttributeGroupFactory
* @var \Rector\BetterPhpDocParser\PhpDocParser\StaticDoctrineAnnotationParser
*/
private $staticDoctrineAnnotationParser;
public function __construct(AnnotationToAttributeMapper $annotationToAttributeMapper, \Rector\PhpAttribute\NodeFactory\AttributeNameFactory $attributeNameFactory, \Rector\PhpAttribute\NodeFactory\NamedArgsFactory $namedArgsFactory, ExprParameterReflectionTypeCorrector $exprParameterReflectionTypeCorrector, AttributeArrayNameInliner $attributeArrayNameInliner, TokenIteratorFactory $tokenIteratorFactory, StaticDoctrineAnnotationParser $staticDoctrineAnnotationParser)
public function __construct(AnnotationToAttributeMapper $annotationToAttributeMapper, \Rector\PhpAttribute\NodeFactory\AttributeNameFactory $attributeNameFactory, \Rector\PhpAttribute\NodeFactory\NamedArgsFactory $namedArgsFactory, AttributeArrayNameInliner $attributeArrayNameInliner, TokenIteratorFactory $tokenIteratorFactory, StaticDoctrineAnnotationParser $staticDoctrineAnnotationParser)
{
$this->annotationToAttributeMapper = $annotationToAttributeMapper;
$this->attributeNameFactory = $attributeNameFactory;
$this->namedArgsFactory = $namedArgsFactory;
$this->exprParameterReflectionTypeCorrector = $exprParameterReflectionTypeCorrector;
$this->attributeArrayNameInliner = $attributeArrayNameInliner;
$this->tokenIteratorFactory = $tokenIteratorFactory;
$this->staticDoctrineAnnotationParser = $staticDoctrineAnnotationParser;
@ -82,7 +75,7 @@ final class PhpNestedAttributeGroupFactory
{
$values = $doctrineAnnotationTagValueNode->getValues();
$values = $this->removeItems($values, $nestedAnnotationToAttribute);
$args = $this->createArgsFromItems($values, $nestedAnnotationToAttribute);
$args = $this->createArgsFromItems($values);
$args = $this->attributeArrayNameInliner->inlineArrayToArgs($args);
$attributeName = $this->attributeNameFactory->create($nestedAnnotationToAttribute, $doctrineAnnotationTagValueNode, $uses);
$attribute = new Attribute($attributeName, $args);
@ -107,7 +100,7 @@ final class PhpNestedAttributeGroupFactory
if (!$nestedArrayItemNode->value instanceof DoctrineAnnotationTagValueNode) {
continue;
}
$attributeArgs = $this->createAttributeArgs($nestedArrayItemNode->value, $nestedAnnotationToAttribute);
$attributeArgs = $this->createAttributeArgs($nestedArrayItemNode->value);
$originalIdentifier = $doctrineAnnotationTagValueNode->identifierTypeNode->name;
$attributeName = $this->resolveAliasedAttributeName($originalIdentifier, $nestedAnnotationPropertyToAttributeClass);
$attribute = new Attribute($attributeName, $attributeArgs);
@ -119,21 +112,20 @@ final class PhpNestedAttributeGroupFactory
/**
* @return Arg[]
*/
private function createAttributeArgs(DoctrineAnnotationTagValueNode $nestedDoctrineAnnotationTagValueNode, NestedAnnotationToAttribute $nestedAnnotationToAttribute) : array
private function createAttributeArgs(DoctrineAnnotationTagValueNode $nestedDoctrineAnnotationTagValueNode) : array
{
$args = $this->createArgsFromItems($nestedDoctrineAnnotationTagValueNode->getValues(), $nestedAnnotationToAttribute);
$args = $this->createArgsFromItems($nestedDoctrineAnnotationTagValueNode->getValues());
return $this->attributeArrayNameInliner->inlineArrayToArgs($args);
}
/**
* @param ArrayItemNode[] $arrayItemNodes
* @return Arg[]
*/
private function createArgsFromItems(array $arrayItemNodes, NestedAnnotationToAttribute $nestedAnnotationToAttribute) : array
private function createArgsFromItems(array $arrayItemNodes) : array
{
/** @var Expr[]|Expr\Array_ $arrayItemNodes */
$arrayItemNodes = $this->annotationToAttributeMapper->map($arrayItemNodes);
$arrayItemNodes = $this->exprParameterReflectionTypeCorrector->correctItemsByAttributeClass($arrayItemNodes, $nestedAnnotationToAttribute->getTag());
return $this->namedArgsFactory->createFromValues($arrayItemNodes);
$values = $arrayItemNodes instanceof Array_ ? $arrayItemNodes->items : $arrayItemNodes;
return $this->namedArgsFactory->createFromValues($values);
}
/**
* @todo improve this hardcoded approach later
@ -202,7 +194,7 @@ final class PhpNestedAttributeGroupFactory
$values = $this->staticDoctrineAnnotationParser->resolveAnnotationMethodCall($nestedTokenIterator, new Nop());
$nestedDoctrineAnnotationTagValueNode = new DoctrineAnnotationTagValueNode($identifierTypeNode, $match['annotation_content'] ?? '', $values);
}
$attributeArgs = $this->createAttributeArgs($nestedDoctrineAnnotationTagValueNode, $nestedAnnotationToAttribute);
$attributeArgs = $this->createAttributeArgs($nestedDoctrineAnnotationTagValueNode);
$originalIdentifier = $nestedDoctrineAnnotationTagValueNode->identifierTypeNode->name;
$attributeName = $this->resolveAliasedAttributeName($originalIdentifier, $annotationPropertyToAttributeClass);
if ($annotationPropertyToAttributeClass->doesNeedNewImport() && \count($attributeName->getParts()) === 1) {

View File

@ -1316,6 +1316,7 @@ return array(
'Rector\\Doctrine\\CodeQuality\\EntityMappingResolver' => $vendorDir . '/rector/rector-doctrine/rules/CodeQuality/EntityMappingResolver.php',
'Rector\\Doctrine\\CodeQuality\\Enum\\EntityMappingKey' => $vendorDir . '/rector/rector-doctrine/rules/CodeQuality/Enum/EntityMappingKey.php',
'Rector\\Doctrine\\CodeQuality\\Enum\\ToManyMappings' => $vendorDir . '/rector/rector-doctrine/rules/CodeQuality/Enum/ToManyMappings.php',
'Rector\\Doctrine\\CodeQuality\\Helper\\NodeValueNormalizer' => $vendorDir . '/rector/rector-doctrine/rules/CodeQuality/Helper/NodeValueNormalizer.php',
'Rector\\Doctrine\\CodeQuality\\NodeFactory\\ArrayItemNodeFactory' => $vendorDir . '/rector/rector-doctrine/rules/CodeQuality/NodeFactory/ArrayItemNodeFactory.php',
'Rector\\Doctrine\\CodeQuality\\Rector\\Class_\\InitializeDefaultEntityCollectionRector' => $vendorDir . '/rector/rector-doctrine/rules/CodeQuality/Rector/Class_/InitializeDefaultEntityCollectionRector.php',
'Rector\\Doctrine\\CodeQuality\\Rector\\Class_\\MoveCurrentDateTimeDefaultInEntityToConstructorRector' => $vendorDir . '/rector/rector-doctrine/rules/CodeQuality/Rector/Class_/MoveCurrentDateTimeDefaultInEntityToConstructorRector.php',
@ -1334,6 +1335,7 @@ return array(
'Rector\\Doctrine\\Dbal211\\Rector\\MethodCall\\ExtractArrayArgOnQueryBuilderSelectRector' => $vendorDir . '/rector/rector-doctrine/rules/Dbal211/Rector/MethodCall/ExtractArrayArgOnQueryBuilderSelectRector.php',
'Rector\\Doctrine\\Dbal211\\Rector\\MethodCall\\ReplaceFetchAllMethodCallRector' => $vendorDir . '/rector/rector-doctrine/rules/Dbal211/Rector/MethodCall/ReplaceFetchAllMethodCallRector.php',
'Rector\\Doctrine\\Dbal40\\Rector\\MethodCall\\ChangeCompositeExpressionAddMultipleWithWithRector' => $vendorDir . '/rector/rector-doctrine/rules/Dbal40/Rector/MethodCall/ChangeCompositeExpressionAddMultipleWithWithRector.php',
'Rector\\Doctrine\\Enum\\MappingClass' => $vendorDir . '/rector/rector-doctrine/src/Enum/MappingClass.php',
'Rector\\Doctrine\\NodeAnalyzer\\AttributeFinder' => $vendorDir . '/rector/rector-doctrine/src/NodeAnalyzer/AttributeFinder.php',
'Rector\\Doctrine\\NodeAnalyzer\\AttrinationFinder' => $vendorDir . '/rector/rector-doctrine/src/NodeAnalyzer/AttrinationFinder.php',
'Rector\\Doctrine\\NodeAnalyzer\\ConstructorAssignPropertyAnalyzer' => $vendorDir . '/rector/rector-doctrine/src/NodeAnalyzer/ConstructorAssignPropertyAnalyzer.php',
@ -1927,7 +1929,6 @@ return array(
'Rector\\PhpAttribute\\AttributeArrayNameInliner' => $baseDir . '/src/PhpAttribute/AttributeArrayNameInliner.php',
'Rector\\PhpAttribute\\Contract\\AnnotationToAttributeMapperInterface' => $baseDir . '/src/PhpAttribute/Contract/AnnotationToAttributeMapperInterface.php',
'Rector\\PhpAttribute\\Enum\\DocTagNodeState' => $baseDir . '/src/PhpAttribute/Enum/DocTagNodeState.php',
'Rector\\PhpAttribute\\NodeAnalyzer\\ExprParameterReflectionTypeCorrector' => $baseDir . '/src/PhpAttribute/NodeAnalyzer/ExprParameterReflectionTypeCorrector.php',
'Rector\\PhpAttribute\\NodeFactory\\AttributeNameFactory' => $baseDir . '/src/PhpAttribute/NodeFactory/AttributeNameFactory.php',
'Rector\\PhpAttribute\\NodeFactory\\NamedArgsFactory' => $baseDir . '/src/PhpAttribute/NodeFactory/NamedArgsFactory.php',
'Rector\\PhpAttribute\\NodeFactory\\PhpAttributeGroupFactory' => $baseDir . '/src/PhpAttribute/NodeFactory/PhpAttributeGroupFactory.php',

View File

@ -1535,6 +1535,7 @@ class ComposerStaticInit2d887a2f87c676eb32b3e04612865e54
'Rector\\Doctrine\\CodeQuality\\EntityMappingResolver' => __DIR__ . '/..' . '/rector/rector-doctrine/rules/CodeQuality/EntityMappingResolver.php',
'Rector\\Doctrine\\CodeQuality\\Enum\\EntityMappingKey' => __DIR__ . '/..' . '/rector/rector-doctrine/rules/CodeQuality/Enum/EntityMappingKey.php',
'Rector\\Doctrine\\CodeQuality\\Enum\\ToManyMappings' => __DIR__ . '/..' . '/rector/rector-doctrine/rules/CodeQuality/Enum/ToManyMappings.php',
'Rector\\Doctrine\\CodeQuality\\Helper\\NodeValueNormalizer' => __DIR__ . '/..' . '/rector/rector-doctrine/rules/CodeQuality/Helper/NodeValueNormalizer.php',
'Rector\\Doctrine\\CodeQuality\\NodeFactory\\ArrayItemNodeFactory' => __DIR__ . '/..' . '/rector/rector-doctrine/rules/CodeQuality/NodeFactory/ArrayItemNodeFactory.php',
'Rector\\Doctrine\\CodeQuality\\Rector\\Class_\\InitializeDefaultEntityCollectionRector' => __DIR__ . '/..' . '/rector/rector-doctrine/rules/CodeQuality/Rector/Class_/InitializeDefaultEntityCollectionRector.php',
'Rector\\Doctrine\\CodeQuality\\Rector\\Class_\\MoveCurrentDateTimeDefaultInEntityToConstructorRector' => __DIR__ . '/..' . '/rector/rector-doctrine/rules/CodeQuality/Rector/Class_/MoveCurrentDateTimeDefaultInEntityToConstructorRector.php',
@ -1553,6 +1554,7 @@ class ComposerStaticInit2d887a2f87c676eb32b3e04612865e54
'Rector\\Doctrine\\Dbal211\\Rector\\MethodCall\\ExtractArrayArgOnQueryBuilderSelectRector' => __DIR__ . '/..' . '/rector/rector-doctrine/rules/Dbal211/Rector/MethodCall/ExtractArrayArgOnQueryBuilderSelectRector.php',
'Rector\\Doctrine\\Dbal211\\Rector\\MethodCall\\ReplaceFetchAllMethodCallRector' => __DIR__ . '/..' . '/rector/rector-doctrine/rules/Dbal211/Rector/MethodCall/ReplaceFetchAllMethodCallRector.php',
'Rector\\Doctrine\\Dbal40\\Rector\\MethodCall\\ChangeCompositeExpressionAddMultipleWithWithRector' => __DIR__ . '/..' . '/rector/rector-doctrine/rules/Dbal40/Rector/MethodCall/ChangeCompositeExpressionAddMultipleWithWithRector.php',
'Rector\\Doctrine\\Enum\\MappingClass' => __DIR__ . '/..' . '/rector/rector-doctrine/src/Enum/MappingClass.php',
'Rector\\Doctrine\\NodeAnalyzer\\AttributeFinder' => __DIR__ . '/..' . '/rector/rector-doctrine/src/NodeAnalyzer/AttributeFinder.php',
'Rector\\Doctrine\\NodeAnalyzer\\AttrinationFinder' => __DIR__ . '/..' . '/rector/rector-doctrine/src/NodeAnalyzer/AttrinationFinder.php',
'Rector\\Doctrine\\NodeAnalyzer\\ConstructorAssignPropertyAnalyzer' => __DIR__ . '/..' . '/rector/rector-doctrine/src/NodeAnalyzer/ConstructorAssignPropertyAnalyzer.php',
@ -2146,7 +2148,6 @@ class ComposerStaticInit2d887a2f87c676eb32b3e04612865e54
'Rector\\PhpAttribute\\AttributeArrayNameInliner' => __DIR__ . '/../..' . '/src/PhpAttribute/AttributeArrayNameInliner.php',
'Rector\\PhpAttribute\\Contract\\AnnotationToAttributeMapperInterface' => __DIR__ . '/../..' . '/src/PhpAttribute/Contract/AnnotationToAttributeMapperInterface.php',
'Rector\\PhpAttribute\\Enum\\DocTagNodeState' => __DIR__ . '/../..' . '/src/PhpAttribute/Enum/DocTagNodeState.php',
'Rector\\PhpAttribute\\NodeAnalyzer\\ExprParameterReflectionTypeCorrector' => __DIR__ . '/../..' . '/src/PhpAttribute/NodeAnalyzer/ExprParameterReflectionTypeCorrector.php',
'Rector\\PhpAttribute\\NodeFactory\\AttributeNameFactory' => __DIR__ . '/../..' . '/src/PhpAttribute/NodeFactory/AttributeNameFactory.php',
'Rector\\PhpAttribute\\NodeFactory\\NamedArgsFactory' => __DIR__ . '/../..' . '/src/PhpAttribute/NodeFactory/NamedArgsFactory.php',
'Rector\\PhpAttribute\\NodeFactory\\PhpAttributeGroupFactory' => __DIR__ . '/../..' . '/src/PhpAttribute/NodeFactory/PhpAttributeGroupFactory.php',

View File

@ -1679,12 +1679,12 @@
"source": {
"type": "git",
"url": "https:\/\/github.com\/rectorphp\/rector-doctrine.git",
"reference": "68d0f86babbb722037f888a2fba7f53e521b777d"
"reference": "0858ab3d83ed66e57869c30ed4e577c8e028643b"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-doctrine\/zipball\/68d0f86babbb722037f888a2fba7f53e521b777d",
"reference": "68d0f86babbb722037f888a2fba7f53e521b777d",
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-doctrine\/zipball\/0858ab3d83ed66e57869c30ed4e577c8e028643b",
"reference": "0858ab3d83ed66e57869c30ed4e577c8e028643b",
"shasum": ""
},
"require": {
@ -1709,7 +1709,7 @@
"tomasvotruba\/unused-public": "^0.3",
"tracy\/tracy": "^2.10"
},
"time": "2024-02-14T14:33:16+00:00",
"time": "2024-02-14T16:57:40+00:00",
"default-branch": true,
"type": "rector-extension",
"extra": {

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,7 @@ namespace Rector\RectorInstaller;
*/
final class GeneratedConfig
{
public const EXTENSIONS = array('rector/rector-doctrine' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-doctrine', 'relative_install_path' => '../../rector-doctrine', 'extra' => NULL, 'version' => 'dev-main 68d0f86'), 'rector/rector-downgrade-php' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-downgrade-php', 'relative_install_path' => '../../rector-downgrade-php', 'extra' => NULL, 'version' => 'dev-main 8d1aab2'), 'rector/rector-phpunit' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-phpunit', 'relative_install_path' => '../../rector-phpunit', 'extra' => NULL, 'version' => 'dev-main cdbe390'), 'rector/rector-symfony' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-symfony', 'relative_install_path' => '../../rector-symfony', 'extra' => NULL, 'version' => 'dev-main 59edb62'));
public const EXTENSIONS = array('rector/rector-doctrine' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-doctrine', 'relative_install_path' => '../../rector-doctrine', 'extra' => NULL, 'version' => 'dev-main 0858ab3'), 'rector/rector-downgrade-php' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-downgrade-php', 'relative_install_path' => '../../rector-downgrade-php', 'extra' => NULL, 'version' => 'dev-main 8d1aab2'), 'rector/rector-phpunit' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-phpunit', 'relative_install_path' => '../../rector-phpunit', 'extra' => NULL, 'version' => 'dev-main cdbe390'), 'rector/rector-symfony' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-symfony', 'relative_install_path' => '../../rector-symfony', 'extra' => NULL, 'version' => 'dev-main 59edb62'));
private function __construct()
{
}

View File

@ -4,10 +4,10 @@ declare (strict_types=1);
namespace Rector\Doctrine\CodeQuality\AnnotationTransformer\ClassAnnotationTransformer;
use Rector\BetterPhpDocParser\PhpDoc\ArrayItemNode;
use Rector\BetterPhpDocParser\PhpDoc\StringNode;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\Doctrine\CodeQuality\Contract\ClassAnnotationTransformerInterface;
use Rector\Doctrine\CodeQuality\DocTagNodeFactory;
use Rector\Doctrine\CodeQuality\Helper\NodeValueNormalizer;
use Rector\Doctrine\CodeQuality\Utils\CaseStringHelper;
use Rector\Doctrine\CodeQuality\ValueObject\EntityMapping;
final class SoftDeletableClassAnnotationTransformer implements ClassAnnotationTransformerInterface
@ -38,9 +38,10 @@ final class SoftDeletableClassAnnotationTransformer implements ClassAnnotationTr
private function createArrayItemNodes(array $softDeletableMapping) : array
{
$arrayItemNodes = [];
foreach ($softDeletableMapping as $fieldKey => $fieldValue) {
$camelCaseFieldKey = CaseStringHelper::camelCase($fieldKey);
$arrayItemNodes[] = new ArrayItemNode(new StringNode($fieldValue), $camelCaseFieldKey);
foreach ($softDeletableMapping as $fieldKey => $fieldValueNode) {
$fieldKey = CaseStringHelper::camelCase($fieldKey);
$fieldValueNode = NodeValueNormalizer::normalize($fieldValueNode);
$arrayItemNodes[] = new ArrayItemNode($fieldValueNode, $fieldKey);
}
return $arrayItemNodes;
}

View File

@ -18,6 +18,10 @@ final class TableClassAnnotationTransformer implements ClassAnnotationTransforme
* @var string
*/
private const TABLE_KEY = 'table';
/**
* @var string
*/
private const UNIQUE_CONSTRAINTS_CLASS = 'Doctrine\\ORM\\Mapping\\UniqueConstraint';
public function transform(EntityMapping $entityMapping, PhpDocInfo $classPhpDocInfo) : void
{
$classMapping = $entityMapping->getClassMapping();
@ -38,7 +42,7 @@ final class TableClassAnnotationTransformer implements ClassAnnotationTransforme
$columnArrayItems[] = new ArrayItemNode(new StringNode($column));
}
$columnCurlList = new CurlyListNode($columnArrayItems);
$uniqueConstraintDoctrineAnnotationTagValueNodes[] = new ArrayItemNode(new DoctrineAnnotationTagValueNode(new IdentifierTypeNode('@\\Doctrine\\ORM\\Mapping\\UniqueConstraint'), null, [new ArrayItemNode(new StringNode($name), 'name'), new ArrayItemNode($columnCurlList, 'columns')]));
$uniqueConstraintDoctrineAnnotationTagValueNodes[] = new ArrayItemNode(new DoctrineAnnotationTagValueNode(new IdentifierTypeNode('@\\' . self::UNIQUE_CONSTRAINTS_CLASS), null, [new ArrayItemNode(new StringNode($name), 'name'), new ArrayItemNode($columnCurlList, 'columns')]));
}
$arrayItemNodes[] = new ArrayItemNode(new CurlyListNode($uniqueConstraintDoctrineAnnotationTagValueNodes), 'uniqueConstraints');
}

View File

@ -10,6 +10,7 @@ use Rector\Doctrine\CodeQuality\DocTagNodeFactory;
use Rector\Doctrine\CodeQuality\Enum\EntityMappingKey;
use Rector\Doctrine\CodeQuality\NodeFactory\ArrayItemNodeFactory;
use Rector\Doctrine\CodeQuality\ValueObject\EntityMapping;
use Rector\Doctrine\Enum\MappingClass;
final class ColumnAnnotationTransformer implements PropertyAnnotationTransformerInterface
{
/**
@ -38,6 +39,6 @@ final class ColumnAnnotationTransformer implements PropertyAnnotationTransformer
}
public function getClassName() : string
{
return 'Doctrine\\ORM\\Mapping\\Column';
return MappingClass::COLUMN;
}
}

View File

@ -10,6 +10,7 @@ use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\Doctrine\CodeQuality\Contract\PropertyAnnotationTransformerInterface;
use Rector\Doctrine\CodeQuality\DocTagNodeFactory;
use Rector\Doctrine\CodeQuality\ValueObject\EntityMapping;
use Rector\Doctrine\Enum\MappingClass;
final class IdColumnAnnotationTransformer implements PropertyAnnotationTransformerInterface
{
public function transform(EntityMapping $entityMapping, PhpDocInfo $propertyPhpDocInfo, Property $property) : void
@ -28,6 +29,6 @@ final class IdColumnAnnotationTransformer implements PropertyAnnotationTransform
}
public function getClassName() : string
{
return 'Doctrine\\ORM\\Mapping\\Column';
return MappingClass::COLUMN;
}
}

View File

@ -8,5 +8,5 @@ use Rector\Doctrine\CodeQuality\ValueObject\EntityMapping;
interface ClassAnnotationTransformerInterface
{
public function getClassName() : string;
public function transform(EntityMapping $entityMapping, PhpDocInfo $propertyPhpDocInfo) : void;
public function transform(EntityMapping $entityMapping, PhpDocInfo $classPhpDocInfo) : void;
}

View File

@ -0,0 +1,23 @@
<?php
declare (strict_types=1);
namespace Rector\Doctrine\CodeQuality\Helper;
use Rector\BetterPhpDocParser\PhpDoc\StringNode;
final class NodeValueNormalizer
{
/**
* @param mixed $value
* @return mixed
*/
public static function normalize($value)
{
if (\is_bool($value)) {
return $value ? 'true' : 'false';
}
if (\is_numeric($value)) {
return $value;
}
return new StringNode($value);
}
}

View File

@ -7,6 +7,7 @@ use Rector\BetterPhpDocParser\PhpDoc\ArrayItemNode;
use Rector\BetterPhpDocParser\PhpDoc\StringNode;
use Rector\BetterPhpDocParser\ValueObject\PhpDoc\DoctrineAnnotation\CurlyListNode;
use Rector\Doctrine\CodeQuality\Enum\EntityMappingKey;
use Rector\Doctrine\CodeQuality\Helper\NodeValueNormalizer;
use RectorPrefix202402\Webmozart\Assert\Assert;
final class ArrayItemNodeFactory
{
@ -19,7 +20,7 @@ final class ArrayItemNodeFactory
*
* @var string[]
*/
private const EXTENSION_KEYS = ['gedmo'];
private const EXTENSION_KEYS = ['gedmo', 'joinColumns'];
/**
* @param array<string, mixed> $propertyMapping
* @return ArrayItemNode[]
@ -42,24 +43,11 @@ final class ArrayItemNodeFactory
if (\in_array($fieldKey, self::EXTENSION_KEYS, \true)) {
continue;
}
// special case for separate entity
if ($fieldKey === 'joinColumns') {
continue;
}
if (\is_array($fieldValue)) {
$fieldValueArrayItemNodes = [];
foreach ($fieldValue as $fieldSingleKey => $fieldSingleValue) {
if (\is_numeric($fieldSingleValue)) {
$fieldSingleValue = (string) $fieldSingleValue;
$fieldArrayItemNode = new ArrayItemNode($fieldSingleValue, new StringNode($fieldSingleKey));
} elseif (\is_bool($fieldSingleValue)) {
$fieldSingleValue = $fieldSingleValue ? 'true' : 'false';
$fieldArrayItemNode = new ArrayItemNode($fieldSingleValue, new StringNode($fieldSingleKey));
} elseif (\is_string($fieldSingleKey)) {
$fieldArrayItemNode = new ArrayItemNode(new StringNode($fieldSingleValue), new StringNode($fieldSingleKey));
} else {
$fieldArrayItemNode = new ArrayItemNode(new StringNode($fieldSingleValue));
}
$fieldSingleNode = NodeValueNormalizer::normalize($fieldSingleValue);
$fieldArrayItemNode = new ArrayItemNode($fieldSingleNode, \is_string($fieldSingleKey) ? new StringNode($fieldSingleKey) : null);
$fieldValueArrayItemNodes[] = $fieldArrayItemNode;
}
$arrayItemNodes[] = new ArrayItemNode(new CurlyListNode($fieldValueArrayItemNodes), $fieldKey);
@ -77,6 +65,7 @@ final class ArrayItemNodeFactory
$arrayItemNodes[] = new ArrayItemNode(new StringNode($fieldValue), $fieldKey);
continue;
}
$fieldValue = NodeValueNormalizer::normalize($fieldValue);
$arrayItemNodes[] = new ArrayItemNode($fieldValue, $fieldKey);
}
return $arrayItemNodes;

View File

@ -17,6 +17,7 @@ use Rector\BetterPhpDocParser\PhpDoc\ArrayItemNode;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
use Rector\BetterPhpDocParser\PhpDoc\StringNode;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
use Rector\Doctrine\Enum\MappingClass;
use Rector\Exception\NotImplementedYetException;
use Rector\PhpParser\Node\Value\ValueResolver;
use Rector\Rector\AbstractRector;
@ -87,7 +88,7 @@ CODE_SAMPLE
public function refactor(Node $node) : ?Node
{
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
$doctrineAnnotationTagValueNode = $phpDocInfo->getByAnnotationClass('Doctrine\\ORM\\Mapping\\Column');
$doctrineAnnotationTagValueNode = $phpDocInfo->getByAnnotationClass(MappingClass::COLUMN);
if (!$doctrineAnnotationTagValueNode instanceof DoctrineAnnotationTagValueNode) {
return null;
}

View File

@ -0,0 +1,12 @@
<?php
declare (strict_types=1);
namespace Rector\Doctrine\Enum;
final class MappingClass
{
/**
* @var string
*/
public const COLUMN = 'Doctrine\\ORM\\Mapping\\Column';
}

View File

@ -12,6 +12,7 @@ use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Property;
use Rector\Doctrine\Enum\MappingClass;
use Rector\NodeNameResolver\NodeNameResolver;
/**
* @api
@ -28,7 +29,7 @@ final class AttributeFinder
$this->nodeNameResolver = $nodeNameResolver;
}
/**
* @param class-string $attributeClass
* @param MappingClass::* $attributeClass
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Property|\PhpParser\Node\Stmt\ClassLike|\PhpParser\Node\Param $node
*/
public function findAttributeByClassArgByName($node, string $attributeClass, string $argName) : ?Expr

View File

@ -18,6 +18,7 @@ use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
use Rector\BetterPhpDocParser\PhpDoc\StringNode;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
use Rector\Doctrine\Enum\MappingClass;
use Rector\Doctrine\NodeAnalyzer\AttributeFinder;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
final class ColumnPropertyTypeResolver
@ -46,10 +47,6 @@ final class ColumnPropertyTypeResolver
* @var string
*/
private const DATE_TIME_INTERFACE = 'DateTimeInterface';
/**
* @var string
*/
private const COLUMN_CLASS = 'Doctrine\\ORM\\Mapping\\Column';
/**
* @param array<string, Type> $doctrineTypeToScalarType
* @see https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/basic-mapping.html#doctrine-mapping-types
@ -100,7 +97,7 @@ final class ColumnPropertyTypeResolver
}
public function resolve(Property $property, bool $isNullable) : ?Type
{
$expr = $this->attributeFinder->findAttributeByClassArgByName($property, self::COLUMN_CLASS, 'type');
$expr = $this->attributeFinder->findAttributeByClassArgByName($property, MappingClass::COLUMN, 'type');
if ($expr instanceof String_) {
return $this->createPHPStanTypeFromDoctrineStringType($expr->value, $isNullable);
}
@ -109,7 +106,7 @@ final class ColumnPropertyTypeResolver
}
private function resolveFromPhpDocInfo(PhpDocInfo $phpDocInfo, bool $isNullable) : ?\PHPStan\Type\Type
{
$doctrineAnnotationTagValueNode = $phpDocInfo->findOneByAnnotationClass(self::COLUMN_CLASS);
$doctrineAnnotationTagValueNode = $phpDocInfo->findOneByAnnotationClass(MappingClass::COLUMN);
if (!$doctrineAnnotationTagValueNode instanceof DoctrineAnnotationTagValueNode) {
return null;
}

View File

@ -10,6 +10,7 @@ use Rector\BetterPhpDocParser\PhpDoc\ArrayItemNode;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
use Rector\Doctrine\Enum\MappingClass;
use Rector\Doctrine\NodeAnalyzer\AttributeFinder;
use Rector\PhpParser\Node\Value\ValueResolver;
final class NullabilityColumnPropertyTypeResolver
@ -44,7 +45,7 @@ final class NullabilityColumnPropertyTypeResolver
}
public function isNullable(Property $property) : bool
{
$nullableExpr = $this->attributeFinder->findAttributeByClassArgByName($property, self::COLUMN_CLASS, 'nullable');
$nullableExpr = $this->attributeFinder->findAttributeByClassArgByName($property, MappingClass::COLUMN, 'nullable');
if ($nullableExpr instanceof Expr) {
return $this->valueResolver->isTrue($nullableExpr);
}