2021-05-10 00:23:30 +00:00
< ? php
declare ( strict_types = 1 );
2022-06-06 17:12:56 +00:00
namespace Rector\Symfony\Rector\ClassMethod ;
2021-05-10 00:23:30 +00:00
2022-06-06 17:12:56 +00:00
use PhpParser\Node ;
2023-03-30 09:04:49 +00:00
use PhpParser\Node\Expr ;
2022-06-06 17:12:56 +00:00
use PhpParser\Node\Scalar\String_ ;
use PhpParser\Node\Stmt\Class_ ;
use PhpParser\Node\Stmt\ClassMethod ;
use PhpParser\Node\Stmt\Return_ ;
use PHPStan\Type\ObjectType ;
use Rector\Core\Rector\AbstractRector ;
use Rector\Symfony\FormHelper\FormTypeStringToTypeProvider ;
2022-06-07 09:18:30 +00:00
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample ;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition ;
2021-05-10 00:23:30 +00:00
/**
* @ see \Rector\Symfony\Tests\Rector\ClassMethod\FormTypeGetParentRector\FormTypeGetParentRectorTest
*/
2022-06-07 08:22:29 +00:00
final class FormTypeGetParentRector extends AbstractRector
2021-05-10 00:23:30 +00:00
{
/**
2023-06-11 23:01:39 +00:00
* @ readonly
2021-05-15 08:37:15 +00:00
* @ var \Rector\Symfony\FormHelper\FormTypeStringToTypeProvider
2021-05-10 00:23:30 +00:00
*/
private $formTypeStringToTypeProvider ;
2022-06-07 08:22:29 +00:00
public function __construct ( FormTypeStringToTypeProvider $formTypeStringToTypeProvider )
2021-05-10 00:23:30 +00:00
{
$this -> formTypeStringToTypeProvider = $formTypeStringToTypeProvider ;
}
2022-06-07 08:22:29 +00:00
public function getRuleDefinition () : RuleDefinition
2021-05-10 00:23:30 +00:00
{
2022-06-07 08:22:29 +00:00
return new RuleDefinition ( 'Turns string Form Type references to their CONSTANT alternatives in `getParent()` and `getExtendedType()` methods in Form in Symfony' , [ new CodeSample ( <<< 'CODE_SAMPLE'
2021-05-10 00:23:30 +00:00
use Symfony\Component\Form\AbstractType ;
class SomeType extends AbstractType
{
public function getParent ()
{
return 'collection' ;
}
}
CODE_SAMPLE
, <<< 'CODE_SAMPLE'
use Symfony\Component\Form\AbstractType ;
class SomeType extends AbstractType
{
public function getParent ()
{
return \Symfony\Component\Form\Extension\Core\Type\CollectionType :: class ;
}
}
CODE_SAMPLE
2022-06-07 08:22:29 +00:00
), new CodeSample ( <<< 'CODE_SAMPLE'
2021-05-10 00:23:30 +00:00
use Symfony\Component\Form\AbstractTypeExtension ;
class SomeExtension extends AbstractTypeExtension
{
public function getExtendedType ()
{
return 'collection' ;
}
}
CODE_SAMPLE
, <<< 'CODE_SAMPLE'
use Symfony\Component\Form\AbstractTypeExtension ;
class SomeExtension extends AbstractTypeExtension
{
public function getExtendedType ()
{
return \Symfony\Component\Form\Extension\Core\Type\CollectionType :: class ;
}
}
CODE_SAMPLE
)]);
}
/**
* @ return array < class - string < Node >>
*/
public function getNodeTypes () : array
{
2023-06-16 03:34:15 +00:00
return [ Class_ :: class ];
2021-05-10 00:23:30 +00:00
}
/**
2023-06-16 03:34:15 +00:00
* @ param Class_ $node
2021-05-10 00:23:30 +00:00
*/
2022-06-07 08:22:29 +00:00
public function refactor ( Node $node ) : ? Node
2021-05-10 00:23:30 +00:00
{
2023-06-16 03:34:15 +00:00
$hasChanged = \false ;
foreach ( $node -> getMethods () as $classMethod ) {
if ( ! $this -> isClassAndMethodMatch ( $node , $classMethod )) {
continue ;
2021-05-10 00:23:30 +00:00
}
2023-06-16 03:34:15 +00:00
$this -> traverseNodesWithCallable (( array ) $classMethod -> stmts , function ( Node $node ) use ( & $hasChanged ) : ? Node {
if ( ! $node instanceof Return_ ) {
return null ;
}
if ( ! $node -> expr instanceof Expr ) {
return null ;
}
if ( ! $node -> expr instanceof String_ ) {
return null ;
}
$this -> replaceStringWIthFormTypeClassConstIfFound ( $node -> expr -> value , $node , $hasChanged );
return $node ;
});
}
if ( $hasChanged ) {
2021-05-10 00:23:30 +00:00
return $node ;
2023-06-16 03:34:15 +00:00
}
2021-05-10 00:23:30 +00:00
return null ;
}
2023-06-16 03:34:15 +00:00
private function isClassAndMethodMatch ( Class_ $class , ClassMethod $classMethod ) : bool
2021-05-10 00:23:30 +00:00
{
2023-03-22 14:20:22 +00:00
if ( $this -> isName ( $classMethod -> name , 'getParent' )) {
return $this -> isObjectType ( $class , new ObjectType ( 'Symfony\\Component\\Form\\AbstractType' ));
2021-05-10 00:23:30 +00:00
}
2023-03-22 14:20:22 +00:00
if ( $this -> isName ( $classMethod -> name , 'getExtendedType' )) {
return $this -> isObjectType ( $classMethod , new ObjectType ( 'Symfony\\Component\\Form\\AbstractTypeExtension' ));
2021-05-10 00:23:30 +00:00
}
return \false ;
}
2023-06-16 03:34:15 +00:00
private function replaceStringWIthFormTypeClassConstIfFound ( string $stringValue , Return_ $return , bool & $hasChanged ) : void
2021-05-10 00:23:30 +00:00
{
$formClass = $this -> formTypeStringToTypeProvider -> matchClassForNameWithPrefix ( $stringValue );
if ( $formClass === null ) {
return ;
}
$return -> expr = $this -> nodeFactory -> createClassConstReference ( $formClass );
2023-06-16 03:34:15 +00:00
$hasChanged = \true ;
2021-05-10 00:23:30 +00:00
}
}