Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FrameworkBundle][DependencyInjection] Skip removed ids in the lint container command and its associated pass #34935

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,17 @@
use Symfony\Component\Config\ConfigCache;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\DependencyInjection\Compiler\CheckTypeDeclarationsPass;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
use Symfony\Component\HttpKernel\Kernel;

final class ContainerLintCommand extends Command
{
Expand All @@ -47,13 +51,18 @@ protected function configure()
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$container = $this->getContainerBuilder();
$io = new SymfonyStyle($input, $output);
$errorIo = $io->getErrorStyle();

$container->setParameter('container.build_hash', 'lint_container');
$container->setParameter('container.build_time', time());
$container->setParameter('container.build_id', 'lint_container');
try {
$container = $this->getContainerBuilder();
} catch (RuntimeException $e) {
$errorIo->error($e->getMessage());

return 2;
}

$container->addCompilerPass(new CheckTypeDeclarationsPass(true), PassConfig::TYPE_AFTER_REMOVING, -100);
$container->setParameter('container.build_time', time());

$container->compile();

Expand All @@ -67,22 +76,44 @@ private function getContainerBuilder(): ContainerBuilder
}

$kernel = $this->getApplication()->getKernel();
$kernelContainer = $kernel->getContainer();

if (!$kernel->isDebug() || !(new ConfigCache($kernelContainer->getParameter('debug.container.dump'), true))->isFresh()) {
if (!$kernel instanceof Kernel) {
throw new RuntimeException("This command does not support the console application's kernel.");
}

if (!$kernel->isDebug() || !(new ConfigCache($kernel->getContainer()->getParameter('debug.container.dump'), true))->isFresh()) {
$buildContainer = \Closure::bind(function (): ContainerBuilder {
$this->initializeBundles();

return $this->buildContainer();
}, $kernel, \get_class($kernel));
$container = $buildContainer();

$skippedIds = [];
} else {
(new XmlFileLoader($container = new ContainerBuilder($parameterBag = new EnvPlaceholderParameterBag()), new FileLocator()))->load($kernel->getContainer()->getParameter('debug.container.dump'));
if (!$kernelContainer instanceof Container) {
throw new RuntimeException("This command does not support the console application kernel's container.");
}

(new XmlFileLoader($container = new ContainerBuilder($parameterBag = new EnvPlaceholderParameterBag()), new FileLocator()))->load($kernelContainer->getParameter('debug.container.dump'));

$refl = new \ReflectionProperty($parameterBag, 'resolved');
$refl->setAccessible(true);
$refl->setValue($parameterBag, true);

$passConfig = $container->getCompilerPassConfig();
$passConfig->setRemovingPasses([]);
$passConfig->setAfterRemovingPasses([]);

$skippedIds = $kernelContainer->getRemovedIds();
}

$container->setParameter('container.build_hash', 'lint_container');
$container->setParameter('container.build_id', 'lint_container');

$container->addCompilerPass(new CheckTypeDeclarationsPass(true, $skippedIds), PassConfig::TYPE_AFTER_REMOVING, -100);

return $this->containerBuilder = $container;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,23 +42,30 @@ final class CheckTypeDeclarationsPass extends AbstractRecursivePass
private const SCALAR_TYPES = ['int', 'float', 'bool', 'string'];

private $autoload;
private $skippedIds;

private $expressionLanguage;

/**
* @param bool $autoload Whether services who's class in not loaded should be checked or not.
* Defaults to false to save loading code during compilation.
* @param bool $autoload Whether services who's class in not loaded should be checked or not.
* Defaults to false to save loading code during compilation.
* @param array $skippedIds An array indexed by the service ids to skip
*/
public function __construct(bool $autoload = false)
public function __construct(bool $autoload = false, array $skippedIds = [])
{
$this->autoload = $autoload;
$this->skippedIds = $skippedIds;
}

/**
* {@inheritdoc}
*/
protected function processValue($value, $isRoot = false)
{
if (isset($this->skippedIds[$this->currentId])) {
return $value;
}

if (!$value instanceof Definition || $value->hasErrors()) {
return parent::processValue($value, $isRoot);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -669,4 +669,16 @@ public function testProcessHandleNotFoundEnvPlaceholder()

$this->addToAssertionCount(1);
}

public function testProcessSkipSkippedIds()
{
$container = new ContainerBuilder();
$container
->register('foobar', BarMethodCall::class)
->addMethodCall('setArray', ['a string']);

(new CheckTypeDeclarationsPass(true, ['foobar' => true]))->process($container);

$this->addToAssertionCount(1);
}
}