8000 feature #32256 [DI] Add compiler pass and command to check that servi… · symfony/symfony@29fd51f · GitHub
[go: up one dir, main page]

Skip to content

Commit 29fd51f

Browse files
feature #32256 [DI] Add compiler pass and command to check that services wiring matches type declarations (alcalyn, GuilhemN, nicolas-grekas)
This PR was merged into the 4.4 branch. Discussion ---------- [DI] Add compiler pass and command to check that services wiring matches type declarations | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #27744 | License | MIT | Doc PR | PR replacing #27825. It adds a `lint:container` command asserting the type hints used in your code are correct. Commits ------- 8230a15 Make it really work on real apps 4b3e9d4 Fix comments, improve the feature a6292b9 [DI] Add compiler pass to check arguments type hint
2 parents 08a218c + 8230a15 commit 29fd51f

File tree

31 files changed

+1030
-2
lines changed

31 files changed

+1030
-2
lines changed

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
4.4.0
55
-----
66

7+
* Added `lint:container` command to check that services wiring matches type declarations
78
* Added `MailerAssertionsTrait`
89
* Deprecated support for `templating` engine in `TemplateController`, use Twig instead
910
* Deprecated the `$parser` argument of `ControllerResolver::__construct()` and `DelegatingLoader::__construct()`
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Command;
13+
14+
use Symfony\Component\Config\ConfigCache;
15+
use Symfony\Component\Config\FileLocator;
16+
use Symfony\Component\Console\Command\Command;
17+
use Symfony\Component\Console\Input\InputInterface;
18+
use Symfony\Component\Console\Output\OutputInterface;
19+
use Symfony\Component\DependencyInjection\Compiler\CheckTypeDeclarationsPass;
20+
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
21+
use Symfony\Component\DependencyInjection\ContainerBuilder;
22+
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
23+
24+
final class ContainerLintCommand extends Command
25+
{
26+
protected static $defaultName = 'lint:container';
27+
28+
/**
29+
* @var ContainerBuilder
30+
*/
31+
private $containerBuilder;
32+
33+
/**
34+
* {@inheritdoc}
35+
*/
36+
protected function configure()
37+
{
38+
$this
39+
->setDescription('Ensures that arguments injected into services match type declarations')
40+
->setHelp('This command parses service definitions and ensures that injected values match the type declarations of each services\' class.')
41+
;
42+
}
43+
44+
/**
45+
* {@inheritdoc}
46+
*/
47+
protected function execute(InputInterface $input, OutputInterface $output): int
48+
{
49+
$container = $this->getContainerBuilder();
50+
51+
$container->setParameter('container.build_hash', 'lint_container');
52+
$container->setParameter('container.build_time', time());
53+
$container->setParameter('container.build_id', 'lint_container');
54+
55+
$container->addCompilerPass(new CheckTypeDeclarationsPass(true), PassConfig::TYPE_AFTER_REMOVING, -100);
56+
57+
$container->compile();
58+
59+
return 0;
60+
}
61+
62+
private function getContainerBuilder(): ContainerBuilder
63+
{
64+
if ($this->containerBuilder) {
65+
return $this->containerBuilder;
66+
}
67+
68+
$kernel = $this->getApplication()->getKernel();
69+
70+
if (!$kernel->isDebug() || !(new ConfigCache($kernel->getContainer()->getParameter('debug.container.dump'), true))->isFresh()) {
71+
$buildContainer = \Closure::bind(function () { return $this->buildContainer(); }, $kernel, \get_class($kernel));
72+
$container = $buildContainer();
73+
$container->getCompilerPassConfig()->setRemovingPasses([]);
74+
} else {
75+
(new XmlFileLoader($container = new ContainerBuilder(), new FileLocator()))->load($kernel->getContainer()->getParameter('debug.container.dump'));
76+
}
77+
78+
return $this->containerBuilder = $container;
79+
}
80+
}

src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@
7070
<tag name="console.command" command="debug:container" />
7171
</service>
7272

73+
<service id="console.command.container_lint" class="Symfony\Bundle\FrameworkBundle\Command\ContainerLintCommand">
74+
<tag name="console.command" command="lint:container" />
75+
</service>
76+
7377
<service id="console.command.debug_autowiring" class="Symfony\Bundle\FrameworkBundle\Command\DebugAutowiringCommand">
7478
<argument>null</argument>
7579
<argument type="service" id="debug.file_link_formatter" on-invalid="null"/>

