classAnnotationMatcher = $classAnnotationMatcher; } /** * Covers annotations like @ORM, @Serializer, @Assert etc * See https://github.com/rectorphp/rector/issues/1872 * * @param string[] $oldToNewClasses */ public function changeTypeInAnnotationTypes(Node $node, PhpDocInfo $phpDocInfo, array $oldToNewClasses, bool &$hasChanged) : bool { $this->processAssertChoiceTagValueNode($oldToNewClasses, $phpDocInfo, $hasChanged); $this->processDoctrineRelationTagValueNode($node, $oldToNewClasses, $phpDocInfo, $hasChanged); $this->processSerializerTypeTagValueNode($oldToNewClasses, $phpDocInfo, $hasChanged); return $hasChanged; } /** * @param array $oldToNewClasses */ private function processAssertChoiceTagValueNode(array $oldToNewClasses, PhpDocInfo $phpDocInfo, bool &$hasChanged) : void { $assertChoiceDoctrineAnnotationTagValueNode = $phpDocInfo->findOneByAnnotationClass('Symfony\\Component\\Validator\\Constraints\\Choice'); if (!$assertChoiceDoctrineAnnotationTagValueNode instanceof DoctrineAnnotationTagValueNode) { return; } $callbackArrayItemNode = $assertChoiceDoctrineAnnotationTagValueNode->getValue('callback'); if (!$callbackArrayItemNode instanceof ArrayItemNode) { return; } $callbackClass = $callbackArrayItemNode->value; // array is needed for callable if (!$callbackClass instanceof CurlyListNode) { return; } $callableCallbackArrayItems = $callbackClass->getValues(); $classNameArrayItemNode = $callableCallbackArrayItems[0]; $classNameStringNode = $classNameArrayItemNode->value; if (!$classNameStringNode instanceof StringNode) { return; } foreach ($oldToNewClasses as $oldClass => $newClass) { if ($classNameStringNode->value !== $oldClass) { continue; } $classNameStringNode->value = $newClass; // trigger reprint $classNameArrayItemNode->setAttribute(PhpDocAttributeKey::ORIG_NODE, null); $hasChanged = \true; break; } } /** * @param array $oldToNewClasses */ private function processDoctrineRelationTagValueNode(Node $node, array $oldToNewClasses, PhpDocInfo $phpDocInfo, bool &$hasChanged) : void { $doctrineAnnotationTagValueNode = $phpDocInfo->getByAnnotationClasses(['Doctrine\\ORM\\Mapping\\OneToMany', 'Doctrine\\ORM\\Mapping\\ManyToMany', 'Doctrine\\ORM\\Mapping\\Embedded']); if (!$doctrineAnnotationTagValueNode instanceof DoctrineAnnotationTagValueNode) { return; } $this->processDoctrineToMany($doctrineAnnotationTagValueNode, $node, $oldToNewClasses, $hasChanged); } /** * @param array $oldToNewClasses */ private function processSerializerTypeTagValueNode(array $oldToNewClasses, PhpDocInfo $phpDocInfo, bool &$hasChanged) : void { $doctrineAnnotationTagValueNode = $phpDocInfo->findOneByAnnotationClass('JMS\\Serializer\\Annotation\\Type'); if (!$doctrineAnnotationTagValueNode instanceof DoctrineAnnotationTagValueNode) { return; } $classNameArrayItemNode = $doctrineAnnotationTagValueNode->getSilentValue(); foreach ($oldToNewClasses as $oldClass => $newClass) { if ($classNameArrayItemNode instanceof ArrayItemNode && $classNameArrayItemNode->value instanceof StringNode) { $classNameStringNode = $classNameArrayItemNode->value; if ($classNameStringNode->value === $oldClass) { $classNameStringNode->value = $newClass; continue; } $classNameStringNode->value = Strings::replace($classNameStringNode->value, '#\\b' . \preg_quote($oldClass, '#') . '\\b#', $newClass); $classNameArrayItemNode->setAttribute(PhpDocAttributeKey::ORIG_NODE, null); $hasChanged = \true; } $currentTypeArrayItemNode = $doctrineAnnotationTagValueNode->getValue('type'); if (!$currentTypeArrayItemNode instanceof ArrayItemNode) { continue; } $currentTypeStringNode = $currentTypeArrayItemNode->value; if (!$currentTypeStringNode instanceof StringNode) { continue; } if ($currentTypeStringNode->value === $oldClass) { $currentTypeStringNode->value = $newClass; $hasChanged = \true; } } } /** * @param array $oldToNewClasses */ private function processDoctrineToMany(DoctrineAnnotationTagValueNode $doctrineAnnotationTagValueNode, Node $node, array $oldToNewClasses, bool &$hasChanged) : void { $classKey = $doctrineAnnotationTagValueNode->hasClassName('Doctrine\\ORM\\Mapping\\Embedded') ? 'class' : 'targetEntity'; $targetEntityArrayItemNode = $doctrineAnnotationTagValueNode->getValue($classKey); if (!$targetEntityArrayItemNode instanceof ArrayItemNode) { return; } $targetEntityStringNode = $targetEntityArrayItemNode->value; if (!$targetEntityStringNode instanceof StringNode) { return; } $targetEntityClass = $targetEntityStringNode->value; // resolve to FQN $tagFullyQualifiedName = $this->classAnnotationMatcher->resolveTagFullyQualifiedName($targetEntityClass, $node); foreach ($oldToNewClasses as $oldClass => $newClass) { if ($tagFullyQualifiedName !== $oldClass) { continue; } $targetEntityStringNode->value = $newClass; $targetEntityArrayItemNode->setAttribute(PhpDocAttributeKey::ORIG_NODE, null); $hasChanged = \true; } } }