mirror of
https://github.com/rectorphp/rector.git
synced 2024-09-06 15:41:59 +00:00
[Laravel] Add RequestStaticValidateToInjectRector
This commit is contained in:
parent
1d8deff30a
commit
708029e7a3
@ -1,2 +1,3 @@
|
||||
services:
|
||||
Rector\Laravel\Rector\StaticCall\FacadeStaticCallToConstructorInjectionRector: ~
|
||||
Rector\Laravel\Rector\StaticCall\RequestStaticValidateToInjectRector: ~
|
||||
|
@ -0,0 +1,96 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Laravel\Rector\StaticCall;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use Rector\PhpParser\Node\Manipulator\ClassMethodManipulator;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/pull/27276
|
||||
*/
|
||||
final class RequestStaticValidateToInjectRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var ClassMethodManipulator
|
||||
*/
|
||||
private $classMethodManipulator;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $requestClass = 'Illuminate\Http\Request';
|
||||
|
||||
public function __construct(ClassMethodManipulator $classMethodManipulator)
|
||||
{
|
||||
$this->classMethodManipulator = $classMethodManipulator;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('Change static validate() method to $request->validate()', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function store()
|
||||
{
|
||||
$validatedData = Request::validate(['some_attribute' => 'required']);
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function store(\Illuminate\Http\Request $request)
|
||||
{
|
||||
$validatedData = $request->validate(['some_attribute' => 'required']);
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [StaticCall::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StaticCall $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if (! $this->isType($node, $this->requestClass)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->isName($node, 'validate')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$requestName = $this->classMethodManipulator->addMethodParameterIfMissing(
|
||||
$node,
|
||||
$this->requestClass,
|
||||
['request', 'httpRequest']
|
||||
);
|
||||
|
||||
$variable = new Variable($requestName);
|
||||
|
||||
return new MethodCall($variable, $node->name, $node->args);
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Laravel\Tests\Rector\StaticCall\RequestStaticValidateToInjectRector\Fixture;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function store()
|
||||
{
|
||||
$validatedData = Request::validate(['some_attribute' => 'required']);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Laravel\Tests\Rector\StaticCall\RequestStaticValidateToInjectRector\Fixture;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function store(\Illuminate\Http\Request $request)
|
||||
{
|
||||
$validatedData = $request->validate(['some_attribute' => 'required']);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,19 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Laravel\Tests\Rector\StaticCall\RequestStaticValidateToInjectRector;
|
||||
|
||||
use Rector\Laravel\Rector\StaticCall\RequestStaticValidateToInjectRector;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
|
||||
final class RequestStaticValidateToInjectRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$this->doTestFiles([__DIR__ . '/Fixture/fixture.php.inc']);
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return RequestStaticValidateToInjectRector::class;
|
||||
}
|
||||
}
|
@ -7,11 +7,7 @@ use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
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\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\PhpParser\Node\Manipulator\ClassMethodManipulator;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
@ -27,13 +23,21 @@ final class FromHttpRequestGetHeaderToHeadersGetRector extends AbstractRector
|
||||
*/
|
||||
private $netteHttpRequestClass;
|
||||
|
||||
/**
|
||||
* @var ClassMethodManipulator
|
||||
*/
|
||||
private $classMethodManipulator;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $symfonyRequestClass = 'Symfony\Component\HttpFoundation\Request';
|
||||
|
||||
public function __construct(string $netteHttpRequestClass = 'Nette\Http\Request')
|
||||
{
|
||||
public function __construct(
|
||||
ClassMethodManipulator $classMethodManipulator,
|
||||
string $netteHttpRequestClass = 'Nette\Http\Request'
|
||||
) {
|
||||
$this->classMethodManipulator = $classMethodManipulator;
|
||||
$this->netteHttpRequestClass = $netteHttpRequestClass;
|
||||
}
|
||||
|
||||
@ -89,7 +93,11 @@ CODE_SAMPLE
|
||||
return null;
|
||||
}
|
||||
|
||||
$requestName = $this->completeRequestParameterIfMissingAndGetRequestName($node);
|
||||
$requestName = $this->classMethodManipulator->addMethodParameterIfMissing(
|
||||
$node,
|
||||
$this->symfonyRequestClass,
|
||||
['request', 'symfonyRequest']
|
||||
);
|
||||
|
||||
$requestVariableNode = new Variable($requestName);
|
||||
$headersPropertyFetch = new PropertyFetch($requestVariableNode, 'headers');
|
||||
@ -99,31 +107,4 @@ CODE_SAMPLE
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function completeRequestParameterIfMissingAndGetRequestName(Node $node): string
|
||||
{
|
||||
$classMethodNode = $node->getAttribute(Attribute::METHOD_NODE);
|
||||
if (! $classMethodNode instanceof ClassMethod) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
foreach ($classMethodNode->params as $paramNode) {
|
||||
if ($this->isType($paramNode, $this->symfonyRequestClass)) {
|
||||
return $this->getName($paramNode);
|
||||
}
|
||||
}
|
||||
|
||||
$requestName = 'request';
|
||||
foreach ($classMethodNode->params as $paramNode) {
|
||||
if ($this->isName($paramNode, 'request')) {
|
||||
$requestName = 'symfonyRequest';
|
||||
}
|
||||
}
|
||||
|
||||
$classMethodNode->params[] = new Param(new Variable($requestName), null, new FullyQualified(
|
||||
$this->symfonyRequestClass
|
||||
));
|
||||
|
||||
return $requestName;
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,14 @@
|
||||
|
||||
namespace Rector\NodeTypeResolver;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\ArrayDimFetch;
|
||||
use PhpParser\Node\Expr\Cast;
|
||||
use PhpParser\Node\Expr\ClassConstFetch;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Stmt\ClassConst;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
@ -68,6 +71,37 @@ final class NodeTypeResolver
|
||||
$this->nameResolver = $nameResolver;
|
||||
}
|
||||
|
||||
public function isType(Node $node, string $type): bool
|
||||
{
|
||||
$nodeTypes = $this->getTypes($node);
|
||||
|
||||
// fnmatch support
|
||||
if (Strings::contains($type, '*')) {
|
||||
foreach ($nodeTypes as $nodeType) {
|
||||
if (fnmatch($type, $nodeType, FNM_NOESCAPE)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return in_array($type, $nodeTypes, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getTypes(Node $node): array
|
||||
{
|
||||
// @todo should be resolved by NodeTypeResolver internally
|
||||
if ($node instanceof MethodCall || $node instanceof PropertyFetch || $node instanceof ArrayDimFetch) {
|
||||
return $this->resolve($node->var);
|
||||
}
|
||||
|
||||
return $this->resolve($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
|
@ -4,7 +4,7 @@ namespace Rector\Php\Tests\Rector\FuncCall\RegexDashEscapeRector\Fixture;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
|
||||
class MethodCall
|
||||
class UniqueMethodNameCall
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
@ -23,7 +23,7 @@ namespace Rector\Php\Tests\Rector\FuncCall\RegexDashEscapeRector\Fixture;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
|
||||
class MethodCall
|
||||
class UniqueMethodNameCall
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
|
@ -7,9 +7,11 @@ use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PhpParser\Node\Param;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use Rector\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
use Rector\PhpParser\Node\BetterNodeFinder;
|
||||
@ -187,6 +189,29 @@ final class ClassMethodManipulator
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $possibleNames
|
||||
*/
|
||||
public function addMethodParameterIfMissing(Node $node, string $type, array $possibleNames): string
|
||||
{
|
||||
$classMethodNode = $node->getAttribute(Attribute::METHOD_NODE);
|
||||
if (! $classMethodNode instanceof ClassMethod) {
|
||||
// or null?
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
foreach ($classMethodNode->params as $paramNode) {
|
||||
if ($this->nodeTypeResolver->isType($paramNode, $type)) {
|
||||
return $this->nameResolver->resolve($paramNode);
|
||||
}
|
||||
}
|
||||
|
||||
$paramName = $this->resolveName($classMethodNode, $possibleNames);
|
||||
$classMethodNode->params[] = new Param(new Variable($paramName), null, new FullyQualified($type));
|
||||
|
||||
return $paramName;
|
||||
}
|
||||
|
||||
private function isMethodInParent(string $class, string $method): bool
|
||||
{
|
||||
$parentClass = $class;
|
||||
@ -214,4 +239,22 @@ final class ClassMethodManipulator
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $possibleNames
|
||||
*/
|
||||
private function resolveName(ClassMethod $classMethod, array $possibleNames): string
|
||||
{
|
||||
foreach ($possibleNames as $possibleName) {
|
||||
foreach ($classMethod->params as $paramNode) {
|
||||
if ($this->nameResolver->isName($paramNode, $possibleName)) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
return $possibleName;
|
||||
}
|
||||
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,7 @@
|
||||
|
||||
namespace Rector\Rector;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\ArrayDimFetch;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\NodeTypeResolver\NodeTypeAnalyzer;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
@ -40,20 +36,7 @@ trait TypeAnalyzerTrait
|
||||
|
||||
protected function isType(Node $node, string $type): bool
|
||||
{
|
||||
$nodeTypes = $this->getTypes($node);
|
||||
|
||||
// fnmatch support
|
||||
if (Strings::contains($type, '*')) {
|
||||
foreach ($nodeTypes as $nodeType) {
|
||||
if (fnmatch($type, $nodeType, FNM_NOESCAPE)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return in_array($type, $nodeTypes, true);
|
||||
return $this->nodeTypeResolver->isType($node, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -134,11 +117,6 @@ trait TypeAnalyzerTrait
|
||||
*/
|
||||
protected function getTypes(Node $node): array
|
||||
{
|
||||
// @todo should be resolved by NodeTypeResolver internally
|
||||
if ($node instanceof MethodCall || $node instanceof PropertyFetch || $node instanceof ArrayDimFetch) {
|
||||
return $this->nodeTypeResolver->resolve($node->var);
|
||||
}
|
||||
|
||||
return $this->nodeTypeResolver->resolve($node);
|
||||
return $this->nodeTypeResolver->getTypes($node);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user