Skip to content

Commit

Permalink
bug #38357 [DI] fix dumping non-shared lazy services (nicolas-grekas)
Browse files Browse the repository at this point in the history
This PR was merged into the 5.1 branch.

Discussion
----------

[DI] fix dumping non-shared lazy services

| Q             | A
| ------------- | ---
| Branch?       | 5.1
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #38327
| License       | MIT
| Doc PR        | -

It took me a while to get this correct, but here we are.

Commits
-------

e33a0b0 [DI] fix dumping non-shared lazy services
  • Loading branch information
fabpot committed Oct 1, 2020
2 parents 65ee6c9 + e33a0b0 commit e36a36a
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 16 deletions.
39 changes: 33 additions & 6 deletions src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
Original file line number Diff line number Diff line change
Expand Up @@ -863,18 +863,45 @@ protected function {$methodName}($lazyInitialization)
}
}

if ($this->getProxyDumper()->isProxyCandidate($definition)) {
$factoryCode = $definition->isShared() ? ($asFile ? "\$this->load('%s', false)" : '$this->%s(false)') : '$this->factories[%2$s](false)';
$factoryCode = $this->getProxyDumper()->getProxyFactoryCode($definition, $id, sprintf($factoryCode, $methodName, $this->doExport($id)));
if (!$definition->isShared()) {
$factory = sprintf('$this->factories%s[%s]', $definition->isPublic() ? '' : "['service_container']", $this->doExport($id));
}

if ($isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition)) {
if (!$definition->isShared()) {
$code .= sprintf(' %s = %1$s ?? ', $factory);

if ($asFile) {
$code .= "function () {\n";
$code .= " return self::do(\$container);\n";
$code .= " };\n\n";
} else {
$code .= sprintf("\\Closure::fromCallable([\$this, '%s']);\n\n", $methodName);
}
}

$factoryCode = $asFile ? 'self::do($container, false)' : sprintf('$this->%s(false)', $methodName);
$factoryCode = $this->getProxyDumper()->getProxyFactoryCode($definition, $id, $factoryCode);
$code .= $asFile ? preg_replace('/function \(([^)]*+)\) {/', 'function (\1) use ($container) {', $factoryCode) : $factoryCode;
}

$code .= $this->addServiceInclude($id, $definition);
$c = $this->addServiceInclude($id, $definition);

if ('' !== $c && $isProxyCandidate && !$definition->isShared()) {
$c = implode("\n", array_map(function ($line) { return $line ? ' '.$line : $line; }, explode("\n", $c)));
$code .= " static \$include = true;\n\n";
$code .= " if (\$include) {\n";
$code .= $c;
$code .= " \$include = false;\n";
$code .= " }\n\n";
} else {
$code .= $c;
}

$c = $this->addInlineService($id, $definition);

if (!$definition->isShared()) {
if (!$isProxyCandidate && !$definition->isShared()) {
$c = implode("\n", array_map(function ($line) { return $line ? ' '.$line : $line; }, explode("\n", $c)));
$factory = sprintf('$this->factories%s[%s]', $definition->isPublic() ? '' : "['service_container']", $this->doExport($id));
$lazyloadInitialization = $definition->isLazy() ? '$lazyLoad = true' : '';

$c = sprintf(" %s = function (%s) {\n%s };\n\n return %1\$s();\n", $factory, $lazyloadInitialization, $c);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ public function testNonSharedLazyDumpAsFiles()
->setLazy(true);
$container->compile();
$dumper = new PhpDumper($container);
$dumper->setProxyDumper(new \DummyProxyDumper());
$dump = print_r($dumper->dump(['as_files' => true, 'file' => __DIR__, 'inline_factories_parameter' => false, 'inline_class_loader_parameter' => false]), true);

if ('\\' === \DIRECTORY_SEPARATOR) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,11 @@ protected function getBarService()
*/
protected function getFooService($lazyLoad = true)
{
// lazy factory for stdClass
$this->factories['service_container']['foo'] = $this->factories['service_container']['foo'] ?? \Closure::fromCallable([$this, 'getFooService']);

$this->factories['service_container']['foo'] = function ($lazyLoad = true) {
return new \stdClass();
};
// lazy factory for stdClass

return $this->factories['service_container']['foo']();
return new \stdClass();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,34 @@ class getNonSharedFooService extends ProjectServiceContainer
*/
public static function do($container, $lazyLoad = true)
{
include_once $container->targetDir.''.'/Fixtures/includes/foo_lazy.php';

$container->factories['non_shared_foo'] = function ($lazyLoad = true) use ($container) {
return new \Bar\FooLazyClass();
$container->factories['non_shared_foo'] = $container->factories['non_shared_foo'] ?? function () use ($container) {
return self::do($container);
};

return $container->factories['non_shared_foo']();
// lazy factory for Bar\FooLazyClass

static $include = true;

if ($include) {
include_once $container->targetDir.''.'/Fixtures/includes/foo_lazy.php';

$include = false;
}

return new \Bar\FooLazyClass();
}
}

[Container%s/proxy.php] => <?php

namespace Container%s;

// proxy code for Bar\FooLazyClass

if (!\class_exists('proxy', false)) {
\class_alias(__NAMESPACE__.'\\proxy', 'proxy', false);
}

[Container%s/ProjectServiceContainer.php] => <?php

namespace Container%s;
Expand Down Expand Up @@ -105,6 +123,13 @@ class ProjectServiceContainer extends Container

return class_exists($class, false) ? $class::do($this, $lazyLoad) : $service;
}

protected function createProxy($class, \Closure $factory)
{
class_exists($class, false) || require __DIR__.'/'.$class.'.php';

return $factory();
}
}

[ProjectServiceContainer.preload.php] => <?php
Expand All @@ -120,6 +145,7 @@ if (in_array(PHP_SAPI, ['cli', 'phpdbg'], true)) {

require dirname(__DIR__, %d).'%svendor/autoload.php';
require __DIR__.'/Container%s/ProjectServiceContainer.php';
require __DIR__.'/Container%s/proxy.php';
require __DIR__.'/Container%s/getNonSharedFooService.php';

$classes = [];
Expand Down

0 comments on commit e36a36a

Please sign in to comment.