diff --git a/ecs.php b/ecs.php index c085c5c75..eb5c8c84d 100644 --- a/ecs.php +++ b/ecs.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use PhpCsFixer\Fixer\StringNotation\SingleQuoteFixer; use Symplify\EasyCodingStandard\Config\ECSConfig; return ECSConfig::configure() @@ -10,4 +11,13 @@ ) ->withRootFiles() ->withPreparedSets(psr12: true, symplify: true, common: true, strict: true) - ->withSkip(['*/Source/*', '*/Fixture/*', '*/Expected/*']); + ->withSkip([ + '*/Source/*', + '*/Fixture/*', + '*/Expected/*', + + // skip change "\\Entity" to '\\Entity as cause removed the \\ on scoped build + SingleQuoteFixer::class => [ + __DIR__ . '/rules/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector.php', + ], + ]); diff --git a/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/skip_required_annotation.php.inc b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/skip_required_annotation.php.inc new file mode 100644 index 000000000..2fd4005c4 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/skip_required_annotation.php.inc @@ -0,0 +1,21 @@ +logger = $logger; + } +} diff --git a/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/skip_required_attribute.php.inc b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/skip_required_attribute.php.inc new file mode 100644 index 000000000..91d2d7d67 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/skip_required_attribute.php.inc @@ -0,0 +1,20 @@ +logger = $logger; + } +} diff --git a/src/Bridge/NodeAnalyzer/ControllerMethodAnalyzer.php b/src/Bridge/NodeAnalyzer/ControllerMethodAnalyzer.php index 64393bed9..24b29a21d 100644 --- a/src/Bridge/NodeAnalyzer/ControllerMethodAnalyzer.php +++ b/src/Bridge/NodeAnalyzer/ControllerMethodAnalyzer.php @@ -5,12 +5,18 @@ namespace Rector\Symfony\Bridge\NodeAnalyzer; use PhpParser\Node\Stmt\ClassMethod; +use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; +use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; +use Rector\Php80\NodeAnalyzer\PhpAttributeAnalyzer; +use Rector\Symfony\Enum\SymfonyAttribute; use Rector\Symfony\TypeAnalyzer\ControllerAnalyzer; final readonly class ControllerMethodAnalyzer { public function __construct( - private ControllerAnalyzer $controllerAnalyzer + private ControllerAnalyzer $controllerAnalyzer, + private PhpDocInfoFactory $phpDocInfoFactory, + private PhpAttributeAnalyzer $phpAttributeAnalyzer ) { } @@ -23,6 +29,15 @@ public function isAction(ClassMethod $classMethod): bool return false; } - return $classMethod->isPublic() && ! $classMethod->isStatic(); + if ($classMethod->isPublic() && ! $classMethod->isStatic()) { + $phpDocInfo = $this->phpDocInfoFactory->createFromNode($classMethod); + if ($phpDocInfo instanceof PhpDocInfo && $phpDocInfo->hasByName('required')) { + return false; + } + + return ! $this->phpAttributeAnalyzer->hasPhpAttribute($classMethod, SymfonyAttribute::REQUIRED); + } + + return false; } }