Skip to content

Commit e804022

Browse files
[DependencyInjection][FrameworkBundle] Use php-serialize to dump the container for debug/link commands
1 parent d92477a commit e804022

File tree

4 files changed

+73
-19
lines changed

4 files changed

+73
-19
lines changed

src/Symfony/Bundle/FrameworkBundle/Command/BuildDebugContainerTrait.php

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ protected function getContainerBuilder(KernelInterface $kernel): ContainerBuilde
3939
return $this->container;
4040
}
4141

42-
if (!$kernel->isDebug() || !$kernel->getContainer()->getParameter('debug.container.dump') || !(new ConfigCache($kernel->getContainer()->getParameter('debug.container.dump'), true))->isFresh()) {
42+
$file = $kernel->isDebug ? $kernel->getContainer()->getParameter('debug.container.dump') : false;
43+
44+
if (!$file || !(new ConfigCache($file, true))->isFresh()) {
4345
$buildContainer = \Closure::bind(function () {
4446
$this->initializeBundles();
4547

@@ -57,13 +59,17 @@ protected function getContainerBuilder(KernelInterface $kernel): ContainerBuilde
5759
return $containerBuilder;
5860
}, $kernel, $kernel::class);
5961
$container = $buildContainer();
60-
(new XmlFileLoader($container, new FileLocator()))->load($kernel->getContainer()->getParameter('debug.container.dump'));
61-
$locatorPass = new ServiceLocatorTagPass();
62-
$locatorPass->process($container);
6362

64-
$container->getCompilerPassConfig()->setBeforeOptimizationPasses([]);
65-
$container->getCompilerPassConfig()->setOptimizationPasses([]);
66-
$container->getCompilerPassConfig()->setBeforeRemovingPasses([]);
63+
if (str_ends_with($file, '.xml') && is_file(substr_replace($file, '.ser', -4))) {
64+
$dumpedContainer = unserialize(file_get_contents(substr_replace($file, '.ser', -4)));
65+
$container->setDefinitions($dumpedContainer->getDefinitions());
66+
$container->setAliases($dumpedContainer->getAliases());
67+
$container->__construct($dumpedContainer->getParameterBag());
68+
} else {
69+
(new XmlFileLoader($container, new FileLocator()))->load($file);
70+
$locatorPass = new ServiceLocatorTagPass();
71+
$locatorPass->process($container);
72+
}
6773
}
6874

6975
return $this->container = $container;

src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,10 @@ private function getContainerBuilder(): ContainerBuilder
7979
}
8080

8181
$kernel = $this->getApplication()->getKernel();
82-
$kernelContainer = $kernel->getContainer();
82+
$container = $kernel->getContainer();
83+
$file = $container->isDebug() ? $container->getParameter('debug.container.dump') : false;
8384

