[Symfony 5.1] Add LogoutHandlerToLogoutEventSubscriberRector (#5346)

This commit is contained in:
Tomas Votruba 2021-01-28 19:55:35 +01:00 committed by GitHub
parent 8e3e3fd6e1
commit f9f12d9109
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 597 additions and 47 deletions

View File

@ -10,6 +10,8 @@ use Rector\Renaming\Rector\Name\RenameClassRector;
use Rector\Renaming\Rector\String_\RenameStringRector;
use Rector\Renaming\ValueObject\MethodCallRename;
use Rector\Renaming\ValueObject\RenameClassAndConstFetch;
use Rector\Symfony5\Rector\Class_\LogoutHandlerToLogoutEventSubscriberRector;
use Rector\Symfony5\Rector\Class_\LogoutSuccessHandlerToLogoutEventSubscriberRector;
use Rector\Transform\Rector\New_\NewArgToMethodCallRector;
use Rector\Transform\Rector\StaticCall\StaticCallToNewRector;
use Rector\Transform\ValueObject\NewArgToMethodCall;
@ -24,6 +26,10 @@ use Symplify\SymfonyPhpConfig\ValueObjectInliner;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
// see https://github.com/symfony/symfony/pull/36243
$services->set(LogoutHandlerToLogoutEventSubscriberRector::class);
$services->set(LogoutSuccessHandlerToLogoutEventSubscriberRector::class);
$services->set(RenameClassRector::class)
->call('configure', [[
RenameClassRector::OLD_TO_NEW_CLASSES => [

View File

@ -2,7 +2,7 @@
namespace Rector\EarlyReturn\Tests\Rector\Return_\ReturnBinaryAndToEarlyReturnRector\Fixture;
class NotIdentical
final class SomeNotIdentical
{
public function accept($something, $somethingelse)
{
@ -16,7 +16,7 @@ class NotIdentical
namespace Rector\EarlyReturn\Tests\Rector\Return_\ReturnBinaryAndToEarlyReturnRector\Fixture;
class NotIdentical
final class SomeNotIdentical
{
public function accept($something, $somethingelse)
{

View File

@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace Rector\SymfonyCodeQuality\Contract;
use PhpParser\Node\Expr\ClassConstFetch;
interface EventReferenceToMethodNameInterface
{
public function getClassConstFetch(): ClassConstFetch;
public function getMethodName(): string;
}

View File

@ -26,8 +26,9 @@ use Rector\Symfony\Contract\Tag\TagInterface;
use Rector\Symfony\ValueObject\ServiceDefinition;
use Rector\Symfony\ValueObject\Tag;
use Rector\Symfony\ValueObject\Tag\EventListenerTag;
use Rector\SymfonyCodeQuality\Contract\EventReferenceToMethodNameInterface;
use Rector\SymfonyCodeQuality\ValueObject\EventNameToClassAndConstant;
use Rector\SymfonyCodeQuality\ValueObject\EventReferenceToMethodName;
use Rector\SymfonyCodeQuality\ValueObject\EventReferenceToMethodNameWithPriority;
final class GetSubscribedEventsClassMethodFactory
{
@ -83,7 +84,7 @@ final class GetSubscribedEventsClassMethodFactory
}
/**
* @param EventReferenceToMethodName[] $eventReferencesToMethodNames
* @param EventReferenceToMethodNameInterface[] $eventReferencesToMethodNames
*/
public function create(array $eventReferencesToMethodNames): ClassMethod
{
@ -92,8 +93,10 @@ final class GetSubscribedEventsClassMethodFactory
$eventsToMethodsArray = new Array_();
foreach ($eventReferencesToMethodNames as $eventReferencesToMethodName) {
$priority = $eventReferencesToMethodName instanceof EventReferenceToMethodNameWithPriority ? $eventReferencesToMethodName->getPriority() : null;
$eventsToMethodsArray->items[] = $this->createArrayItemFromMethodAndPriority(
null,
$priority,
$eventReferencesToMethodName->getMethodName(),
$eventReferencesToMethodName->getClassConstFetch()
);

View File

@ -5,8 +5,9 @@ declare(strict_types=1);
namespace Rector\SymfonyCodeQuality\ValueObject;
use PhpParser\Node\Expr\ClassConstFetch;
use Rector\SymfonyCodeQuality\Contract\EventReferenceToMethodNameInterface;
final class EventReferenceToMethodName
final class EventReferenceToMethodName implements EventReferenceToMethodNameInterface
{
/**
* @var ClassConstFetch

View File

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace Rector\SymfonyCodeQuality\ValueObject;
use PhpParser\Node\Expr\ClassConstFetch;
use Rector\SymfonyCodeQuality\Contract\EventReferenceToMethodNameInterface;
final class EventReferenceToMethodNameWithPriority implements EventReferenceToMethodNameInterface
{
/**
* @var ClassConstFetch
*/
private $classConstFetch;
/**
* @var string
*/
private $methodName;
/**
* @var int
*/
private $priority;
public function __construct(ClassConstFetch $classConstFetch, string $methodName, int $priority)
{
$this->classConstFetch = $classConstFetch;
$this->methodName = $methodName;
$this->priority = $priority;
}
public function getClassConstFetch(): ClassConstFetch
{
return $this->classConstFetch;
}
public function getMethodName(): string
{
return $this->methodName;
}
public function getPriority(): int
{
return $this->priority;
}
}

View File

@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
namespace Rector\Symfony5\NodeFactory;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Core\Php\PhpVersionProvider;
use Rector\Core\PhpParser\Node\NodeFactory;
use Rector\Core\ValueObject\PhpVersionFeature;
final class BareLogoutClassMethodFactory
{
/**
* @var NodeFactory
*/
private $nodeFactory;
/**
* @var PhpVersionProvider
*/
private $phpVersionProvider;
public function __construct(NodeFactory $nodeFactory, PhpVersionProvider $phpVersionProvider)
{
$this->nodeFactory = $nodeFactory;
$this->phpVersionProvider = $phpVersionProvider;
}
public function create(): ClassMethod
{
$classMethod = $this->nodeFactory->createPublicMethod('onLogout');
$variable = new Variable('logoutEvent');
$classMethod->params[] = $this->createLogoutEventParam($variable);
if ($this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::VOID_TYPE)) {
$classMethod->returnType = new Identifier('void');
}
return $classMethod;
}
private function createLogoutEventParam(Variable $variable): Param
{
$param = new Param($variable);
$param->type = new FullyQualified('Symfony\Component\Security\Http\Event\LogoutEvent');
return $param;
}
}

View File

@ -7,14 +7,10 @@ namespace Rector\Symfony5\NodeFactory;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use Rector\Core\Php\PhpVersionProvider;
use Rector\Core\PhpParser\Node\NodeFactory;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\NetteKdyby\NodeManipulator\ListeningClassMethodArgumentManipulator;
use Rector\NodeNameResolver\NodeNameResolver;
@ -29,16 +25,6 @@ final class OnLogoutClassMethodFactory
'token' => 'getToken',
];
/**
* @var NodeFactory
*/
private $nodeFactory;
/**
* @var PhpVersionProvider
*/
private $phpVersionProvider;
/**
* @var ListeningClassMethodArgumentManipulator
*/
@ -49,25 +35,45 @@ final class OnLogoutClassMethodFactory
*/
private $nodeNameResolver;
/**
* @var BareLogoutClassMethodFactory
*/
private $bareLogoutClassMethodFactory;
public function __construct(
NodeFactory $nodeFactory,
PhpVersionProvider $phpVersionProvider,
ListeningClassMethodArgumentManipulator $listeningClassMethodArgumentManipulator,
NodeNameResolver $nodeNameResolver
NodeNameResolver $nodeNameResolver,
BareLogoutClassMethodFactory $bareLogoutClassMethodFactory
) {
$this->nodeFactory = $nodeFactory;
$this->phpVersionProvider = $phpVersionProvider;
$this->listeningClassMethodArgumentManipulator = $listeningClassMethodArgumentManipulator;
$this->nodeNameResolver = $nodeNameResolver;
$this->bareLogoutClassMethodFactory = $bareLogoutClassMethodFactory;
}
public function createFromLogoutClassMethod(ClassMethod $logoutClassMethod): ClassMethod
{
$classMethod = $this->nodeFactory->createPublicMethod('onLogout');
$classMethod = $this->bareLogoutClassMethodFactory->create();
$logoutEventVariable = new Variable('logoutEvent');
$classMethod->params[] = $this->createLogoutEventParam($logoutEventVariable);
$assignStmts = $this->createAssignStmtFromOldClassMethod($logoutClassMethod);
$classMethod->stmts = array_merge($assignStmts, (array) $logoutClassMethod->stmts);
return $classMethod;
}
/**
* @return Stmt[]
*/
private function createAssignStmtFromOldClassMethod(ClassMethod $onLogoutSuccessClassMethod): array
{
$usedParams = $this->resolveUsedParams($onLogoutSuccessClassMethod);
return $this->createAssignStmts($usedParams);
}
/**
* @return Param[]
*/
private function resolveUsedParams(ClassMethod $logoutClassMethod): array
{
$usedParams = [];
foreach ($logoutClassMethod->params as $oldParam) {
if (! $this->listeningClassMethodArgumentManipulator->isParamUsedInClassMethodBody(
@ -79,30 +85,17 @@ final class OnLogoutClassMethodFactory
$usedParams[] = $oldParam;
}
if ($this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::VOID_TYPE)) {
$classMethod->returnType = new Identifier('void');
}
$assignStmts = $this->createAssignStmts($usedParams, $logoutEventVariable);
$classMethod->stmts = array_merge($assignStmts, (array) $logoutClassMethod->stmts);
return $classMethod;
}
private function createLogoutEventParam(Variable $logoutEventVariable): Param
{
$param = new Param($logoutEventVariable);
$param->type = new FullyQualified('Symfony\Component\Security\Http\Event\LogoutEvent');
return $param;
return $usedParams;
}
/**
* @param Param[] $params
* @return Expression[]
*/
private function createAssignStmts(array $params, Variable $logoutEventVariable): array
private function createAssignStmts(array $params): array
{
$logoutEventVariable = new Variable('logoutEvent');
$assignStmts = [];
foreach ($params as $param) {
foreach (self::PARAMETER_TO_GETTER_NAMES as $parameterName => $getterName) {

View File

@ -0,0 +1,111 @@
<?php
declare(strict_types=1);
namespace Rector\Symfony5\NodeFactory;
use PhpParser\Node;
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\If_;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\PhpParser\Node\NodeFactory;
use Rector\NodeNameResolver\NodeNameResolver;
use Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;
final class OnSuccessLogoutClassMethodFactory
{
/**
* @var string
*/
private const LOGOUT_EVENT = 'logoutEvent';
/**
* @var NodeFactory
*/
private $nodeFactory;
/**
* @var NodeNameResolver
*/
private $nodeNameResolver;
/**
* @var SimpleCallableNodeTraverser
*/
private $simpleCallableNodeTraverser;
/**
* @var BareLogoutClassMethodFactory
*/
private $bareLogoutClassMethodFactory;
public function __construct(
NodeFactory $nodeFactory,
NodeNameResolver $nodeNameResolver,
SimpleCallableNodeTraverser $simpleCallableNodeTraverser,
BareLogoutClassMethodFactory $bareLogoutClassMethodFactory
) {
$this->nodeFactory = $nodeFactory;
$this->nodeNameResolver = $nodeNameResolver;
$this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
$this->bareLogoutClassMethodFactory = $bareLogoutClassMethodFactory;
}
public function createFromOnLogoutSuccessClassMethod(ClassMethod $onLogoutSuccessClassMethod): ClassMethod
{
$classMethod = $this->bareLogoutClassMethodFactory->create();
$getResponseMethodCall = new MethodCall(new Variable(self::LOGOUT_EVENT), 'getResponse');
$notIdentical = new NotIdentical($getResponseMethodCall, $this->nodeFactory->createNull());
$if = new If_($notIdentical);
$if->stmts[] = new Return_();
// replace `return $response;` with `$logoutEvent->setResponse($response)`
$this->replaceReturnResponseWithSetResponse($onLogoutSuccessClassMethod);
$this->replaceRequestWithGetRequest($onLogoutSuccessClassMethod);
$oldClassStmts = (array) $onLogoutSuccessClassMethod->stmts;
$classStmts = array_merge([$if], $oldClassStmts);
$classMethod->stmts = $classStmts;
return $classMethod;
}
private function replaceReturnResponseWithSetResponse(ClassMethod $classMethod): void
{
$this->simpleCallableNodeTraverser->traverseNodesWithCallable($classMethod, function (Node $node): ?Expression {
if (! $node instanceof Return_) {
return null;
}
if ($node->expr === null) {
return null;
}
$args = $this->nodeFactory->createArgs([$node->expr]);
$methodCall = new MethodCall(new Variable(self::LOGOUT_EVENT), 'setResponse', $args);
return new Expression($methodCall);
});
}
private function replaceRequestWithGetRequest(ClassMethod $classMethod): void
{
$this->simpleCallableNodeTraverser->traverseNodesWithCallable($classMethod, function (Node $node): ?MethodCall {
if (! $node instanceof Variable) {
return null;
}
if (! $this->nodeNameResolver->isName($node, 'request')) {
return null;
}
return new MethodCall(new Variable(self::LOGOUT_EVENT), 'getRequest');
});
}
}

View File

@ -47,7 +47,7 @@ final class LogoutHandlerToLogoutEventSubscriberRector extends AbstractRector
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Change logout handler to an event listener that listens to LogoutEent', [
return new RuleDefinition('Change logout handler to an event listener that listens to LogoutEvent', [
new CodeSample(
<<<'CODE_SAMPLE'
use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface;

View File

@ -0,0 +1,171 @@
<?php
declare(strict_types=1);
namespace Rector\Symfony5\Rector\Class_;
use PhpParser\Node;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Core\Rector\AbstractRector;
use Rector\Symfony5\NodeFactory\OnSuccessLogoutClassMethodFactory;
use Rector\SymfonyCodeQuality\NodeFactory\GetSubscribedEventsClassMethodFactory;
use Rector\SymfonyCodeQuality\ValueObject\EventReferenceToMethodNameWithPriority;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see https://github.com/symfony/symfony/pull/36243
*
* @see \Rector\Symfony5\Tests\Rector\Class_\LogoutSuccessHandlerToLogoutEventSubscriberRector\LogoutSuccessHandlerToLogoutEventSubscriberRectorTest
*/
final class LogoutSuccessHandlerToLogoutEventSubscriberRector extends AbstractRector
{
/**
* @var string
*/
private const LOGOUT_SUCCESS_HANDLER_TYPE = 'Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface';
/**
* @var GetSubscribedEventsClassMethodFactory
*/
private $getSubscribedEventsClassMethodFactory;
/**
* @var OnSuccessLogoutClassMethodFactory
*/
private $onSuccessLogoutClassMethodFactory;
public function __construct(
OnSuccessLogoutClassMethodFactory $onSuccessLogoutClassMethodFactory,
GetSubscribedEventsClassMethodFactory $getSubscribedEventsClassMethodFactory
) {
$this->getSubscribedEventsClassMethodFactory = $getSubscribedEventsClassMethodFactory;
$this->onSuccessLogoutClassMethodFactory = $onSuccessLogoutClassMethodFactory;
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Change logout success handler to an event listener that listens to LogoutEvent', [
new CodeSample(
<<<'CODE_SAMPLE'
use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
final class SomeLogoutHandler implements LogoutSuccessHandlerInterface
{
/**
* @var HttpUtils
*/
private $httpUtils;
public function __construct(HttpUtils $httpUtils)
{
$this->httpUtils = $httpUtils;
}
public function onLogoutSuccess(Request $request)
{
$response = $this->httpUtils->createRedirectResponse($request, 'some_url');
return $response;
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Http\Event\LogoutEvent;
final class SomeLogoutHandler implements EventSubscriberInterface
{
/**
* @var HttpUtils
*/
private $httpUtils;
public function onLogout(LogoutEvent $logoutEvent): void
{
if ($logoutEvent->getResponse() !== null) {
return;
}
$response = $this->httpUtils->createRedirectResponse($logoutEvent->getRequest(), 'some_url');
$logoutEvent->setResponse($response);
}
/**
* @return array<string, mixed>
*/
public static function getSubscribedEvents(): array
{
return [
LogoutEvent::class => [['onLogout', 64]],
];
}
}
CODE_SAMPLE
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [Class_::class];
}
/**
* @param Class_ $node
*/
public function refactor(Node $node): ?Node
{
if (! $this->isObjectType($node, self::LOGOUT_SUCCESS_HANDLER_TYPE)) {
return null;
}
$this->refactorImplements($node);
// 2. refactor logout() class method to onLogout()
$onLogoutSuccessClassMethod = $node->getMethod('onLogoutSuccess');
if (! $onLogoutSuccessClassMethod instanceof ClassMethod) {
return null;
}
$node->stmts[] = $this->onSuccessLogoutClassMethodFactory->createFromOnLogoutSuccessClassMethod(
$onLogoutSuccessClassMethod
);
// 3. add getSubscribedEvents() class method
$classConstFetch = $this->createClassConstReference('Symfony\Component\Security\Http\Event\LogoutEvent');
$eventReferencesToMethodNames = [new EventReferenceToMethodNameWithPriority($classConstFetch, 'onLogout', 64)];
$getSubscribedEventsClassMethod = $this->getSubscribedEventsClassMethodFactory->create(
$eventReferencesToMethodNames
);
$node->stmts[] = $getSubscribedEventsClassMethod;
$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, self::LOGOUT_SUCCESS_HANDLER_TYPE)) {
continue;
}
unset($class->implements[$key]);
}
}
}

View File

@ -0,0 +1,53 @@
<?php
namespace Rector\Symfony5\Tests\Rector\Class_\LogoutHandlerToLogoutEventSubscriberRector\Fixture;
use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
final class LogoutHandlerWithoutAnyUsage implements LogoutHandlerInterface
{
/**
* @var int
*/
private $value;
public function logout(Request $request, Response $response, TokenInterface $token)
{
$this->value = 1000;
}
}
?>
-----
<?php
namespace Rector\Symfony5\Tests\Rector\Class_\LogoutHandlerToLogoutEventSubscriberRector\Fixture;
use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
final class LogoutHandlerWithoutAnyUsage implements \Symfony\Component\EventDispatcher\EventSubscriberInterface
{
/**
* @var int
*/
private $value;
public function onLogout(\Symfony\Component\Security\Http\Event\LogoutEvent $logoutEvent): void
{
$this->value = 1000;
}
/**
* @return array<string, mixed>
*/
public static function getSubscribedEvents(): array
{
return [\Symfony\Component\Security\Http\Event\LogoutEvent::class => 'onLogout'];
}
}
?>

View File

@ -0,0 +1,64 @@
<?php
namespace Rector\Symfony5\Tests\Rector\Class_\LogoutSuccessHandlerToLogoutEventSubscriberRector\Fixture;
use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface;
use Symfony\Component\HttpFoundation\Request;
final class SimpleLogoutSuccessHandler implements LogoutSuccessHandlerInterface
{
/**
* @var HttpUtils
*/
private $httpUtils;
public function __construct(HttpUtils $httpUtils)
{
$this->httpUtils = $httpUtils;
}
public function onLogoutSuccess(Request $request)
{
$response = $this->httpUtils->createRedirectResponse($request, 'some_url');
return $response;
}
}
?>
-----
<?php
namespace Rector\Symfony5\Tests\Rector\Class_\LogoutSuccessHandlerToLogoutEventSubscriberRector\Fixture;
use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface;
use Symfony\Component\HttpFoundation\Request;
final class SimpleLogoutSuccessHandler implements \Symfony\Component\EventDispatcher\EventSubscriberInterface
{
/**
* @var HttpUtils
*/
private $httpUtils;
public function __construct(HttpUtils $httpUtils)
{
$this->httpUtils = $httpUtils;
}
public function onLogout(\Symfony\Component\Security\Http\Event\LogoutEvent $logoutEvent): void
{
if ($logoutEvent->getResponse() !== null) {
return;
}
$response = $this->httpUtils->createRedirectResponse($logoutEvent->getRequest(), 'some_url');
$logoutEvent->setResponse($response);
}
/**
* @return array<string, mixed>
*/
public static function getSubscribedEvents(): array
{
return [\Symfony\Component\Security\Http\Event\LogoutEvent::class => ['onLogout', 64]];
}
}
?>

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Rector\Symfony5\Tests\Rector\Class_\LogoutSuccessHandlerToLogoutEventSubscriberRector;
use Iterator;
use Rector\Symfony5\Rector\Class_\LogoutSuccessHandlerToLogoutEventSubscriberRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class LogoutSuccessHandlerToLogoutEventSubscriberRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
protected function getRectorClass(): string
{
return LogoutSuccessHandlerToLogoutEventSubscriberRector::class;
}
}