Skip to content

Commit

Permalink
[Symfony 5.1] Add LogoutSuccessHandlerToLogoutEventSubscriberRector
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Jan 28, 2021
1 parent b4d3b7c commit ae52376
Show file tree
Hide file tree
Showing 13 changed files with 582 additions and 56 deletions.
2 changes: 2 additions & 0 deletions config/set/symfony51.php
Expand Up @@ -11,6 +11,7 @@
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;
Expand All @@ -27,6 +28,7 @@

// see https://github.com/symfony/symfony/pull/36243
$services->set(LogoutHandlerToLogoutEventSubscriberRector::class);
$services->set(LogoutSuccessHandlerToLogoutEventSubscriberRector::class);

$services->set(RenameClassRector::class)
->call('configure', [[
Expand Down
Expand Up @@ -2,7 +2,7 @@

namespace Rector\EarlyReturn\Tests\Rector\Return_\ReturnBinaryAndToEarlyReturnRector\Fixture;

class NotIdentical
final class SomeNotIdentical
{
public function accept($something, $somethingelse)
{
Expand All @@ -16,7 +16,7 @@ class NotIdentical

namespace Rector\EarlyReturn\Tests\Rector\Return_\ReturnBinaryAndToEarlyReturnRector\Fixture;

class NotIdentical
final class SomeNotIdentical
{
public function accept($something, $somethingelse)
{
Expand Down
@@ -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;
}
Expand Up @@ -26,8 +26,9 @@
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
{
Expand Down Expand Up @@ -83,7 +84,7 @@ public function __construct(
}

/**
* @param EventReferenceToMethodName[] $eventReferencesToMethodNames
* @param EventReferenceToMethodNameInterface[] $eventReferencesToMethodNames
*/
public function create(array $eventReferencesToMethodNames): ClassMethod
{
Expand All @@ -92,8 +93,10 @@ public function create(array $eventReferencesToMethodNames): ClassMethod
$eventsToMethodsArray = new Array_();

foreach ($eventReferencesToMethodNames as $eventReferencesToMethodName) {
$priority = $eventReferencesToMethodName instanceof EventReferenceToMethodNameWithPriority ? $eventReferencesToMethodName->getPriority() : null;

$eventsToMethodsArray->items[] = $this->createArrayItemFromMethodAndPriority(
null,
$priority,
$eventReferencesToMethodName->getMethodName(),
$eventReferencesToMethodName->getClassConstFetch()
);
Expand Down
Expand Up @@ -5,8 +5,9 @@
namespace Rector\SymfonyCodeQuality\ValueObject;

use PhpParser\Node\Expr\ClassConstFetch;
use Rector\SymfonyCodeQuality\Contract\EventReferenceToMethodNameInterface;

final class EventReferenceToMethodName
final class EventReferenceToMethodName implements EventReferenceToMethodNameInterface
{
/**
* @var ClassConstFetch
Expand Down
@@ -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;
}
}
81 changes: 81 additions & 0 deletions rules/symfony5/src/NodeFactory/BareLogoutClassMethodFactory.php
@@ -0,0 +1,81 @@
<?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;
use Rector\NetteKdyby\NodeManipulator\ListeningClassMethodArgumentManipulator;
use Rector\NodeNameResolver\NodeNameResolver;
use Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;

final class BareLogoutClassMethodFactory
{
/**
* @var NodeFactory
*/
private $nodeFactory;

/**
* @var PhpVersionProvider
*/
private $phpVersionProvider;

/**
* @var ListeningClassMethodArgumentManipulator
*/
private $listeningClassMethodArgumentManipulator;

/**
* @var NodeNameResolver
*/
private $nodeNameResolver;

/**
* @var SimpleCallableNodeTraverser
*/
private $simpleCallableNodeTraverser;

public function __construct(
NodeFactory $nodeFactory,
PhpVersionProvider $phpVersionProvider,
ListeningClassMethodArgumentManipulator $listeningClassMethodArgumentManipulator,
NodeNameResolver $nodeNameResolver,
SimpleCallableNodeTraverser $simpleCallableNodeTraverser
) {
$this->nodeFactory = $nodeFactory;
$this->phpVersionProvider = $phpVersionProvider;
$this->listeningClassMethodArgumentManipulator = $listeningClassMethodArgumentManipulator;
$this->nodeNameResolver = $nodeNameResolver;
$this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
}

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;
}
}
91 changes: 42 additions & 49 deletions rules/symfony5/src/NodeFactory/OnLogoutClassMethodFactory.php
Expand Up @@ -7,14 +7,10 @@
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;

Expand All @@ -29,16 +25,6 @@ final class OnLogoutClassMethodFactory
'token' => 'getToken',
];

/**
* @var NodeFactory
*/
private $nodeFactory;

/**
* @var PhpVersionProvider
*/
private $phpVersionProvider;

/**
* @var ListeningClassMethodArgumentManipulator
*/
Expand All @@ -49,60 +35,39 @@ 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');

$logoutEventVariable = new Variable('logoutEvent');
$classMethod->params[] = $this->createLogoutEventParam($logoutEventVariable);

$usedParams = [];
foreach ($logoutClassMethod->params as $oldParam) {
if (! $this->listeningClassMethodArgumentManipulator->isParamUsedInClassMethodBody(
$logoutClassMethod,
$oldParam
)) {
continue;
}
$classMethod = $this->bareLogoutClassMethodFactory->create();

$usedParams[] = $oldParam;
}

if ($this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::VOID_TYPE)) {
$classMethod->returnType = new Identifier('void');
}

$assignStmts = $this->createAssignStmts($usedParams, $logoutEventVariable);
$assignStmts = $this->createAssignStmtFromOldClassMethod($logoutClassMethod);
$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;
}

/**
* @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) {
Expand All @@ -117,4 +82,32 @@ private function createAssignStmts(array $params, Variable $logoutEventVariable)

return $assignStmts;
}

/**
* @return Param[]
*/
private function resolveUsedParams(ClassMethod $logoutClassMethod): array
{
$usedParams = [];
foreach ($logoutClassMethod->params as $oldParam) {
if (! $this->listeningClassMethodArgumentManipulator->isParamUsedInClassMethodBody(
$logoutClassMethod,
$oldParam
)) {
continue;
}

$usedParams[] = $oldParam;
}
return $usedParams;
}

/**
* @return Stmt[]
*/
private function createAssignStmtFromOldClassMethod(ClassMethod $onLogoutSuccessClassMethod): array
{
$usedParams = $this->resolveUsedParams($onLogoutSuccessClassMethod);
return $this->createAssignStmts($usedParams);
}
}

0 comments on commit ae52376

Please sign in to comment.