src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
</service>
1818
<service id="Symfony\Component\Validator\Validator\ValidatorInterface" alias="validator" />
1919

20-
<service id="validator.builder" class="Symfony\Component\Validator\ValidatorBuilderInterface">
20+
<service id="validator.builder" class="Symfony\Component\Validator\ValidatorBuilder">
2121
<factory class="Symfony\Component\Validator\Validation" method="createValidatorBuilder" />
2222
<call method="setConstraintValidatorFactory">
2323
<argument type="service" id="validator.validator_factory" />

src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TestBundle.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\DependencyInjection\AnnotationReaderPass;
1515
use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\DependencyInjection\Config\CustomConfig;
1616
use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\DependencyInjection\TranslationDebugPass;
17+
use Symfony\Component\DependencyInjection\Compiler\CheckTypeDeclarationsPass;
18+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
1719
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
1820
use Symfony\Component\DependencyInjection\ContainerBuilder;
1921
use Symfony\Component\HttpKernel\Bundle\Bundle;
@@ -31,5 +33,15 @@ public function build(ContainerBuilder $container)
3133

3234
$container->addCompilerPass(new AnnotationReaderPass(), PassConfig::TYPE_AFTER_REMOVING);
3335
$container->addCompilerPass(new TranslationDebugPass());
36+
37+
$container->addCompilerPass(new class() implements CompilerPassInterface {
38+
public function process(ContainerBuilder $container)
39+
{
40+
$container->removeDefinition('twig.controller.exception');
41+
$container->removeDefinition('twig.controller.preview_error');
42+
}
43+
});
44+
45+
$container->addCompilerPass(new CheckTypeDeclarationsPass(true), PassConfig::TYPE_AFTER_REMOVING, -100);
3446
}
3547
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle;
13+
14+
use Symfony\Component\DependencyInjection\Compiler\CheckTypeDeclarationsPass;
15+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
16+
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
17+
use Symfony\Component\DependencyInjection\ContainerBuilder;
18+
use Symfony\Component\HttpKernel\Bundle\Bundle;
19+
20+
class TestBundle extends Bundle
21+
{
22+
public function build(ContainerBuilder $container)
23+
{
24+
$container->setParameter('container.build_hash', 'test_bundle');
25+
$container->setParameter('container.build_time', time());
26+
$container->setParameter('container.build_id', 'test_bundle');
27+
28+
$container->addCompilerPass(new class() implements CompilerPassInterface {
29+
public function process(ContainerBuilder $container)
30+
{
31+
$container->removeDefinition('twig.controller.exception');
32+
$container->removeDefinition('twig.controller.preview_error');
33+
}
34+
});
35+
36+
$container->addCompilerPass(new CheckTypeDeclarationsPass(true), PassConfig::TYPE_AFTER_REMOVING, -100);
37+
}
38+
}

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AbstractTokenCompareRoles/bundles.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff li 10000 ne numberDiff line change
@@ -12,9 +12,11 @@
1212
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
1313
use Symfony\Bundle\SecurityBundle\SecurityBundle;
1414
use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\SecuredPageBundle\SecuredPageBundle;
15+
use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\TestBundle;
1516

1617
return [
1718
new FrameworkBundle(),
1819
new SecurityBundle(),
1920
new SecuredPageBundle(),
21+
new TestBundle(),
2022
];

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AliasedEvents/bundles.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
1313
use Symfony\Bundle\SecurityBundle\SecurityBundle;
1414
use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\EventBundle\EventBundle;
15+
use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\TestBundle;
1516

