From f534eabd24f9017d944252029602f8c59fdf4d77 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Fri, 29 May 2020 22:34:22 +0200 Subject: [PATCH] [Restoration] Add CompleteMissingDependencyInNewRector --- docs/rector_rules_overview.md | 40 ++++- .../CompleteMissingDependencyInNewRector.php | 157 ++++++++++++++++++ ...mpleteMissingDependencyInNewRectorTest.php | 37 +++++ .../Fixture/fixture.php.inc | 31 ++++ .../Source/RandomDependency.php | 9 + .../Source/RandomValueObject.php | 12 ++ 6 files changed, 284 insertions(+), 2 deletions(-) create mode 100644 rules/restoration/src/Rector/New_/CompleteMissingDependencyInNewRector.php create mode 100644 rules/restoration/tests/Rector/New_/CompleteMissingDependencyInNewRector/CompleteMissingDependencyInNewRectorTest.php create mode 100644 rules/restoration/tests/Rector/New_/CompleteMissingDependencyInNewRector/Fixture/fixture.php.inc create mode 100644 rules/restoration/tests/Rector/New_/CompleteMissingDependencyInNewRector/Source/RandomDependency.php create mode 100644 rules/restoration/tests/Rector/New_/CompleteMissingDependencyInNewRector/Source/RandomValueObject.php diff --git a/docs/rector_rules_overview.md b/docs/rector_rules_overview.md index 399a14589490..219921334215 100644 --- a/docs/rector_rules_overview.md +++ b/docs/rector_rules_overview.md @@ -1,4 +1,4 @@ -# All 494 Rectors Overview +# All 495 Rectors Overview - [Projects](#projects) - [General](#general) @@ -55,7 +55,7 @@ - [Refactoring](#refactoring) (2) - [RemovingStatic](#removingstatic) (4) - [Renaming](#renaming) (10) -- [Restoration](#restoration) (3) +- [Restoration](#restoration) (4) - [SOLID](#solid) (12) - [Sensio](#sensio) (1) - [StrictCodeQuality](#strictcodequality) (1) @@ -9091,6 +9091,42 @@ services:
+### `CompleteMissingDependencyInNewRector` + +- class: [`Rector\Restoration\Rector\New_\CompleteMissingDependencyInNewRector`](/../master/rules/restoration/src/Rector/New_/CompleteMissingDependencyInNewRector.php) +- [test fixtures](/../master/rules/restoration/tests/Rector/New_/CompleteMissingDependencyInNewRector/Fixture) + +Complete missing constructor dependency instance by type + +```yaml +services: + Rector\Restoration\Rector\New_\CompleteMissingDependencyInNewRector: + $classToInstantiateByType: + RandomDependency: RandomDependency +``` + +↓ + +```diff + final class SomeClass + { + public function run() + { +- $valueObject = new RandomValueObject(); ++ $valueObject = new RandomValueObject(new RandomDependency()); + } + } + + class RandomValueObject + { + public function __construct(RandomDependency $randomDependency) + { + } + } +``` + +
+ ### `MissingClassConstantReferenceToStringRector` - class: [`Rector\Restoration\Rector\ClassConstFetch\MissingClassConstantReferenceToStringRector`](/../master/rules/restoration/src/Rector/ClassConstFetch/MissingClassConstantReferenceToStringRector.php) diff --git a/rules/restoration/src/Rector/New_/CompleteMissingDependencyInNewRector.php b/rules/restoration/src/Rector/New_/CompleteMissingDependencyInNewRector.php new file mode 100644 index 000000000000..61652242a34a --- /dev/null +++ b/rules/restoration/src/Rector/New_/CompleteMissingDependencyInNewRector.php @@ -0,0 +1,157 @@ +classToInstantiateByType = $classToInstantiateByType; + } + + public function getDefinition(): RectorDefinition + { + return new RectorDefinition('Complete missing constructor dependency instance by type', [ + new ConfiguredCodeSample( + <<<'PHP' +final class SomeClass +{ + public function run() + { + $valueObject = new RandomValueObject(); + } +} + +class RandomValueObject +{ + public function __construct(RandomDependency $randomDependency) + { + } +} +PHP +, + <<<'PHP' +final class SomeClass +{ + public function run() + { + $valueObject = new RandomValueObject(new RandomDependency()); + } +} + +class RandomValueObject +{ + public function __construct(RandomDependency $randomDependency) + { + } +} +PHP + , [ + '$classToInstantiateByType' => [ + 'RandomDependency' => 'RandomDependency', + ], + ] + ), + ]); + } + + /** + * @return string[] + */ + public function getNodeTypes(): array + { + return [New_::class]; + } + + /** + * @param New_ $node + */ + public function refactor(Node $node): ?Node + { + if ($this->shouldSkipNew($node)) { + return null; + } + + /** @var ReflectionMethod $constructorMethodReflection */ + $constructorMethodReflection = $this->getNewNodeClassConstructorMethodReflection($node); + + foreach ($constructorMethodReflection->getParameters() as $position => $parameterReflection) { + // argument is already set + if (isset($node->args[$position])) { + continue; + } + + $classToInstantiate = $this->resolveClassToInstantiateByParameterReflection($parameterReflection); + if ($classToInstantiate === null) { + continue; + } + + $new = new New_(new FullyQualified($classToInstantiate)); + $node->args[$position] = new Arg($new); + } + + return $node; + } + + private function shouldSkipNew(New_ $new): bool + { + $constructorMethodReflection = $this->getNewNodeClassConstructorMethodReflection($new); + if ($constructorMethodReflection === null) { + return true; + } + + return $constructorMethodReflection->getNumberOfRequiredParameters() <= count($new->args); + } + + private function getNewNodeClassConstructorMethodReflection(New_ $new): ?ReflectionMethod + { + $className = $this->getName($new->class); + if ($className === null) { + return null; + } + + if (! class_exists($className)) { + return null; + } + + $reflectionClass = new ReflectionClass($className); + + return $reflectionClass->getConstructor(); + } + + private function resolveClassToInstantiateByParameterReflection(ReflectionParameter $reflectionParameter): ?string + { + $parameterType = $reflectionParameter->getType(); + if ($parameterType === null) { + return null; + } + + $requiredType = (string) $parameterType; + + return $this->classToInstantiateByType[$requiredType] ?? null; + } +} diff --git a/rules/restoration/tests/Rector/New_/CompleteMissingDependencyInNewRector/CompleteMissingDependencyInNewRectorTest.php b/rules/restoration/tests/Rector/New_/CompleteMissingDependencyInNewRector/CompleteMissingDependencyInNewRectorTest.php new file mode 100644 index 000000000000..ef8d511ad4d0 --- /dev/null +++ b/rules/restoration/tests/Rector/New_/CompleteMissingDependencyInNewRector/CompleteMissingDependencyInNewRectorTest.php @@ -0,0 +1,37 @@ +doTestFile($file); + } + + public function provideData(): Iterator + { + return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + protected function getRectorsWithConfiguration(): array + { + return [ + CompleteMissingDependencyInNewRector::class => [ + '$classToInstantiateByType' => [ + RandomDependency::class => RandomDependency::class, + ], + ], + ]; + } +} diff --git a/rules/restoration/tests/Rector/New_/CompleteMissingDependencyInNewRector/Fixture/fixture.php.inc b/rules/restoration/tests/Rector/New_/CompleteMissingDependencyInNewRector/Fixture/fixture.php.inc new file mode 100644 index 000000000000..19e63f82a588 --- /dev/null +++ b/rules/restoration/tests/Rector/New_/CompleteMissingDependencyInNewRector/Fixture/fixture.php.inc @@ -0,0 +1,31 @@ + +----- + diff --git a/rules/restoration/tests/Rector/New_/CompleteMissingDependencyInNewRector/Source/RandomDependency.php b/rules/restoration/tests/Rector/New_/CompleteMissingDependencyInNewRector/Source/RandomDependency.php new file mode 100644 index 000000000000..1794357034b2 --- /dev/null +++ b/rules/restoration/tests/Rector/New_/CompleteMissingDependencyInNewRector/Source/RandomDependency.php @@ -0,0 +1,9 @@ +