84-
if (!$kernel->isDebug() || !$kernelContainer->getParameter('debug.container.dump') || !(new ConfigCache($kernelContainer->getParameter('debug.container.dump'), true))->isFresh()) {
85+
if (!$file || !(new ConfigCache($file, true))->isFresh()) {
8586
if (!$kernel instanceof Kernel) {
8687
throw new RuntimeException(\sprintf('This command does not support the application kernel: "%s" does not extend "%s".', get_debug_type($kernel), Kernel::class));
8788
}
@@ -93,12 +94,17 @@ private function getContainerBuilder(): ContainerBuilder
9394
}, $kernel, $kernel::class);
9495
$container = $buildContainer();
9596
} else {
96-
if (!$kernelContainer instanceof Container) {
97-
throw new RuntimeException(\sprintf('This command does not support the application container: "%s" does not extend "%s".', get_debug_type($kernelContainer), Container::class));
97+
if (str_ends_with($file, '.xml') && is_file(substr_replace($file, '.ser', -4))) {
98+
$container = unserialize(file_get_contents(substr_replace($file, '.ser', -4)));
99+
} else {
100+
(new XmlFileLoader($container = new ContainerBuilder(new EnvPlaceholderParameterBag()), new FileLocator()))->load($file);
98101
}
99102

100-
(new XmlFileLoader($container = new ContainerBuilder($parameterBag = new EnvPlaceholderParameterBag()), new FileLocator()))->load($kernelContainer->getParameter('debug.container.dump'));
103+
if (!$container instanceof ContainerBuilder) {
104+
throw new RuntimeException(\sprintf('This command does not support the application container: "%s" is not a "%s".', get_debug_type($container), ContainerBuilder::class));
105+
}
101106

107+
$parameterBag = $container->getParameterBag();
102108
$refl = new \ReflectionProperty($parameterBag, 'resolved');
103109
$refl->setValue($parameterBag, true);
104110

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ContainerBuilderDebugDumpPass.php

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313

1414
use Symfony\Component\Config\ConfigCache;
1515
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
16+
use Symfony\Component\DependencyInjection\Compiler\ResolveEnvPlaceholdersPass;
1617
use Symfony\Component\DependencyInjection\ContainerBuilder;
1718
use Symfony\Component\DependencyInjection\Dumper\XmlDumper;
19+
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
20+
use Symfony\Component\Filesystem\Filesystem;
1821

1922
/**
2023
* Dumps the ContainerBuilder to a cache file so that it can be used by
@@ -31,9 +34,38 @@ public function process(ContainerBuilder $container): void
3134
return;
3235
}
3336

34-
$cache = new ConfigCache($container->getParameter('debug.container.dump'), true);
35-
if (!$cache->isFresh()) {
36-
$cache->write((new XmlDumper($container))->dump(), $container->getResources());
37+
$file = $container->getParameter('debug.container.dump');
38+
$cache = new ConfigCache($file, true);
39+
if ($cache->isFresh()) {
40+
return;
41+
}
42+
$cache->write((new XmlDumper($container))->dump(), $container->getResources());
43+
44+
if (!str_ends_with($file, '.xml')) {
45+
return;
46+
}
47+
48+
if (!($bag = $container->getParameterBag()) instanceof EnvPlaceholderParameterBag) {
49+
return;
50+
}
51+
$file = substr_replace($file, '.ser', -4);
52+
53+
try {
54+
$dump = new ContainerBuilder(clone $container->getParameterBag());
55+
$dump->setDefinitions(unserialize(serialize($container->getDefinitions())));
56+
$dump->setAliases($container->getAliases());
57+
(new ResolveEnvPlaceholdersPass(null))->process($dump);
58+
$dump->__construct(new EnvPlaceholderParameterBag($container->resolveEnvPlaceholders($bag->all())));
59+
60+
$fs = new Filesystem();
61+
$fs->dumpFile($file, serialize($dump));
62+
$fs->chmod($file, 0666, umask());
63+
} catch (\Throwable $e) {
64+
$container->getCompiler()->log($this, $e->getMessage());
65+
// ignore serialization and file-system errors
66+
if (file_exists($file)) {
67+
@unlink($file);
68+
}
3769
}
3870
}
3971
}

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

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,25 +20,35 @@ class ResolveEnvPlaceholdersPass extends AbstractRecursivePass
2020
{
2121
protected bool $skipScalars = false;
2222

23+
/**
24+
* @param string|true|null $format A sprintf() format returning the replacement for each env var name or
25+
* null to resolve back to the original "%env(VAR)%" format or
26+
* true to resolve to the actual values of the referenced env vars
27+
*/
28+
public function __construct(
29+
private string|bool|null $format = true,
30+
) {
31+
}
32+
2333
protected function processValue(mixed $value, bool $isRoot = false): mixed
2434
{
2535
if (\is_string($value)) {
26-
return $this->container->resolveEnvPlaceholders($value, true);
36+
return $this->container->resolveEnvPlaceholders($value, $this->format);
2737
}
2838
if ($value instanceof Definition) {
2939
$changes = $value->getChanges();
3040
if (isset($changes['class'])) {
31-
$value->setClass($this->container->resolveEnvPlaceholders($value->getClass(), true));
41+
$value->setClass($this->container->resolveEnvPlaceholders($value->getClass(), $this->format));
3242
}
3343
if (isset($changes['file'])) {
34-
$value->setFile($this->container->resolveEnvPlaceholders($value->getFile(), true));
44+
$value->setFile($this->container->resolveEnvPlaceholders($value->getFile(), $this->format));
3545
}
3646
}
3747

3848
$value = parent::processValue($value, $isRoot);
3949

4050
if ($value && \is_array($value) && !$isRoot) {
41-
$value = array_combine($this->container->resolveEnvPlaceholders(array_keys($value), true), $value);
51+
$value = array_combine($this->container->resolveEnvPlaceholders(array_keys($value), $this->format), $value);
4252
}
4353

4454
return $value;

0 commit comments

Comments
 (0)