1617
return [
1718
new FrameworkBundle(),
1819
new SecurityBundle(),
1920
new EventBundle(),
21+
new TestBundle(),
2022
];

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AutowiringTypes/bundles.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@
1313
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
1414
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
1515
new Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AutowiringBundle\AutowiringBundle(),
16+
new Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\TestBundle(),
1617
];

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CsrfFormLogin/bundles.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@
1414
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
1515
new Symfony\Bundle\TwigBundle\TwigBundle(),
1616
new Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\CsrfFormLoginBundle\CsrfFormLoginBundle(),
17+
new Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\TestBundle(),
1718
];

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/FirewallEntryPoint/bundles.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@
1313
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
1414
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
1515
new Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FirewallEntryPointBundle\FirewallEntryPointBundle(),
16+
new Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\TestBundle(),
1617
];

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/bundles.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@
1313
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
1414
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
1515
new Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\JsonLoginBundle\JsonLoginBundle(),
16+
new Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\TestBundle(),
1617
];

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLoginLdap/bundles.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@
1212
return [
1313
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
1414
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
15+
new Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\TestBundle(),
1516
];

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/LogoutAccess/bundles.php

Lines changed: 2 additions & 0 deletions
D7AE
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111

1212
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
1313
use Symfony\Bundle\SecurityBundle\SecurityBundle;
14+
use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\TestBundle;
1415

1516
return [
1617
new FrameworkBundle(),
1718
new SecurityBundle(),
19+
new TestBundle(),
1820
];

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/LogoutWithoutSessionInvalidation/bundles.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111

1212
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
1313
use Symfony\Bundle\SecurityBundle\SecurityBundle;
14+
use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\TestBundle;
1415

1516
return [
1617
new FrameworkBundle(),
1718
new SecurityBundle(),
19+
new TestBundle(),
1820
];

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/MissingUserProvider/bundles.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
1313
use Symfony\Bundle\SecurityBundle\SecurityBundle;
1414
use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\MissingUserProviderBundle\MissingUserProviderBundle;
15+
use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\TestBundle;
1516

1617
return [
1718
new FrameworkBundle(),
1819
new SecurityBundle(),
1920
new MissingUserProviderBundle(),
21+
new TestBundle(),
2022
];

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/bundles.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@
1212
return [
1313
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
1414
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
15+
new Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\TestBundle(),
1516
];

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/RememberMeLogout/bundles.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111

1212
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
1313
use Symfony\Bundle\SecurityBundle\SecurityBundle;
14+
use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\TestBundle;
1415

1516
return [
1617
new FrameworkBundle(),
1718
new SecurityBundle(),
19+
new TestBundle(),
1820
];

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/SecurityHelper/bundles.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111

1212
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
1313
use Symfony\Bundle\SecurityBundle\SecurityBundle;
14+
use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\TestBundle;
1415

1516
return [
1617
new FrameworkBundle(),
1718
new SecurityBundle(),
19+
new TestBundle(),
1820
];

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/bundles.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
1313
use Symfony\Bundle\SecurityBundle\SecurityBundle;
1414
use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FormLoginBundle\FormLoginBundle;
15+
use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\TestBundle;
1516
use Symfony\Bundle\TwigBundle\TwigBundle;
1617

1718
return [
1819
new FrameworkBundle(),
1920
new SecurityBundle(),
2021
new TwigBundle(),
2122
new FormLoginBundle(),
23+
new TestBundle(),
2224
];

src/Symfony/Bundle/SecurityBundle/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"php": "^7.1.3",
2020
"ext-xml": "*",
2121
"symfony/config": "^4.2|^5.0",
22-
"symfony/dependency-injection": "^4.2|^5.0",
22+
"symfony/dependency-injection": "^4.4|^5.0",
2323
"symfony/http-kernel": "^4.4",
2424
"symfony/security-core": "^4.4",
2525
"symfony/security-csrf": "^4.2|^5.0",

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
4.4.0
55
-----
66

7+
* added `CheckTypeDeclarationsPass` to check injected parameters type during compilation
78
* added support for opcache.preload by generating a preloading script in the cache folder
89
* added support for dumping the container in one file instead of many files
910
* deprecated support for short factories and short configurators in Yaml

src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,12 @@ protected function getConstructor(Definition $definition, $required)
133133
list($class, $method) = $factory;
134134
if ($class instanceof Reference) {
135135
$class = $this->container->findDefinition((string) $class)->getClass();
136+
} elseif ($class instanceof Definition) {
137+
$class = $class->getClass();
136138
} elseif (null === $class) {
137139
$class = $definition->getClass();
138140
}
141+
139142
if ('__construct' === $method) {
140143
throw new RuntimeException(sprintf('Invalid service "%s": "__construct()" cannot be used as a factory method.', $this->currentId));
141144
}

0 commit comments

Comments
 (0)
0