Skip to content

Commit 6e196ef

Browse files
authored
[DependencyInjection] Extract GetByTypeMethodCallToConstructorInjectionRector to make migration smoother (#685)
* tidy up * [DependencyInjection] Extract GetByTypeMethodCallToConstructorInjectionRector to make migration smoother
1 parent dfec6fd commit 6e196ef

File tree

14 files changed

+328
-95
lines changed

14 files changed

+328
-95
lines changed

config/sets/symfony/symfony-constructor-injection.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99

1010
return static function (RectorConfig $rectorConfig): void {
1111
$rectorConfig->rules([
12+
// modern step-by-step narrow approach
13+
\Rector\Symfony\DependencyInjection\Rector\Class_\ControllerGetByTypeToConstructorInjectionRector::class,
14+
15+
// legacy rules that require container fetch
1216
ContainerGetToConstructorInjectionRector::class,
1317
ContainerGetNameToTypeInTestsRector::class,
1418
GetToConstructorInjectionRector::class,
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Symfony\Tests\DependencyInjection\Rector\Class_\ControllerGetByTypeToConstructorInjectionRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class ControllerGetByTypeToConstructorInjectionRectorTest extends AbstractRectorTestCase
12+
{
13+
#[DataProvider('provideData')]
14+
public function test(string $filePath): void
15+
{
16+
$this->doTestFile($filePath);
17+
}
18+
19+
public static function provideData(): Iterator
20+
{
21+
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
22+
}
23+
24+
public function provideConfigFilePath(): string
25+
{
26+
return __DIR__ . '/config/configured_rule.php';
27+
}
28+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace Rector\Symfony\Tests\DependencyInjection\Rector\Class_\ControllerGetByTypeToConstructorInjectionRector\Fixture;
4+
5+
use Rector\Symfony\Tests\DependencyInjection\Rector\Class_\ControllerGetByTypeToConstructorInjectionRector\Source\SomeService;
6+
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
7+
8+
final class ControllerGetWithType extends Controller
9+
{
10+
public function configure()
11+
{
12+
$someType = $this->get(SomeService::class);
13+
}
14+
}
15+
16+
?>
17+
-----
18+
<?php
19+
20+
namespace Rector\Symfony\Tests\DependencyInjection\Rector\Class_\ControllerGetByTypeToConstructorInjectionRector\Fixture;
21+
22+
use Rector\Symfony\Tests\DependencyInjection\Rector\Class_\ControllerGetByTypeToConstructorInjectionRector\Source\SomeService;
23+
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
24+
25+
final class ControllerGetWithType extends Controller
26+
{
27+
public function __construct(private \Rector\Symfony\Tests\DependencyInjection\Rector\Class_\ControllerGetByTypeToConstructorInjectionRector\Source\SomeService $someService)
28+
{
29+
}
30+
public function configure()
31+
{
32+
$someType = $this->someService;
33+
}
34+
}
35+
36+
?>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Rector\Symfony\Tests\DependencyInjection\Rector\Class_\ControllerGetByTypeToConstructorInjectionRector\Fixture;
4+
5+
use Rector\Symfony\Tests\DependencyInjection\Rector\Class_\ControllerGetByTypeToConstructorInjectionRector\Source\SomeService;
6+
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
7+
8+
final class SkipAnotherGet extends Controller
9+
{
10+
public function configure()
11+
{
12+
$someType = $this->some->get(SomeService::class);
13+
}
14+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Rector\Symfony\Tests\DependencyInjection\Rector\Class_\ControllerGetByTypeToConstructorInjectionRector\Fixture;
4+
5+
use Rector\Symfony\Tests\DependencyInjection\Rector\Class_\ControllerGetByTypeToConstructorInjectionRector\Source\SomeService;
6+
7+
final class SkipNonController
8+
{
9+
public function configure()
10+
{
11+
$someType = $this->get(SomeService::class);
12+
}
13+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Rector\Symfony\Tests\DependencyInjection\Rector\Class_\ControllerGetByTypeToConstructorInjectionRector\Source;
4+
5+
final class SomeService
6+
{
7+
8+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
7+
return static function (RectorConfig $rectorConfig): void {
8+
$rectorConfig->rule(
9+
\Rector\Symfony\DependencyInjection\Rector\Class_\ControllerGetByTypeToConstructorInjectionRector::class
10+
);
11+
};

rules-tests/Symfony42/Rector/MethodCall/ContainerGetToConstructorInjectionRector/Fixture/skip_test_case_static_call.php.inc

Lines changed: 0 additions & 13 deletions
This file was deleted.

rules-tests/Symfony42/Rector/MethodCall/ContainerGetToConstructorInjectionRector/Fixture/some_translator_exists3.php.inc

Lines changed: 0 additions & 55 deletions
This file was deleted.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Symfony\DependencyInjection\NodeDecorator;
6+
7+
use PhpParser\Node\Expr\StaticCall;
8+
use PhpParser\Node\Name;
9+
use PhpParser\Node\Stmt\Class_;
10+
use PhpParser\Node\Stmt\ClassMethod;
11+
use PhpParser\Node\Stmt\Expression;
12+
use PHPStan\Type\ObjectType;
13+
use Rector\NodeTypeResolver\NodeTypeResolver;
14+
use Rector\ValueObject\MethodName;
15+
16+
final class CommandConstructorDecorator
17+
{
18+
public function __construct(
19+
private NodeTypeResolver $nodeTypeResolver
20+
) {
21+
}
22+
23+
public function decorate(Class_ $class): void
24+
{
25+
// special case for command to keep parent constructor call
26+
if (! $this->nodeTypeResolver->isObjectType(
27+
$class,
28+
new ObjectType('Symfony\Component\Console\Command\Command')
29+
)) {
30+
return;
31+
}
32+
33+
$constuctClassMethod = $class->getMethod(MethodName::CONSTRUCT);
34+
if (! $constuctClassMethod instanceof ClassMethod) {
35+
return;
36+
}
37+
38+
// empty stmts? add parent::__construct() to setup command
39+
if ((array) $constuctClassMethod->stmts === []) {
40+
$parentConstructStaticCall = new StaticCall(new Name('parent'), '__construct');
41+
$constuctClassMethod->stmts[] = new Expression($parentConstructStaticCall);
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)