Updated Rector to commit 56e1633c826c009e643873ca8461ea45d0fff217

56e1633c82 [TypeMapper] Use Identifier instead of Name on ObjectWithoutClassType (#3377)
This commit is contained in:
Tomas Votruba 2023-02-14 11:52:01 +00:00
parent 17071f1320
commit 90ca96064c
17 changed files with 148 additions and 84 deletions

View File

@ -4,6 +4,7 @@ declare (strict_types=1);
namespace Rector\PHPStanStaticTypeMapper\TypeMapper;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\Reflection\ReflectionProvider;
@ -81,22 +82,22 @@ final class IntersectionTypeMapper implements TypeMapperInterface
$intersectionedTypeNodes = [];
foreach ($type->getTypes() as $intersectionedType) {
$resolvedType = $this->phpStanStaticTypeMapper->mapToPhpParserNode($intersectionedType, $typeKind);
if (!$resolvedType instanceof Name) {
continue;
if (!$resolvedType instanceof Name && !$resolvedType instanceof Identifier) {
return null;
}
$resolvedTypeName = (string) $resolvedType;
/**
* ObjectWithoutClassType can happen when use along with \PHPStan\Type\Accessory\HasMethodType
* Use "object" as returned type
*/
if ($intersectionedType instanceof ObjectWithoutClassType) {
return $resolvedType;
}
/**
* $this->reflectionProvider->hasClass($resolvedTypeName) returns true on iterable type
* this ensure type is ObjectType early
*/
if (!$intersectionedType instanceof ObjectType) {
continue;
return null;
}
if (!$this->reflectionProvider->hasClass($resolvedTypeName)) {
continue;
return null;
}
$intersectionedTypeNodes[] = $resolvedType;
}

View File

@ -4,7 +4,7 @@ declare (strict_types=1);
namespace Rector\PHPStanStaticTypeMapper\TypeMapper;
use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name\FullyQualified;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
@ -77,6 +77,6 @@ final class ObjectWithoutClassTypeMapper implements TypeMapperInterface
if (!$this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::OBJECT_TYPE)) {
return null;
}
return new Name('object');
return new Identifier('object');
}
}

View File

@ -179,7 +179,7 @@ CODE_SAMPLE
if (!$this->unionTypeAnalyzer->hasObjectWithoutClassTypeWithOnlyFullyQualifiedObjectType($unionType)) {
return;
}
$param->type = new Name('object');
$param->type = new Identifier('object');
$this->hasChanged = \true;
}
/**

View File

@ -19,12 +19,12 @@ final class VersionResolver
* @api
* @var string
*/
public const PACKAGE_VERSION = 'dbaf0da38ac23091d39d4df71749da474e8df8ac';
public const PACKAGE_VERSION = '56e1633c826c009e643873ca8461ea45d0fff217';
/**
* @api
* @var string
*/
public const RELEASE_DATE = '2023-02-13 14:38:25';
public const RELEASE_DATE = '2023-02-14 18:47:40';
/**
* @var int
*/

2
vendor/autoload.php vendored
View File

