mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-17 21:38:22 +01:00
[PHPUnit][Symfony] Add jakzal-injetor Rector
This commit is contained in:
parent
47025a95ee
commit
5f523b5727
2
config/set/phpunit/phpunit-injector.yaml
Normal file
2
config/set/phpunit/phpunit-injector.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
services:
|
||||
Rector\PHPUnit\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector: ~
|
@ -20,6 +20,7 @@ use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
use Rector\ValueObject\PhpVersionFeature;
|
||||
|
||||
/**
|
||||
* @see https://3v4l.org/GL6II
|
||||
@ -210,7 +211,7 @@ PHP
|
||||
$propertyBuilder->makePublic();
|
||||
$property = $propertyBuilder->getNode();
|
||||
|
||||
if ($this->isAtLeastPhpVersion('7.4')) {
|
||||
if ($this->isAtLeastPhpVersion(PhpVersionFeature::TYPED_PROPERTIES)) {
|
||||
$phpStanNode = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($propertyType);
|
||||
if ($phpStanNode !== null) {
|
||||
$property->type = $phpStanNode;
|
||||
|
@ -7,6 +7,7 @@ namespace Rector\CodeQuality\Tests\Rector\Class_\CompleteDynamicPropertiesRector
|
||||
use Iterator;
|
||||
use Rector\CodeQuality\Rector\Class_\CompleteDynamicPropertiesRector;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Rector\ValueObject\PhpVersionFeature;
|
||||
|
||||
final class CompleteDynamicPropertiesRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
@ -30,7 +31,6 @@ final class CompleteDynamicPropertiesRectorTest extends AbstractRectorTestCase
|
||||
|
||||
protected function getPhpVersion(): string
|
||||
{
|
||||
// prevents union types
|
||||
return '7.4';
|
||||
return PhpVersionFeature::BEFORE_UNION_TYPES;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\PHPUnit\Manipulator;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\PhpParser\Node\Commander\NodeRemovingCommander;
|
||||
use Rector\PhpParser\Node\Resolver\NameResolver;
|
||||
use Rector\PhpParser\Node\Value\ValueResolver;
|
||||
use Rector\PhpParser\NodeTraverser\CallableNodeTraverser;
|
||||
use Rector\SymfonyPHPUnit\Naming\ServiceNaming;
|
||||
use Rector\SymfonyPHPUnit\Node\KernelTestCaseNodeAnalyzer;
|
||||
|
||||
final class OnContainerGetCallManipulator
|
||||
{
|
||||
/**
|
||||
* @var NameResolver
|
||||
*/
|
||||
private $nameResolver;
|
||||
|
||||
/**
|
||||
* @var CallableNodeTraverser
|
||||
*/
|
||||
private $callableNodeTraverser;
|
||||
|
||||
/**
|
||||
* @var ServiceNaming
|
||||
*/
|
||||
private $serviceNaming;
|
||||
|
||||
/**
|
||||
* @var NodeRemovingCommander
|
||||
*/
|
||||
private $nodeRemovingCommander;
|
||||
|
||||
/**
|
||||
* @var KernelTestCaseNodeAnalyzer
|
||||
*/
|
||||
private $kernelTestCaseNodeAnalyzer;
|
||||
|
||||
/**
|
||||
* @var ValueResolver
|
||||
*/
|
||||
private $valueResolver;
|
||||
|
||||
public function __construct(
|
||||
NameResolver $nameResolver,
|
||||
CallableNodeTraverser $callableNodeTraverser,
|
||||
ServiceNaming $serviceNaming,
|
||||
NodeRemovingCommander $nodeRemovingCommander,
|
||||
KernelTestCaseNodeAnalyzer $kernelTestCaseNodeAnalyzer,
|
||||
ValueResolver $valueResolver
|
||||
) {
|
||||
$this->nameResolver = $nameResolver;
|
||||
$this->callableNodeTraverser = $callableNodeTraverser;
|
||||
$this->serviceNaming = $serviceNaming;
|
||||
$this->nodeRemovingCommander = $nodeRemovingCommander;
|
||||
$this->kernelTestCaseNodeAnalyzer = $kernelTestCaseNodeAnalyzer;
|
||||
$this->valueResolver = $valueResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* E.g. $someService ↓
|
||||
* $this->someService
|
||||
*
|
||||
* @param string[][] $formerVariablesByMethods
|
||||
*/
|
||||
public function replaceFormerVariablesWithPropertyFetch(Class_ $class, array $formerVariablesByMethods): void
|
||||
{
|
||||
$this->callableNodeTraverser->traverseNodesWithCallable($class->stmts, function (Node $node) use (
|
||||
$formerVariablesByMethods
|
||||
): ?PropertyFetch {
|
||||
if (! $node instanceof Variable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$variableName = $this->nameResolver->getName($node);
|
||||
if ($variableName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var string $methodName */
|
||||
$methodName = $node->getAttribute(AttributeKey::METHOD_NAME);
|
||||
if (! isset($formerVariablesByMethods[$methodName][$variableName])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$serviceType = $formerVariablesByMethods[$methodName][$variableName];
|
||||
$propertyName = $this->serviceNaming->resolvePropertyNameFromServiceType($serviceType);
|
||||
|
||||
return new PropertyFetch(new Variable('this'), $propertyName);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[][]
|
||||
*/
|
||||
public function removeAndCollectFormerAssignedVariables(Class_ $class, bool $skipSetUpMethod = true): array
|
||||
{
|
||||
$formerVariablesByMethods = [];
|
||||
|
||||
$this->callableNodeTraverser->traverseNodesWithCallable($class->stmts, function (Node $node) use (
|
||||
&$formerVariablesByMethods,
|
||||
$skipSetUpMethod
|
||||
): ?PropertyFetch {
|
||||
if (! $node instanceof MethodCall) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($skipSetUpMethod) {
|
||||
if ($this->kernelTestCaseNodeAnalyzer->isSetUpOrEmptyMethod($node)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $this->kernelTestCaseNodeAnalyzer->isOnContainerGetMethodCall($node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$type = $this->valueResolver->getValue($node->args[0]->value);
|
||||
if ($type === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
|
||||
|
||||
if ($parentNode instanceof Assign) {
|
||||
$this->processAssign($node, $parentNode, $type, $formerVariablesByMethods);
|
||||
return null;
|
||||
}
|
||||
|
||||
$propertyName = $this->serviceNaming->resolvePropertyNameFromServiceType($type);
|
||||
|
||||
return new PropertyFetch(new Variable('this'), $propertyName);
|
||||
});
|
||||
|
||||
return $formerVariablesByMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[][] $formerVariablesByMethods
|
||||
*/
|
||||
private function processAssign(
|
||||
MethodCall $methodCall,
|
||||
Assign $assign,
|
||||
string $type,
|
||||
array &$formerVariablesByMethods
|
||||
): void {
|
||||
$variableName = $this->nameResolver->getName($assign->var);
|
||||
if ($variableName === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var string $methodName */
|
||||
$methodName = $methodCall->getAttribute(AttributeKey::METHOD_NAME);
|
||||
$formerVariablesByMethods[$methodName][$variableName] = $type;
|
||||
|
||||
$this->nodeRemovingCommander->addNode($assign);
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\PHPUnit\Rector\Class_;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
|
||||
use Rector\BetterPhpDocParser\Attributes\Ast\PhpDoc\AttributeAwarePhpDocTagNode;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
use Rector\PhpParser\Node\Manipulator\ClassManipulator;
|
||||
use Rector\PHPUnit\Manipulator\OnContainerGetCallManipulator;
|
||||
use Rector\Rector\AbstractPHPUnitRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
use Rector\SymfonyPHPUnit\Node\KernelTestCaseNodeFactory;
|
||||
use Rector\SymfonyPHPUnit\Rector\Class_\SelfContainerGetMethodCallFromTestToSetUpMethodRector;
|
||||
use Rector\SymfonyPHPUnit\SelfContainerMethodCallCollector;
|
||||
|
||||
/**
|
||||
* Inspiration
|
||||
* @see SelfContainerGetMethodCallFromTestToSetUpMethodRector
|
||||
*
|
||||
* @see https://github.com/shopsys/shopsys/pull/1392
|
||||
* @see https://github.com/jakzal/phpunit-injector
|
||||
*
|
||||
* @see \Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\SelfContainerGetMethodCallFromTestToInjectPropertyRectorTest
|
||||
*/
|
||||
final class SelfContainerGetMethodCallFromTestToInjectPropertyRector extends AbstractPHPUnitRector
|
||||
{
|
||||
/**
|
||||
* @var SelfContainerMethodCallCollector
|
||||
*/
|
||||
private $selfContainerMethodCallCollector;
|
||||
|
||||
/**
|
||||
* @var KernelTestCaseNodeFactory
|
||||
*/
|
||||
private $kernelTestCaseNodeFactory;
|
||||
|
||||
/**
|
||||
* @var OnContainerGetCallManipulator
|
||||
*/
|
||||
private $onContainerGetCallManipulator;
|
||||
|
||||
/**
|
||||
* @var ClassManipulator
|
||||
*/
|
||||
private $classManipulator;
|
||||
|
||||
public function __construct(
|
||||
SelfContainerMethodCallCollector $selfContainerMethodCallCollector,
|
||||
KernelTestCaseNodeFactory $kernelTestCaseNodeFactory,
|
||||
OnContainerGetCallManipulator $onContainerGetCallManipulator,
|
||||
ClassManipulator $classManipulator
|
||||
) {
|
||||
$this->selfContainerMethodCallCollector = $selfContainerMethodCallCollector;
|
||||
$this->kernelTestCaseNodeFactory = $kernelTestCaseNodeFactory;
|
||||
$this->onContainerGetCallManipulator = $onContainerGetCallManipulator;
|
||||
$this->classManipulator = $classManipulator;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition(
|
||||
'Change $container->get() calls in PHPUnit to @inject properties autowired by jakzal/phpunit-injector',
|
||||
[
|
||||
new CodeSample(
|
||||
<<<'PHP'
|
||||
use PHPUnit\Framework\TestCase;
|
||||
class SomeClassTest extends TestCase {
|
||||
public function test()
|
||||
{
|
||||
$someService = $this->getContainer()->get(SomeService::class);
|
||||
}
|
||||
}
|
||||
class SomeService { }
|
||||
PHP
|
||||
,
|
||||
<<<'PHP'
|
||||
use PHPUnit\Framework\TestCase;
|
||||
class SomeClassTest extends TestCase {
|
||||
/**
|
||||
* @var SomeService
|
||||
* @inject
|
||||
*/
|
||||
private $someService;
|
||||
public function test()
|
||||
{
|
||||
$someService = $this->someService;
|
||||
}
|
||||
}
|
||||
class SomeService { }
|
||||
PHP
|
||||
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Class_::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Class_ $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if (! $this->isInTestClass($node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 1. find self::$container->get(x)
|
||||
$serviceTypes = $this->selfContainerMethodCallCollector->collectContainerGetServiceTypes($node, false);
|
||||
if (count($serviceTypes) === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 2,5 - add @inject to existing properties of that type, to prevent re-adding them
|
||||
foreach ($serviceTypes as $key => $serviceType) {
|
||||
$existingProperty = $this->classManipulator->findPropertyByType($node, $serviceType);
|
||||
if ($existingProperty !== null) {
|
||||
$this->addInjectAnnotationToProperty($existingProperty);
|
||||
unset($serviceTypes[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. create private properties with this types
|
||||
$privateProperties = $this->kernelTestCaseNodeFactory->createPrivatePropertiesFromTypes($node, $serviceTypes);
|
||||
$this->addInjectAnnotationToProperties($privateProperties);
|
||||
$node->stmts = array_merge($privateProperties, $node->stmts);
|
||||
|
||||
// 3. remove old in-method $property assigns
|
||||
$formerVariablesByMethods = $this->onContainerGetCallManipulator->removeAndCollectFormerAssignedVariables(
|
||||
$node,
|
||||
false
|
||||
);
|
||||
|
||||
// 4. replace former variables by $this->someProperty
|
||||
$this->onContainerGetCallManipulator->replaceFormerVariablesWithPropertyFetch($node, $formerVariablesByMethods);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Property[] $properties
|
||||
*/
|
||||
private function addInjectAnnotationToProperties(array $properties): void
|
||||
{
|
||||
foreach ($properties as $privateProperty) {
|
||||
$this->addInjectAnnotationToProperty($privateProperty);
|
||||
}
|
||||
}
|
||||
|
||||
private function addInjectAnnotationToProperty(Property $privateProperty): void
|
||||
{
|
||||
/** @var PhpDocInfo $phpDocInfo */
|
||||
$phpDocInfo = $this->getPhpDocInfo($privateProperty);
|
||||
$phpDocNode = $phpDocInfo->getPhpDocNode();
|
||||
$phpDocNode->children[] = new AttributeAwarePhpDocTagNode('@inject', new GenericTagValueNode(''));
|
||||
|
||||
$this->docBlockManipulator->updateNodeWithPhpDocInfo($privateProperty, $phpDocInfo);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\Fixture;
|
||||
|
||||
use Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\Source\TestCaseWithGetContainer;
|
||||
|
||||
class AnotherCaseTest extends TestCaseWithGetContainer
|
||||
{
|
||||
protected function getDomainBaseUrl(): string
|
||||
{
|
||||
/** @var \Shopsys\FrameworkBundle\Component\Domain\Domain $domain */
|
||||
$domain = $this->getContainer()->get(Domain::class);
|
||||
|
||||
return $domain->getUrl();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\Fixture;
|
||||
|
||||
use Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\Source\TestCaseWithGetContainer;
|
||||
|
||||
class AnotherCaseTest extends TestCaseWithGetContainer
|
||||
{
|
||||
/**
|
||||
* @var Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\Fixture\Domain
|
||||
* @inject
|
||||
*/
|
||||
private $domain;
|
||||
protected function getDomainBaseUrl(): string
|
||||
{
|
||||
return $this->domain->getUrl();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\Fixture;
|
||||
|
||||
use Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\Source\TestCaseWithGetContainer;
|
||||
|
||||
class SomeClassTest extends TestCaseWithGetContainer
|
||||
{
|
||||
public function test()
|
||||
{
|
||||
$someService = $this->getContainer()->get(SomeService::class);
|
||||
$someService->someMethod();
|
||||
}
|
||||
}
|
||||
|
||||
class SomeService { }
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\Fixture;
|
||||
|
||||
use Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\Source\TestCaseWithGetContainer;
|
||||
|
||||
class SomeClassTest extends TestCaseWithGetContainer
|
||||
{
|
||||
/**
|
||||
* @var \Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\Fixture\SomeService
|
||||
* @inject
|
||||
*/
|
||||
private $someService;
|
||||
public function test()
|
||||
{
|
||||
$this->someService->someMethod();
|
||||
}
|
||||
}
|
||||
|
||||
class SomeService { }
|
||||
|
||||
?>
|
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\Fixture;
|
||||
|
||||
use Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\Source\RandomElasticClient;
|
||||
use Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\Source\TestCaseWithGetContainer;
|
||||
|
||||
class FromSetUpToInject extends TestCaseWithGetContainer
|
||||
{
|
||||
/**
|
||||
* @var RandomElasticClient
|
||||
*/
|
||||
private $elasticsearchClient;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->elasticsearchClient = $this->getContainer()->get(RandomElasticClient::class);
|
||||
}
|
||||
|
||||
public function testSomething()
|
||||
{
|
||||
$this->elasticsearchClient->init();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\Fixture;
|
||||
|
||||
use Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\Source\RandomElasticClient;
|
||||
use Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\Source\TestCaseWithGetContainer;
|
||||
|
||||
class FromSetUpToInject extends TestCaseWithGetContainer
|
||||
{
|
||||
/**
|
||||
* @var RandomElasticClient
|
||||
* @inject
|
||||
*/
|
||||
private $elasticsearchClient;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
}
|
||||
|
||||
public function testSomething()
|
||||
{
|
||||
$this->elasticsearchClient->init();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\PHPUnit\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
|
||||
final class SelfContainerGetMethodCallFromTestToInjectPropertyRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideDataForTest()
|
||||
*/
|
||||
public function test(string $file): void
|
||||
{
|
||||
$this->doTestFile($file);
|
||||
}
|
||||
|
||||
public function provideDataForTest(): Iterator
|
||||
{
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return SelfContainerGetMethodCallFromTestToInjectPropertyRector::class;
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\Source;
|
||||
|
||||
final class RandomElasticClient
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\PHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToInjectPropertyRector\Source;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
abstract class TestCaseWithGetContainer extends TestCase
|
||||
{
|
||||
public function getContainer(): ContainerInterface
|
||||
{
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
use Rector\ValueObject\PhpVersionFeature;
|
||||
|
||||
/**
|
||||
* @see https://3v4l.org/Bndc9
|
||||
@ -80,7 +81,7 @@ PHP
|
||||
$identicalNode = new Identical($countedNode, $this->createNull());
|
||||
$ternaryNode = new Ternary($identicalNode, new LNumber(0), $node);
|
||||
} else {
|
||||
if ($this->isAtLeastPhpVersion('7.3')) {
|
||||
if ($this->isAtLeastPhpVersion(PhpVersionFeature::IS_COUNTABLE)) {
|
||||
$conditionNode = new FuncCall(new Name('is_countable'), [new Arg($countedNode)]);
|
||||
} else {
|
||||
$conditionNode = new BooleanOr(
|
||||
|
@ -11,6 +11,7 @@ use PhpParser\Node\Expr\BinaryOp\Coalesce;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
use Rector\ValueObject\PhpVersionFeature;
|
||||
|
||||
/**
|
||||
* @see https://wiki.php.net/rfc/null_coalesce_equal_operator
|
||||
@ -48,7 +49,7 @@ PHP
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if (! $this->isAtLeastPhpVersion('7.4')) {
|
||||
if (! $this->isAtLeastPhpVersion(PhpVersionFeature::NULL_COALESCE_ASSIGN)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ use PhpParser\Node\Stmt\Return_;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
use Rector\ValueObject\PhpVersionFeature;
|
||||
|
||||
/**
|
||||
* @see https://wiki.php.net/rfc/arrow_functions_v2
|
||||
@ -62,7 +63,7 @@ PHP
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if (! $this->isAtLeastPhpVersion('7.4')) {
|
||||
if (! $this->isAtLeastPhpVersion(PhpVersionFeature::ARROW_FUNCTION)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ use PhpParser\Node\Scalar\LNumber;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
use Rector\ValueObject\PhpVersionFeature;
|
||||
|
||||
/**
|
||||
* @see https://wiki.php.net/rfc/numeric_literal_separator
|
||||
@ -69,7 +70,7 @@ PHP
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if (! $this->isAtLeastPhpVersion('7.4')) {
|
||||
if (! $this->isAtLeastPhpVersion(PhpVersionFeature::LITERAL_SEPARATOR)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
use Rector\TypeDeclaration\TypeInferer\PropertyTypeInferer;
|
||||
use Rector\ValueObject\PhpVersionFeature;
|
||||
|
||||
/**
|
||||
* @source https://wiki.php.net/rfc/typed_properties_v2#proposal
|
||||
@ -69,7 +70,7 @@ PHP
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if (! $this->isAtLeastPhpVersion('7.4')) {
|
||||
if (! $this->isAtLeastPhpVersion(PhpVersionFeature::TYPED_PROPERTIES)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,10 @@ namespace Rector\SymfonyPHPUnit\Node;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticPropertyFetch;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
use Rector\PhpParser\Node\Resolver\NameResolver;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
final class KernelTestCaseNodeAnalyzer
|
||||
{
|
||||
@ -16,33 +18,46 @@ final class KernelTestCaseNodeAnalyzer
|
||||
*/
|
||||
private $nameResolver;
|
||||
|
||||
public function __construct(NameResolver $nameResolver)
|
||||
/**
|
||||
* @var NodeTypeResolver
|
||||
*/
|
||||
private $nodeTypeResolver;
|
||||
|
||||
public function __construct(NameResolver $nameResolver, NodeTypeResolver $nodeTypeResolver)
|
||||
{
|
||||
$this->nameResolver = $nameResolver;
|
||||
$this->nodeTypeResolver = $nodeTypeResolver;
|
||||
}
|
||||
|
||||
public function isOnContainerGetMethodCall(Node $node): bool
|
||||
{
|
||||
return $this->isSelfContainerGetMethodCall($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is inside setUp() class method
|
||||
*/
|
||||
public function isSetUpOrEmptyMethod(Node $node): bool
|
||||
{
|
||||
$methodName = $node->getAttribute(AttributeKey::METHOD_NAME);
|
||||
|
||||
return $methodName === 'setUp' || $methodName === null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches:
|
||||
* self::$container->get()
|
||||
*/
|
||||
public function isSelfContainerGetMethodCall(Node $node): bool
|
||||
private function isSelfContainerGetMethodCall(Node $node): bool
|
||||
{
|
||||
if (! $node instanceof MethodCall) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $node->var instanceof StaticPropertyFetch) {
|
||||
if (! $this->nameResolver->isName($node->name, 'get')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $this->nameResolver->isName($node->var->class, 'self')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $this->nameResolver->isName($node->var->name, 'container')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->nameResolver->isName($node->name, 'get');
|
||||
return $this->nodeTypeResolver->isObjectType($node->var, ContainerInterface::class);
|
||||
}
|
||||
}
|
||||
|
@ -5,56 +5,42 @@ declare(strict_types=1);
|
||||
namespace Rector\SymfonyPHPUnit\Rector\Class_;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\PHPUnit\Manipulator\OnContainerGetCallManipulator;
|
||||
use Rector\Rector\AbstractPHPUnitRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
use Rector\SymfonyPHPUnit\Naming\ServiceNaming;
|
||||
use Rector\SymfonyPHPUnit\Node\KernelTestCaseNodeAnalyzer;
|
||||
use Rector\SymfonyPHPUnit\Node\KernelTestCaseNodeFactory;
|
||||
use Rector\SymfonyPHPUnit\SelfContainerMethodCallCollector;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
|
||||
/**
|
||||
* @see \Rector\SymfonyPHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToSetUpMethodRector\SelfContainerGetMethodCallFromTestToSetUpMethodRectorTest
|
||||
*/
|
||||
final class SelfContainerGetMethodCallFromTestToSetUpMethodRector extends AbstractRector
|
||||
final class SelfContainerGetMethodCallFromTestToSetUpMethodRector extends AbstractPHPUnitRector
|
||||
{
|
||||
/**
|
||||
* @var KernelTestCaseNodeAnalyzer
|
||||
*/
|
||||
private $kernelTestCaseNodeAnalyzer;
|
||||
|
||||
/**
|
||||
* @var KernelTestCaseNodeFactory
|
||||
*/
|
||||
private $kernelTestCaseNodeFactory;
|
||||
|
||||
/**
|
||||
* @var ServiceNaming
|
||||
*/
|
||||
private $serviceNaming;
|
||||
|
||||
/**
|
||||
* @var SelfContainerMethodCallCollector
|
||||
*/
|
||||
private $selfContainerMethodCallCollector;
|
||||
|
||||
/**
|
||||
* @var OnContainerGetCallManipulator
|
||||
*/
|
||||
private $onContainerGetCallManipulator;
|
||||
|
||||
public function __construct(
|
||||
KernelTestCaseNodeAnalyzer $kernelTestCaseNodeAnalyzer,
|
||||
KernelTestCaseNodeFactory $kernelTestCaseNodeFactory,
|
||||
ServiceNaming $serviceNaming,
|
||||
SelfContainerMethodCallCollector $selfContainerMethodCallCollector
|
||||
SelfContainerMethodCallCollector $selfContainerMethodCallCollector,
|
||||
OnContainerGetCallManipulator $onContainerGetCallManipulator
|
||||
) {
|
||||
$this->kernelTestCaseNodeAnalyzer = $kernelTestCaseNodeAnalyzer;
|
||||
$this->kernelTestCaseNodeFactory = $kernelTestCaseNodeFactory;
|
||||
$this->selfContainerMethodCallCollector = $selfContainerMethodCallCollector;
|
||||
$this->serviceNaming = $serviceNaming;
|
||||
$this->onContainerGetCallManipulator = $onContainerGetCallManipulator;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
@ -126,15 +112,11 @@ PHP
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if ($node->extends === null) {
|
||||
if (! $this->isInTestClass($node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->isObjectType($node, KernelTestCase::class)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 1. find self::$container->get(x) that are called more than in 1 method
|
||||
// 1. find self::$container->get(<X>)
|
||||
$serviceTypes = $this->selfContainerMethodCallCollector->collectContainerGetServiceTypes($node);
|
||||
if (count($serviceTypes) === 0) {
|
||||
return null;
|
||||
@ -160,91 +142,13 @@ PHP
|
||||
$node->stmts = array_merge($privateProperties, $node->stmts);
|
||||
|
||||
// 4. remove old in-method $property assigns
|
||||
$formerVariablesByMethods = $this->removeAndCollectFormerAssignedVariables($node);
|
||||
$formerVariablesByMethods = $this->onContainerGetCallManipulator->removeAndCollectFormerAssignedVariables(
|
||||
$node
|
||||
);
|
||||
|
||||
// 5. replace former variables by $this->someProperty
|
||||
$this->replaceFormerVariablesWithPropertyFetch($node, $formerVariablesByMethods);
|
||||
$this->onContainerGetCallManipulator->replaceFormerVariablesWithPropertyFetch($node, $formerVariablesByMethods);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[][]
|
||||
*/
|
||||
private function removeAndCollectFormerAssignedVariables(Class_ $class): array
|
||||
{
|
||||
$formerVariablesByMethods = [];
|
||||
|
||||
$this->traverseNodesWithCallable($class->stmts, function (Node $node) use (
|
||||
&$formerVariablesByMethods
|
||||
): ?PropertyFetch {
|
||||
if (! $node instanceof MethodCall) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// skip setUp() method
|
||||
$methodName = $node->getAttribute(AttributeKey::METHOD_NAME);
|
||||
if ($methodName === 'setUp' || $methodName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->kernelTestCaseNodeAnalyzer->isSelfContainerGetMethodCall($node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$type = $this->getValue($node->args[0]->value);
|
||||
if ($type === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
|
||||
if ($parentNode instanceof Assign) {
|
||||
$variableName = $this->getName($parentNode->var);
|
||||
if ($variableName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$formerVariablesByMethods[$methodName][$variableName] = $type;
|
||||
|
||||
$this->removeNode($parentNode);
|
||||
return null;
|
||||
}
|
||||
|
||||
$propertyName = $this->serviceNaming->resolvePropertyNameFromServiceType($type);
|
||||
|
||||
return new PropertyFetch(new Variable('this'), $propertyName);
|
||||
});
|
||||
|
||||
return $formerVariablesByMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[][] $formerVariablesByMethods
|
||||
*/
|
||||
private function replaceFormerVariablesWithPropertyFetch(Class_ $class, array $formerVariablesByMethods): void
|
||||
{
|
||||
$this->traverseNodesWithCallable($class->stmts, function (Node $node) use (
|
||||
$formerVariablesByMethods
|
||||
): ?PropertyFetch {
|
||||
if (! $node instanceof Variable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var string $methodName */
|
||||
$methodName = $node->getAttribute(AttributeKey::METHOD_NAME);
|
||||
$variableName = $this->getName($node);
|
||||
if ($variableName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! isset($formerVariablesByMethods[$methodName][$variableName])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$serviceType = $formerVariablesByMethods[$methodName][$variableName];
|
||||
$propertyName = $this->serviceNaming->resolvePropertyNameFromServiceType($serviceType);
|
||||
|
||||
return new PropertyFetch(new Variable('this'), $propertyName);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ namespace Rector\SymfonyPHPUnit;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\PhpParser\Node\Value\ValueResolver;
|
||||
use Rector\PhpParser\NodeTraverser\CallableNodeTraverser;
|
||||
use Rector\SymfonyPHPUnit\Node\KernelTestCaseNodeAnalyzer;
|
||||
@ -43,25 +42,30 @@ final class SelfContainerMethodCallCollector
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function collectContainerGetServiceTypes(Class_ $class): array
|
||||
public function collectContainerGetServiceTypes(Class_ $class, bool $skipSetUpMethod = true): array
|
||||
{
|
||||
$serviceTypes = [];
|
||||
|
||||
$this->callableNodeTraverser->traverseNodesWithCallable($class->stmts, function (Node $node) use (
|
||||
&$serviceTypes
|
||||
&$serviceTypes,
|
||||
$skipSetUpMethod
|
||||
) {
|
||||
if (! $this->kernelTestCaseNodeAnalyzer->isSelfContainerGetMethodCall($node)) {
|
||||
if (! $this->kernelTestCaseNodeAnalyzer->isOnContainerGetMethodCall($node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// skip setUp() method
|
||||
$methodName = $node->getAttribute(AttributeKey::METHOD_NAME);
|
||||
if ($methodName === 'setUp' || $methodName === null) {
|
||||
return null;
|
||||
if ($skipSetUpMethod) {
|
||||
if ($this->kernelTestCaseNodeAnalyzer->isSetUpOrEmptyMethod($node)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** @var MethodCall $node */
|
||||
$serviceType = $this->valueResolver->getValue($node->args[0]->value);
|
||||
if ($serviceType === null || ! is_string($serviceType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->shouldSkipServiceType($serviceType)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use Rector\SymfonyPHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTest
|
||||
|
||||
class ExistingSetUpTest extends KernelTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
protected function setUp(): void
|
||||
{
|
||||
$value = 5;
|
||||
}
|
||||
@ -40,7 +40,7 @@ class ExistingSetUpTest extends KernelTestCase
|
||||
* @var \Rector\SymfonyPHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToSetUpMethodRector\Source\ItemRepository
|
||||
*/
|
||||
private $itemRepository;
|
||||
protected function setUp()
|
||||
protected function setUp(): void
|
||||
{
|
||||
$value = 5;
|
||||
$this->itemRepository = self::$container->get(\Rector\SymfonyPHPUnit\Tests\Rector\Class_\SelfContainerGetMethodCallFromTestToSetUpMethodRector\Source\ItemRepository::class);
|
||||
|
@ -7,6 +7,7 @@ namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\AddMethodCallBasedPara
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Rector\TypeDeclaration\Rector\ClassMethod\AddMethodCallBasedParamTypeRector;
|
||||
use Rector\ValueObject\PhpVersionFeature;
|
||||
|
||||
final class AddMethodCallBasedParamTypeRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
@ -30,7 +31,6 @@ final class AddMethodCallBasedParamTypeRectorTest extends AbstractRectorTestCase
|
||||
|
||||
protected function getPhpVersion(): string
|
||||
{
|
||||
// prevents union types
|
||||
return '7.4';
|
||||
return PhpVersionFeature::BEFORE_UNION_TYPES;
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ namespace Rector\TypeDeclaration\Tests\Rector\Closure\AddClosureReturnTypeRector
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Rector\TypeDeclaration\Rector\Closure\AddClosureReturnTypeRector;
|
||||
use Rector\ValueObject\PhpVersionFeature;
|
||||
|
||||
final class AddClosureReturnTypeRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
@ -30,7 +31,6 @@ final class AddClosureReturnTypeRectorTest extends AbstractRectorTestCase
|
||||
|
||||
protected function getPhpVersion(): string
|
||||
{
|
||||
// prevent union types
|
||||
return '7.4';
|
||||
return PhpVersionFeature::BEFORE_UNION_TYPES;
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ namespace Rector\TypeDeclaration\Tests\Rector\FunctionLike\ParamTypeDeclarationR
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Rector\TypeDeclaration\Rector\FunctionLike\ParamTypeDeclarationRector;
|
||||
use Rector\ValueObject\PhpVersionFeature;
|
||||
|
||||
final class ParamTypeDeclarationRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
@ -30,7 +31,6 @@ final class ParamTypeDeclarationRectorTest extends AbstractRectorTestCase
|
||||
|
||||
protected function getPhpVersion(): string
|
||||
{
|
||||
// prevent union types
|
||||
return '7.4';
|
||||
return PhpVersionFeature::BEFORE_UNION_TYPES;
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ namespace Rector\TypeDeclaration\Tests\Rector\FunctionLike\ReturnTypeDeclaration
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Rector\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector;
|
||||
use Rector\ValueObject\PhpVersionFeature;
|
||||
|
||||
final class CorrectionTest extends AbstractRectorTestCase
|
||||
{
|
||||
@ -30,7 +31,6 @@ final class CorrectionTest extends AbstractRectorTestCase
|
||||
|
||||
protected function getPhpVersion(): string
|
||||
{
|
||||
// to prevent union types
|
||||
return '7.4';
|
||||
return PhpVersionFeature::BEFORE_UNION_TYPES;
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ namespace Rector\TypeDeclaration\Tests\Rector\FunctionLike\ReturnTypeDeclaration
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Rector\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector;
|
||||
use Rector\ValueObject\PhpVersionFeature;
|
||||
|
||||
final class ReturnTypeDeclarationRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
@ -30,7 +31,6 @@ final class ReturnTypeDeclarationRectorTest extends AbstractRectorTestCase
|
||||
|
||||
protected function getPhpVersion(): string
|
||||
{
|
||||
// to prevent union types
|
||||
return '7.4';
|
||||
return PhpVersionFeature::BEFORE_UNION_TYPES;
|
||||
}
|
||||
}
|
||||
|
@ -9,9 +9,17 @@ use PHPStan\Type\ObjectType;
|
||||
|
||||
final class PropertyNaming
|
||||
{
|
||||
public function fqnToVariableName(ObjectType $objectType): string
|
||||
/**
|
||||
* @param ObjectType|string $objectType
|
||||
* @return string
|
||||
*/
|
||||
public function fqnToVariableName($objectType): string
|
||||
{
|
||||
return lcfirst($this->fqnToShortName($objectType->getClassName()));
|
||||
if ($objectType instanceof ObjectType) {
|
||||
$objectType = $objectType->getClassName();
|
||||
}
|
||||
|
||||
return lcfirst($this->fqnToShortName($objectType));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,6 +21,7 @@ use PhpParser\Node\Stmt\TraitUse;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
use Rector\PhpParser\Node\Commander\NodeRemovingCommander;
|
||||
use Rector\PhpParser\Node\NodeFactory;
|
||||
use Rector\PhpParser\Node\Resolver\NameResolver;
|
||||
@ -59,13 +60,19 @@ final class ClassManipulator
|
||||
*/
|
||||
private $betterStandardPrinter;
|
||||
|
||||
/**
|
||||
* @var NodeTypeResolver
|
||||
*/
|
||||
private $nodeTypeResolver;
|
||||
|
||||
public function __construct(
|
||||
NameResolver $nameResolver,
|
||||
NodeFactory $nodeFactory,
|
||||
ChildAndParentClassManipulator $childAndParentClassManipulator,
|
||||
CallableNodeTraverser $callableNodeTraverser,
|
||||
NodeRemovingCommander $nodeRemovingCommander,
|
||||
BetterStandardPrinter $betterStandardPrinter
|
||||
BetterStandardPrinter $betterStandardPrinter,
|
||||
NodeTypeResolver $nodeTypeResolver
|
||||
) {
|
||||
$this->nodeFactory = $nodeFactory;
|
||||
$this->nameResolver = $nameResolver;
|
||||
@ -73,6 +80,7 @@ final class ClassManipulator
|
||||
$this->callableNodeTraverser = $callableNodeTraverser;
|
||||
$this->nodeRemovingCommander = $nodeRemovingCommander;
|
||||
$this->betterStandardPrinter = $betterStandardPrinter;
|
||||
$this->nodeTypeResolver = $nodeTypeResolver;
|
||||
}
|
||||
|
||||
public function addConstructorDependency(Class_ $classNode, string $name, ?Type $type): void
|
||||
@ -341,6 +349,19 @@ final class ClassManipulator
|
||||
$classMethod->stmts = array_merge($stmts, (array) $classMethod->stmts);
|
||||
}
|
||||
|
||||
public function findPropertyByType(Class_ $class, string $serviceType): ?Property
|
||||
{
|
||||
foreach ($class->getProperties() as $property) {
|
||||
if (! $this->nodeTypeResolver->isObjectType($property, $serviceType)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $property;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function tryInsertBeforeFirstMethod(Class_ $classNode, Stmt $stmt): bool
|
||||
{
|
||||
foreach ($classNode->stmts as $key => $classStmt) {
|
||||
|
@ -36,6 +36,36 @@ final class PhpVersionFeature
|
||||
*/
|
||||
public const OBJECT_TYPE = '7.2';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const IS_COUNTABLE = '7.3';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const ARROW_FUNCTION = '7.4';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const LITERAL_SEPARATOR = '7.4';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const NULL_COALESCE_ASSIGN = '7.4';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const TYPED_PROPERTIES = '7.4';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const BEFORE_UNION_TYPES = '7.4';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
@ -4,11 +4,17 @@ declare(strict_types=1);
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Test;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
if (class_exists('Symfony\Bundle\FrameworkBundle\Test\KernelTestCase')) {
|
||||
return;
|
||||
}
|
||||
|
||||
class KernelTestCase
|
||||
class KernelTestCase extends TestCase
|
||||
{
|
||||
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected static $container;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ if (class_exists('Symfony\Bundle\FrameworkBundle\Test\WebTestCase')) {
|
||||
return;
|
||||
}
|
||||
|
||||
class WebTestCase
|
||||
class WebTestCase extends KernelTestCase
|
||||
{
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user