@ -22,4 +22,4 @@ if (PHP_VERSION_ID < 50600) {
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitad4ca5488857da5d6b19f9f67543231d::getLoader();
return ComposerAutoloaderInit51c34ff907724dd47bf3dc3a0bf543c6::getLoader();

View File

@ -2512,6 +2512,7 @@ return array(
'Rector\\Symfony\\NodeAnalyzer\\Annotations\\MethodCallAnnotationAssertResolver' => $vendorDir . '/rector/rector-symfony/src/NodeAnalyzer/Annotations/MethodCallAnnotationAssertResolver.php',
'Rector\\Symfony\\NodeAnalyzer\\Annotations\\PropertyAnnotationAssertResolver' => $vendorDir . '/rector/rector-symfony/src/NodeAnalyzer/Annotations/PropertyAnnotationAssertResolver.php',
'Rector\\Symfony\\NodeAnalyzer\\Annotations\\StmtMethodCallMatcher' => $vendorDir . '/rector/rector-symfony/src/NodeAnalyzer/Annotations/StmtMethodCallMatcher.php',
'Rector\\Symfony\\NodeAnalyzer\\ClassAnalyzer' => $vendorDir . '/rector/rector-symfony/src/NodeAnalyzer/ClassAnalyzer.php',
'Rector\\Symfony\\NodeAnalyzer\\DependencyInjectionMethodCallAnalyzer' => $vendorDir . '/rector/rector-symfony/src/NodeAnalyzer/DependencyInjectionMethodCallAnalyzer.php',
'Rector\\Symfony\\NodeAnalyzer\\FormAddMethodCallAnalyzer' => $vendorDir . '/rector/rector-symfony/src/NodeAnalyzer/FormAddMethodCallAnalyzer.php',
'Rector\\Symfony\\NodeAnalyzer\\FormCollectionAnalyzer' => $vendorDir . '/rector/rector-symfony/src/NodeAnalyzer/FormCollectionAnalyzer.php',
@ -2543,6 +2544,7 @@ return array(
'Rector\\Symfony\\NodeFactory\\RequiredClassMethodFactory' => $vendorDir . '/rector/rector-symfony/src/NodeFactory/RequiredClassMethodFactory.php',
'Rector\\Symfony\\NodeFactory\\ThisRenderFactory' => $vendorDir . '/rector/rector-symfony/src/NodeFactory/ThisRenderFactory.php',
'Rector\\Symfony\\NodeFinder\\EmptyReturnNodeFinder' => $vendorDir . '/rector/rector-symfony/src/NodeFinder/EmptyReturnNodeFinder.php',
'Rector\\Symfony\\NodeManipulator\\ClassManipulator' => $vendorDir . '/rector/rector-symfony/src/NodeManipulator/ClassManipulator.php',
'Rector\\Symfony\\NodeRemover\\ConstructorDependencyRemover' => $vendorDir . '/rector/rector-symfony/src/NodeRemover/ConstructorDependencyRemover.php',
'Rector\\Symfony\\PhpDocNode\\SymfonyRouteTagValueNodeFactory' => $vendorDir . '/rector/rector-symfony/src/PhpDocNode/SymfonyRouteTagValueNodeFactory.php',
'Rector\\Symfony\\Printer\\NeighbourClassLikePrinter' => $vendorDir . '/rector/rector-symfony/src/Printer/NeighbourClassLikePrinter.php',

View File

@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitad4ca5488857da5d6b19f9f67543231d
class ComposerAutoloaderInit51c34ff907724dd47bf3dc3a0bf543c6
{
private static $loader;
@ -22,17 +22,17 @@ class ComposerAutoloaderInitad4ca5488857da5d6b19f9f67543231d
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInitad4ca5488857da5d6b19f9f67543231d', 'loadClassLoader'), true, true);
spl_autoload_register(array('ComposerAutoloaderInit51c34ff907724dd47bf3dc3a0bf543c6', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInitad4ca5488857da5d6b19f9f67543231d', 'loadClassLoader'));
spl_autoload_unregister(array('ComposerAutoloaderInit51c34ff907724dd47bf3dc3a0bf543c6', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitad4ca5488857da5d6b19f9f67543231d::getInitializer($loader));
call_user_func(\Composer\Autoload\ComposerStaticInit51c34ff907724dd47bf3dc3a0bf543c6::getInitializer($loader));
$loader->setClassMapAuthoritative(true);
$loader->register(true);
$filesToLoad = \Composer\Autoload\ComposerStaticInitad4ca5488857da5d6b19f9f67543231d::$files;
$filesToLoad = \Composer\Autoload\ComposerStaticInit51c34ff907724dd47bf3dc3a0bf543c6::$files;
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;

View File

@ -4,7 +4,7 @@
namespace Composer\Autoload;
class ComposerStaticInitad4ca5488857da5d6b19f9f67543231d
class ComposerStaticInit51c34ff907724dd47bf3dc3a0bf543c6
{
public static $files = array (
'ad155f8f1cf0d418fe49e248db8c661b' => __DIR__ . '/..' . '/react/promise/src/functions_include.php',
@ -2759,6 +2759,7 @@ class ComposerStaticInitad4ca5488857da5d6b19f9f67543231d
'Rector\\Symfony\\NodeAnalyzer\\Annotations\\MethodCallAnnotationAssertResolver' => __DIR__ . '/..' . '/rector/rector-symfony/src/NodeAnalyzer/Annotations/MethodCallAnnotationAssertResolver.php',
'Rector\\Symfony\\NodeAnalyzer\\Annotations\\PropertyAnnotationAssertResolver' => __DIR__ . '/..' . '/rector/rector-symfony/src/NodeAnalyzer/Annotations/PropertyAnnotationAssertResolver.php',
'Rector\\Symfony\\NodeAnalyzer\\Annotations\\StmtMethodCallMatcher' => __DIR__ . '/..' . '/rector/rector-symfony/src/NodeAnalyzer/Annotations/StmtMethodCallMatcher.php',
'Rector\\Symfony\\NodeAnalyzer\\ClassAnalyzer' => __DIR__ . '/..' . '/rector/rector-symfony/src/NodeAnalyzer/ClassAnalyzer.php',
'Rector\\Symfony\\NodeAnalyzer\\DependencyInjectionMethodCallAnalyzer' => __DIR__ . '/..' . '/rector/rector-symfony/src/NodeAnalyzer/DependencyInjectionMethodCallAnalyzer.php',
'Rector\\Symfony\\NodeAnalyzer\\FormAddMethodCallAnalyzer' => __DIR__ . '/..' . '/rector/rector-symfony/src/NodeAnalyzer/FormAddMethodCallAnalyzer.php',
'Rector\\Symfony\\NodeAnalyzer\\FormCollectionAnalyzer' => __DIR__ . '/..' . '/rector/rector-symfony/src/NodeAnalyzer/FormCollectionAnalyzer.php',
@ -2790,6 +2791,7 @@ class ComposerStaticInitad4ca5488857da5d6b19f9f67543231d
'Rector\\Symfony\\NodeFactory\\RequiredClassMethodFactory' => __DIR__ . '/..' . '/rector/rector-symfony/src/NodeFactory/RequiredClassMethodFactory.php',
'Rector\\Symfony\\NodeFactory\\ThisRenderFactory' => __DIR__ . '/..' . '/rector/rector-symfony/src/NodeFactory/ThisRenderFactory.php',
'Rector\\Symfony\\NodeFinder\\EmptyReturnNodeFinder' => __DIR__ . '/..' . '/rector/rector-symfony/src/NodeFinder/EmptyReturnNodeFinder.php',
'Rector\\Symfony\\NodeManipulator\\ClassManipulator' => __DIR__ . '/..' . '/rector/rector-symfony/src/NodeManipulator/ClassManipulator.php',
'Rector\\Symfony\\NodeRemover\\ConstructorDependencyRemover' => __DIR__ . '/..' . '/rector/rector-symfony/src/NodeRemover/ConstructorDependencyRemover.php',
'Rector\\Symfony\\PhpDocNode\\SymfonyRouteTagValueNodeFactory' => __DIR__ . '/..' . '/rector/rector-symfony/src/PhpDocNode/SymfonyRouteTagValueNodeFactory.php',
'Rector\\Symfony\\Printer\\NeighbourClassLikePrinter' => __DIR__ . '/..' . '/rector/rector-symfony/src/Printer/NeighbourClassLikePrinter.php',
@ -3099,9 +3101,9 @@ class ComposerStaticInitad4ca5488857da5d6b19f9f67543231d
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInitad4ca5488857da5d6b19f9f67543231d::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitad4ca5488857da5d6b19f9f67543231d::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInitad4ca5488857da5d6b19f9f67543231d::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInit51c34ff907724dd47bf3dc3a0bf543c6::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit51c34ff907724dd47bf3dc3a0bf543c6::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit51c34ff907724dd47bf3dc3a0bf543c6::$classMap;
}, null, ClassLoader::class);
}

View File

@ -2054,12 +2054,12 @@
"source": {
"type": "git",
"url": "https:\/\/github.com\/rectorphp\/rector-symfony.git",
"reference": "18914c204c14d245f8bbd657165821cde1bd5fc6"
"reference": "a82d4c2fbd277c31c51518c4b7142a5cb4cdf06c"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-symfony\/zipball\/18914c204c14d245f8bbd657165821cde1bd5fc6",
"reference": "18914c204c14d245f8bbd657165821cde1bd5fc6",
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-symfony\/zipball\/a82d4c2fbd277c31c51518c4b7142a5cb4cdf06c",
"reference": "a82d4c2fbd277c31c51518c4b7142a5cb4cdf06c",
"shasum": ""
},
"require": {
@ -2089,7 +2089,7 @@
"tomasvotruba\/type-coverage": "^0.0.9",
"tomasvotruba\/unused-public": "^0.0.34"
},
"time": "2023-02-13T16:10:52+00:00",
"time": "2023-02-13T21:48:08+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/vendor/rector/rector-doctrine', 'relative_install_path' => '../../rector-doctrine', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main ea9cf46'), 'rector/rector-downgrade-php' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-downgrade-php', 'relative_install_path' => '../../rector-downgrade-php', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main fc1c39f'), 'rector/rector-phpunit' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-phpunit', 'relative_install_path' => '../../rector-phpunit', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main 13e842b'), 'rector/rector-symfony' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-symfony', 'relative_install_path' => '../../rector-symfony', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main 18914c2'));
public const EXTENSIONS = array('rector/rector-doctrine' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-doctrine', 'relative_install_path' => '../../rector-doctrine', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main ea9cf46'), 'rector/rector-downgrade-php' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-downgrade-php', 'relative_install_path' => '../../rector-downgrade-php', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main fc1c39f'), 'rector/rector-phpunit' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-phpunit', 'relative_install_path' => '../../rector-phpunit', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main 13e842b'), 'rector/rector-symfony' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-symfony', 'relative_install_path' => '../../rector-symfony', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main a82d4c2'));
private function __construct()
{
}

View File

@ -3,6 +3,7 @@
declare (strict_types=1);
namespace RectorPrefix202302;
use PHPStan\Type\ObjectType;
use PHPStan\Type\StringType;
use Rector\Config\RectorConfig;
use Rector\Renaming\Rector\ClassConstFetch\RenameClassConstFetchRector;
@ -13,11 +14,14 @@ use Rector\Renaming\ValueObject\RenameClassConstFetch;
use Rector\Symfony\Rector\Class_\CommandDescriptionToPropertyRector;
use Rector\Symfony\Rector\StaticPropertyFetch\KernelTestCaseContainerPropertyDeprecationRector;
use Rector\Symfony\Set\SymfonySetList;
use Rector\TypeDeclaration\Rector\ClassMethod\AddParamTypeDeclarationRector;
use Rector\TypeDeclaration\Rector\ClassMethod\AddReturnTypeDeclarationRector;
use Rector\TypeDeclaration\ValueObject\AddParamTypeDeclaration;
use Rector\TypeDeclaration\ValueObject\AddReturnTypeDeclaration;
# https://github.com/symfony/symfony/blob/5.4/UPGRADE-5.3.md
return static function (RectorConfig $rectorConfig) : void {
$rectorConfig->sets([SymfonySetList::ANNOTATIONS_TO_ATTRIBUTES]);
$rectorConfig->import(__DIR__ . '/symfony53-types.php');
$rectorConfig->ruleWithConfiguration(RenameMethodRector::class, [
// @see https://github.com/symfony/symfony/pull/40536
new MethodCallRename('Symfony\\Component\\HttpFoundation\\RequestStack', 'getMasterRequest', 'getMainRequest'),
@ -50,6 +54,12 @@ return static function (RectorConfig $rectorConfig) : void {
// @see https://github.com/symfony/symfony/pull/40536
new RenameClassConstFetch('Symfony\\Component\\HttpKernel\\HttpKernelInterface', 'MASTER_REQUEST', 'MAIN_REQUEST'),
]);
$rectorConfig->ruleWithConfiguration(AddParamTypeDeclarationRector::class, [
// @see https://github.com/symfony/symfony/commit/ce77be2507631cd12e4ca37510dab37f4c2b759a
new AddParamTypeDeclaration('Symfony\\Component\\Form\\DataMapperInterface', 'mapFormsToData', 0, new ObjectType(\Traversable::class)),
// @see https://github.com/symfony/symfony/commit/ce77be2507631cd12e4ca37510dab37f4c2b759a
new AddParamTypeDeclaration('Symfony\\Component\\Form\\DataMapperInterface', 'mapDataToForms', 1, new ObjectType(\Traversable::class)),
]);
$rectorConfig->rule(KernelTestCaseContainerPropertyDeprecationRector::class);
$rectorConfig->rule(CommandDescriptionToPropertyRector::class);
};

View File

@ -0,0 +1,28 @@
<?php
declare (strict_types=1);
namespace Rector\Symfony\NodeAnalyzer;
use PhpParser\Node\Stmt\Class_;
use Rector\NodeNameResolver\NodeNameResolver;
final class ClassAnalyzer
{
/**
* @readonly
* @var \Rector\NodeNameResolver\NodeNameResolver
*/
private $nodeNameResolver;
public function __construct(NodeNameResolver $nodeNameResolver)
{
$this->nodeNameResolver = $nodeNameResolver;
}
public function hasImplements(Class_ $class, string $interfaceFQN) : bool
{
foreach ($class->implements as $implement) {
if ($this->nodeNameResolver->isName($implement, $interfaceFQN)) {
return \true;
}
}
return \false;
}
}

View File

@ -0,0 +1,31 @@
<?php
declare (strict_types=1);
namespace Rector\Symfony\NodeManipulator;
use PhpParser\Node\Stmt\Class_;
use Rector\NodeNameResolver\NodeNameResolver;
final class ClassManipulator
{
/**
* @readonly
* @var \Rector\NodeNameResolver\NodeNameResolver
*/
private $nodeNameResolver;
public function __construct(NodeNameResolver $nodeNameResolver)
{
$this->nodeNameResolver = $nodeNameResolver;
}
/**
* @param string[] $interfaceFQNS
*/
public function removeImplements(Class_ $class, array $interfaceFQNS) : void
{
foreach ($class->implements as $key => $implement) {
if (!$this->nodeNameResolver->isNames($implement, $interfaceFQNS)) {
continue;
}
unset($class->implements[$key]);
}
}
}

View File

@ -10,6 +10,7 @@ use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Class_;
use Rector\Core\Rector\AbstractRector;
use Rector\Symfony\ApplicationMetadata\ListenerServiceDefinitionProvider;
use Rector\Symfony\NodeAnalyzer\ClassAnalyzer;
use Rector\Symfony\NodeFactory\GetSubscribedEventsClassMethodFactory;
use Rector\Symfony\ValueObject\EventNameToClassAndConstant;
use Rector\Symfony\ValueObject\ServiceDefinition;
@ -51,10 +52,16 @@ final class EventListenerToEventSubscriberRector extends AbstractRector
* @var \Rector\Symfony\NodeFactory\GetSubscribedEventsClassMethodFactory
*/
private $getSubscribedEventsClassMethodFactory;
public function __construct(ListenerServiceDefinitionProvider $listenerServiceDefinitionProvider, GetSubscribedEventsClassMethodFactory $getSubscribedEventsClassMethodFactory)
/**
* @readonly
* @var \Rector\Symfony\NodeAnalyzer\ClassAnalyzer
*/
private $classAnalyzer;
public function __construct(ListenerServiceDefinitionProvider $listenerServiceDefinitionProvider, GetSubscribedEventsClassMethodFactory $getSubscribedEventsClassMethodFactory, ClassAnalyzer $classAnalyzer)
{
$this->listenerServiceDefinitionProvider = $listenerServiceDefinitionProvider;
$this->getSubscribedEventsClassMethodFactory = $getSubscribedEventsClassMethodFactory;
$this->classAnalyzer = $classAnalyzer;
$this->eventNamesToClassConstants = [
// kernel events
new EventNameToClassAndConstant('kernel.request', self::KERNEL_EVENTS_CLASS, 'REQUEST'),
@ -124,7 +131,7 @@ CODE_SAMPLE
return null;
}
// is already a subscriber
if ($this->isAlreadyEventSubscriber($node)) {
if ($this->classAnalyzer->hasImplements($node, 'Symfony\\Component\\EventDispatcher\\EventSubscriberInterface')) {
return null;
}
// there must be event dispatcher in the application
@ -139,15 +146,6 @@ CODE_SAMPLE
$this->changeListenerToSubscriberWithMethods($node, $listenerClassesToEventsToMethods[$className]);
return $node;
}
private function isAlreadyEventSubscriber(Class_ $class) : bool
{
foreach ($class->implements as $implement) {
if ($this->isName($implement, 'Symfony\\Component\\EventDispatcher\\EventSubscriberInterface')) {
return \true;
}
}
return \false;
}
/**
* @param array<string, ServiceDefinition[]> $eventsToMethods
*/

View File

@ -9,8 +9,10 @@ use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Type\ObjectType;
use Rector\Core\Rector\AbstractRector;
use Rector\Symfony\NodeAnalyzer\ClassAnalyzer;
use Rector\Symfony\NodeFactory\GetSubscribedEventsClassMethodFactory;
use Rector\Symfony\NodeFactory\OnLogoutClassMethodFactory;
use Rector\Symfony\NodeManipulator\ClassManipulator;
use Rector\Symfony\ValueObject\EventReferenceToMethodName;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -36,10 +38,22 @@ final class LogoutHandlerToLogoutEventSubscriberRector extends AbstractRector
* @var \Rector\Symfony\NodeFactory\GetSubscribedEventsClassMethodFactory
*/
private $getSubscribedEventsClassMethodFactory;
public function __construct(OnLogoutClassMethodFactory $onLogoutClassMethodFactory, GetSubscribedEventsClassMethodFactory $getSubscribedEventsClassMethodFactory)
/**
* @readonly
* @var \Rector\Symfony\NodeAnalyzer\ClassAnalyzer
*/
private $classAnalyzer;
/**
* @readonly
* @var \Rector\Symfony\NodeManipulator\ClassManipulator
*/
private $classManipulator;
public function __construct(OnLogoutClassMethodFactory $onLogoutClassMethodFactory, GetSubscribedEventsClassMethodFactory $getSubscribedEventsClassMethodFactory, ClassAnalyzer $classAnalyzer, ClassManipulator $classManipulator)
{
$this->onLogoutClassMethodFactory = $onLogoutClassMethodFactory;
$this->getSubscribedEventsClassMethodFactory = $getSubscribedEventsClassMethodFactory;
$this->classAnalyzer = $classAnalyzer;
$this->classManipulator = $classManipulator;
$this->logoutHandlerObjectType = new ObjectType('Symfony\\Component\\Security\\Http\\Logout\\LogoutHandlerInterface');
}
public function getRuleDefinition() : RuleDefinition
@ -98,10 +112,11 @@ CODE_SAMPLE
if (!$this->isObjectType($node, $this->logoutHandlerObjectType)) {
return null;
}
if (!$this->hasImplements($node)) {
if (!$this->classAnalyzer->hasImplements($node, 'Symfony\\Component\\Security\\Http\\Logout\\LogoutHandlerInterface')) {
return null;
}
$this->refactorImplements($node);
$this->classManipulator->removeImplements($node, [$this->logoutHandlerObjectType->getClassName()]);
$node->implements[] = new FullyQualified('Symfony\\Component\\EventDispatcher\\EventSubscriberInterface');
// 2. refactor logout() class method to onLogout()
$logoutClassMethod = $node->getMethod('logout');
if (!$logoutClassMethod instanceof ClassMethod) {
@ -116,23 +131,4 @@ CODE_SAMPLE
$node->stmts[] = $getSubscribedEventsClassMethod;
return $node;
}
private function refactorImplements(Class_ $class) : void
{
$class->implements[] = new FullyQualified('Symfony\\Component\\EventDispatcher\\EventSubscriberInterface');
foreach ($class->implements as $key => $implement) {
if (!$this->isName($implement, $this->logoutHandlerObjectType->getClassName())) {
continue;
}
unset($class->implements[$key]);
}
}
private function hasImplements(Class_ $class) : bool
{
foreach ($class->implements as $implement) {
if ($this->isName($implement, 'Symfony\\Component\\Security\\Http\\Logout\\LogoutHandlerInterface')) {
return \true;
}
}
return \false;
}
}

View File

@ -9,8 +9,10 @@ use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Type\ObjectType;
use Rector\Core\Rector\AbstractRector;
use Rector\Symfony\NodeAnalyzer\ClassAnalyzer;
use Rector\Symfony\NodeFactory\GetSubscribedEventsClassMethodFactory;
use Rector\Symfony\NodeFactory\OnSuccessLogoutClassMethodFactory;
use Rector\Symfony\NodeManipulator\ClassManipulator;
use Rector\Symfony\ValueObject\EventReferenceToMethodNameWithPriority;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -36,10 +38,22 @@ final class LogoutSuccessHandlerToLogoutEventSubscriberRector extends AbstractRe
* @var \Rector\Symfony\NodeFactory\GetSubscribedEventsClassMethodFactory
*/
private $getSubscribedEventsClassMethodFactory;
public function __construct(OnSuccessLogoutClassMethodFactory $onSuccessLogoutClassMethodFactory, GetSubscribedEventsClassMethodFactory $getSubscribedEventsClassMethodFactory)
/**
* @readonly
* @var \Rector\Symfony\NodeAnalyzer\ClassAnalyzer
*/
private $classAnalyzer;
/**
* @readonly
* @var \Rector\Symfony\NodeManipulator\ClassManipulator
*/
private $classManipulator;
public function __construct(OnSuccessLogoutClassMethodFactory $onSuccessLogoutClassMethodFactory, GetSubscribedEventsClassMethodFactory $getSubscribedEventsClassMethodFactory, ClassAnalyzer $classAnalyzer, ClassManipulator $classManipulator)
{
$this->onSuccessLogoutClassMethodFactory = $onSuccessLogoutClassMethodFactory;
$this->getSubscribedEventsClassMethodFactory = $getSubscribedEventsClassMethodFactory;
$this->classAnalyzer = $classAnalyzer;
$this->classManipulator = $classManipulator;
$this->successHandlerObjectType = new ObjectType('Symfony\\Component\\Security\\Http\\Logout\\LogoutSuccessHandlerInterface');
}
public function getRuleDefinition() : RuleDefinition
@ -118,10 +132,11 @@ CODE_SAMPLE
if (!$this->isObjectType($node, $this->successHandlerObjectType)) {
return null;
}
if (!$this->hasImplements($node)) {
if (!$this->classAnalyzer->hasImplements($node, 'Symfony\\Component\\Security\\Http\\Logout\\LogoutSuccessHandlerInterface')) {
return null;
}
$this->refactorImplements($node);
$this->classManipulator->removeImplements($node, [$this->successHandlerObjectType->getClassName()]);
$node->implements[] = new FullyQualified('Symfony\\Component\\EventDispatcher\\EventSubscriberInterface');
// 2. refactor logout() class method to onLogout()
$onLogoutSuccessClassMethod = $node->getMethod('onLogoutSuccess');
if (!$onLogoutSuccessClassMethod instanceof ClassMethod) {
@ -136,23 +151,4 @@ CODE_SAMPLE
$this->removeNode($onLogoutSuccessClassMethod);
return $node;
}
private function refactorImplements(Class_ $class) : void
{
$class->implements[] = new FullyQualified('Symfony\\Component\\EventDispatcher\\EventSubscriberInterface');
foreach ($class->implements as $key => $implement) {
if (!$this->isName($implement, $this->successHandlerObjectType->getClassName())) {
continue;
}
unset($class->implements[$key]);
}
}
private function hasImplements(Class_ $class) : bool
{
foreach ($class->implements as $implement) {
if ($this->isName($implement, 'Symfony\\Component\\Security\\Http\\Logout\\LogoutSuccessHandlerInterface')) {
return \true;
}
}
return \false;
}
}