From e95b43848795d0c8ff6c892ed5c00c48b1194c40 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 31 Jul 2017 15:17:36 +0200 Subject: [PATCH 1/2] [Bridge\ProxyManager] Dont call __destruct() on non-instantiated services --- .../LazyLoadingValueHolderFactoryV1.php | 31 ++++++++++++++ .../LazyLoadingValueHolderFactoryV2.php | 32 +++++++++++++++ .../Instantiator/RuntimeInstantiator.php | 6 ++- .../LazyLoadingValueHolderGenerator.php | 41 +++++++++++++++++++ .../LazyProxy/PhpDumper/ProxyDumper.php | 1 - .../Tests/LazyProxy/ContainerBuilderTest.php | 6 +++ .../Tests/LazyProxy/Fixtures/includes/foo.php | 7 ++++ 7 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/LazyLoadingValueHolderFactoryV1.php create mode 100644 src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/LazyLoadingValueHolderFactoryV2.php create mode 100644 src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/LazyLoadingValueHolderGenerator.php diff --git a/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/LazyLoadingValueHolderFactoryV1.php b/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/LazyLoadingValueHolderFactoryV1.php new file mode 100644 index 0000000000000..3298b84d46278 --- /dev/null +++ b/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/LazyLoadingValueHolderFactoryV1.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\ProxyManager\LazyProxy\Instantiator; + +use ProxyManager\Factory\LazyLoadingValueHolderFactory as BaseFactory; +use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\LazyLoadingValueHolderGenerator; + +/** + * @internal + */ +class LazyLoadingValueHolderFactoryV1 extends BaseFactory +{ + private $generatorV1; + + /** + * {@inheritdoc} + */ + protected function getGenerator() + { + return $this->generatorV1 ?: $this->generatorV1 = new LazyLoadingValueHolderGenerator(); + } +} diff --git a/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/LazyLoadingValueHolderFactoryV2.php b/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/LazyLoadingValueHolderFactoryV2.php new file mode 100644 index 0000000000000..f41fc20b5d523 --- /dev/null +++ b/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/LazyLoadingValueHolderFactoryV2.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\ProxyManager\LazyProxy\Instantiator; + +use ProxyManager\ProxyGenerator\ProxyGeneratorInterface; +use ProxyManager\Factory\LazyLoadingValueHolderFactory as BaseFactory; +use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\LazyLoadingValueHolderGenerator; + +/** + * @internal + */ +class LazyLoadingValueHolderFactoryV2 extends BaseFactory +{ + private $generator; + + /** + * {@inheritdoc} + */ + protected function getGenerator(): ProxyGeneratorInterface + { + return $this->generator ?: $this->generator = new LazyLoadingValueHolderGenerator(); + } +} diff --git a/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/RuntimeInstantiator.php b/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/RuntimeInstantiator.php index 0101026794c7c..33fc49e1012d9 100644 --- a/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/RuntimeInstantiator.php +++ b/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/RuntimeInstantiator.php @@ -36,7 +36,11 @@ public function __construct() $config = new Configuration(); $config->setGeneratorStrategy(new EvaluatingGeneratorStrategy()); - $this->factory = new LazyLoadingValueHolderFactory($config); + if (method_exists('ProxyManager\Version', 'getVersion')) { + $this->factory = new LazyLoadingValueHolderFactoryV2($config); + } else { + $this->factory = new LazyLoadingValueHolderFactoryV1($config); + } } /** diff --git a/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/LazyLoadingValueHolderGenerator.php b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/LazyLoadingValueHolderGenerator.php new file mode 100644 index 0000000000000..e599ce325f3be --- /dev/null +++ b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/LazyLoadingValueHolderGenerator.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper; + +use ProxyManager\ProxyGenerator\LazyLoadingValueHolderGenerator as BaseGenerator; +use Zend\Code\Generator\ClassGenerator; + +/** + * @internal + */ +class LazyLoadingValueHolderGenerator extends BaseGenerator +{ + /** + * {@inheritdoc} + */ + public function generate(\ReflectionClass $originalClass, ClassGenerator $classGenerator) + { + parent::generate($originalClass, $classGenerator); + + if ($classGenerator->hasMethod('__destruct')) { + $destructor = $classGenerator->getMethod('__destruct'); + $body = $destructor->getBody(); + $newBody = preg_replace('/^(\$this->initializer[\d\w]++) && .*;\n\nreturn (\$this->valueHolder)/', '$1 || $2', $body); + + if ($body === $newBody) { + throw new \UnexpectedValueException(sprintf('Unexpected lazy-proxy format generated for method %s::__destruct()', $originalClass->name)); + } + + $destructor->setBody($newBody); + } + } +} diff --git a/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php index db4768839bf8c..691d942e1c45f 100644 --- a/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php +++ b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php @@ -13,7 +13,6 @@ use ProxyManager\Generator\ClassGenerator; use ProxyManager\GeneratorStrategy\BaseGeneratorStrategy; -use ProxyManager\ProxyGenerator\LazyLoadingValueHolderGenerator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface; diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/ContainerBuilderTest.php b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/ContainerBuilderTest.php index b634a69488a34..858e9d76b64c9 100644 --- a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/ContainerBuilderTest.php +++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/ContainerBuilderTest.php @@ -39,6 +39,9 @@ public function testCreateProxyServiceWithRuntimeInstantiator() /* @var $foo1 \ProxyManager\Proxy\LazyLoadingInterface|\ProxyManager\Proxy\ValueHolderInterface */ $foo1 = $builder->get('foo1'); + $foo1->__destruct(); + $this->assertSame(0, $foo1::$destructorCount); + $this->assertSame($foo1, $builder->get('foo1'), 'The same proxy is retrieved on multiple subsequent calls'); $this->assertInstanceOf('\ProxyManagerBridgeFooClass', $foo1); $this->assertInstanceOf('\ProxyManager\Proxy\LazyLoadingInterface', $foo1); @@ -50,5 +53,8 @@ public function testCreateProxyServiceWithRuntimeInstantiator() $this->assertTrue($foo1->isProxyInitialized()); $this->assertInstanceOf('\ProxyManagerBridgeFooClass', $foo1->getWrappedValueHolderValue()); $this->assertNotInstanceOf('\ProxyManager\Proxy\LazyLoadingInterface', $foo1->getWrappedValueHolderValue()); + + $foo1->__destruct(); + $this->assertSame(1, $foo1::$destructorCount); } } diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/includes/foo.php b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/includes/foo.php index 16c898a370845..8ffc5be9af40a 100644 --- a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/includes/foo.php +++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/includes/foo.php @@ -2,6 +2,8 @@ class ProxyManagerBridgeFooClass { + public static $destructorCount = 0; + public $foo; public $moo; @@ -38,4 +40,9 @@ public function setBar($value = null) { $this->bar = $value; } + + public function __destruct() + { + ++self::$destructorCount; + } } From 359b6ef367471cd7d19676e21ba4e07907c31545 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 24 Jul 2017 21:11:47 +0200 Subject: [PATCH 2/2] [DI] Generate one file per service factory --- .../Bridge/Doctrine/ManagerRegistry.php | 8 +- .../LazyProxy/PhpDumper/ProxyDumper.php | 7 +- .../Command/CacheClearCommand.php | 2 +- .../DependencyInjection/Container.php | 68 +- .../DependencyInjection/Dumper/PhpDumper.php | 233 ++++--- .../Loader/XmlFileLoader.php | 2 +- .../Loader/YamlFileLoader.php | 2 +- .../Tests/Dumper/PhpDumperTest.php | 8 + .../Tests/Fixtures/containers/container9.php | 1 + .../Tests/Fixtures/graphviz/services9.dot | 1 + .../Tests/Fixtures/php/services33.php | 4 +- .../Tests/Fixtures/php/services9_as_files.txt | 608 ++++++++++++++++++ .../Tests/Fixtures/php/services9_compiled.php | 4 +- .../Fixtures/php/services_subscriber.php | 8 +- .../Tests/Fixtures/xml/services9.xml | 4 +- .../Tests/Fixtures/yaml/services9.yml | 1 + .../Tests/Loader/YamlFileLoaderTest.php | 4 +- src/Symfony/Component/HttpKernel/Kernel.php | 24 +- 18 files changed, 833 insertions(+), 156 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt diff --git a/src/Symfony/Bridge/Doctrine/ManagerRegistry.php b/src/Symfony/Bridge/Doctrine/ManagerRegistry.php index 38bb2f69ddda2..fcefb4d6f3791 100644 --- a/src/Symfony/Bridge/Doctrine/ManagerRegistry.php +++ b/src/Symfony/Bridge/Doctrine/ManagerRegistry.php @@ -55,8 +55,12 @@ function (&$wrappedInstance, LazyLoadingInterface $manager) use ($name) { if (isset($this->aliases[$name])) { $name = $this->aliases[$name]; } - $method = $this->methodMap[$name] ?? 'get'.strtr($name, $this->underscoreMap).'Service'; // BC with DI v3.4 - $wrappedInstance = $this->{$method}(false); + if (isset($this->fileMap[$name])) { + $wrappedInstance = $this->requireInScope($this->fileMap[$name], false); + } else { // BC with DI v3.4 + $method = $this->methodMap[$name] ?? 'get'.strtr($name, $this->underscoreMap).'Service'; + $wrappedInstance = $this->{$method}(false); + } $manager->setProxyInitializer(null); diff --git a/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php index 691d942e1c45f..225f4f0837732 100644 --- a/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php +++ b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php @@ -69,7 +69,12 @@ public function getProxyFactoryCode(Definition $definition, $id, $factoryCode = $instantiation = 'return'; if ($definition->isShared()) { - $instantiation .= sprintf(' $this->%s[\'%s\'] =', $definition->isPublic() || !method_exists(ContainerBuilder::class, 'addClassResource') ? 'services' : 'privates', $id); + if (!method_exists(ContainerBuilder::class, 'addClassResource')) { + $instantiation .= sprintf(' $this->%s[\'%s\'] =', $definition->isPublic() ? 'services' : 'privates', $id); + } else { + // BC with DI v3.4 + $instantiation .= sprintf(' $this->services[\'%s\'] =', $id); + } } if (null === $factoryCode) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php index 0a70d9a859119..c898a9a6d80ed 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php @@ -17,7 +17,7 @@ use Symfony\Component\Console\Style\SymfonyStyle; /** - * Clear and Warmup the cache. + * Clear the cache. * * @author Francis Besset * @author Fabien Potencier diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php index def4c4ce15d15..80d78325ff65a 100644 --- a/src/Symfony/Component/DependencyInjection/Container.php +++ b/src/Symfony/Component/DependencyInjection/Container.php @@ -46,6 +46,7 @@ class Container implements ResettableContainerInterface protected $parameterBag; protected $services = array(); + protected $fileMap = array(); protected $methodMap = array(); protected $aliases = array(); protected $loading = array(); @@ -150,7 +151,7 @@ public function set($id, $service) throw new InvalidArgumentException('You cannot set service "service_container".'); } - if (isset($this->methodMap[$id])) { + if (isset($this->fileMap[$id]) || isset($this->methodMap[$id])) { throw new InvalidArgumentException(sprintf('You cannot set the pre-defined service "%s".', $id)); } @@ -186,19 +187,12 @@ public function has($id) return true; } - if (isset($this->methodMap[$id])) { - return true; - } - - return false; + return isset($this->fileMap[$id]) || isset($this->methodMap[$id]); } /** * Gets a service. * - * If a service is defined both through a set() method and - * with a get{$id}Service() method, the former has always precedence. - * * @param string $id The service identifier * @param int $invalidBehavior The behavior when the service does not exist * @@ -228,32 +222,14 @@ public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE throw new ServiceCircularReferenceException($id, array_keys($this->loading)); } - if (isset($this->methodMap[$id])) { - $method = $this->methodMap[$id]; - } else { - if (self::EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior) { - if (!$id) { - throw new ServiceNotFoundException($id); - } - - $alternatives = array(); - foreach ($this->getServiceIds() as $knownId) { - $lev = levenshtein($id, $knownId); - if ($lev <= strlen($id) / 3 || false !== strpos($knownId, $id)) { - $alternatives[] = $knownId; - } - } - - throw new ServiceNotFoundException($id, null, null, $alternatives); - } - - return; - } - $this->loading[$id] = true; try { - $service = $this->$method(); + if (isset($this->fileMap[$id])) { + return $this->requireInScope($this->fileMap[$id]); + } elseif (isset($this->methodMap[$id])) { + return $this->{$this->methodMap[$id]}(); + } } catch (\Exception $e) { unset($this->services[$id]); @@ -262,7 +238,21 @@ public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE unset($this->loading[$id]); } - return $service; + if (self::EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior) { + if (!$id) { + throw new ServiceNotFoundException($id); + } + + $alternatives = array(); + foreach ($this->getServiceIds() as $knownId) { + $lev = levenshtein($id, $knownId); + if ($lev <= strlen($id) / 3 || false !== strpos($knownId, $id)) { + $alternatives[] = $knownId; + } + } + + throw new ServiceNotFoundException($id, null, null, $alternatives); + } } /** @@ -300,7 +290,7 @@ public function reset() */ public function getServiceIds() { - return array_unique(array_merge(array('service_container'), array_keys($this->methodMap), array_keys($this->services))); + return array_unique(array_merge(array('service_container'), array_keys($this->fileMap), array_keys($this->methodMap), array_keys($this->services))); } /** @@ -327,6 +317,16 @@ public static function underscore($id) return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), str_replace('_', '.', $id))); } + /** + * Creates a service by requiring its factory file. + * + * @return object The service created by the file + */ + protected function requireInScope($file) + { + return require $file; + } + /** * Fetches a variable from the environment. * diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index e65afed79b933..01c7617a41684 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -66,6 +66,8 @@ class PhpDumper extends Dumper private $docStar; private $serviceIdToMethodNameMap; private $usedMethodNames; + private $class; + private $asFiles; /** * @var \Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface @@ -104,10 +106,11 @@ public function setProxyDumper(ProxyDumper $proxyDumper) * * class: The class name * * base_class: The base class name * * namespace: The class namespace + * * as_files: To split the container in several files * * @param array $options An array of options * - * @return string A PHP class representing of the service container + * @return string|array A PHP class representing the service container or an array of PHP files if the "as_files" option is set * * @throws EnvParameterException When an env var exists but has not been dumped */ @@ -118,9 +121,12 @@ public function dump(array $options = array()) 'class' => 'ProjectServiceContainer', 'base_class' => 'Container', 'namespace' => '', + 'as_files' => false, 'debug' => true, ), $options); + $this->class = $options['class']; + $this->asFiles = $options['as_files']; $this->initializeMethodNamesMap($options['base_class']); $this->docStar = $options['debug'] ? '*' : ''; @@ -151,16 +157,21 @@ public function dump(array $options = array()) } $code = - $this->startClass($options['class'], $options['base_class'], $options['namespace']). - $this->addConstructor(). - $this->addReset(). - $this->addCompile(). - $this->addIsCompiled(). - $this->addServices(). + $this->startFile($options['namespace']). + $this->startClass($options['class'], $options['base_class']). + $this->addServiceMethods(). $this->addDefaultParametersMethod(). $this->endClass(). $this->addProxyClasses() ; + if ($this->asFiles) { + $fileStart = $this->startFile($options['namespace']). + "\n// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.\n\n"; + $code = array($options['class'].'.php' => $code); + foreach ($this->generateServiceFiles() as $file => $c) { + $code[$file] = $fileStart.$c; + } + } $this->targetDirRegex = null; $unusedEnvs = array(); @@ -360,23 +371,6 @@ private function addServiceInlinedDefinitions($id, array $inlinedDefinitions) return $code; } - /** - * Adds the service return statement. - * - * @param string $id - * @param bool $isSimpleInstance - * - * @return string - */ - private function addServiceReturn($id, $isSimpleInstance) - { - if ($isSimpleInstance) { - return " }\n"; - } - - return "\n return \$instance;\n }\n"; - } - /** * Generates the service instance. * @@ -609,14 +603,12 @@ private function addServiceConfigurator(Definition $definition, $variableName = * * @param string $id * @param Definition $definition + * @param string &$file * * @return string */ - private function addService($id, Definition $definition) + private function addService($id, Definition $definition, &$file = null) { - if ($definition->isSynthetic()) { - return ''; - } $this->definitionVariables = new \SplObjectStorage(); $this->referenceVariables = array(); $this->variableCount = 0; @@ -660,23 +652,28 @@ private function addService($id, Definition $definition) $lazyInitialization = ''; } - // with proxies, for 5.3.3 compatibility, the getter must be public to be accessible to the initializer - $isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition); - $visibility = $isProxyCandidate ? 'public' : ($definition->isPublic() ? 'protected' : 'private'); + $asFile = $this->asFiles && $definition->isShared(); $methodName = $this->generateMethodName($id); - $code = <<class, $methodName); + if ($asFile) { + $code = " // Returns the $public '$id'$shared$autowired service.\n\n"; + } else { + $code = <<docStar} * Gets the $public '$id'$shared$autowired service. * * $return */ - {$visibility} function {$methodName}($lazyInitialization) + protected function {$methodName}($lazyInitialization) { EOF; - - $code .= $isProxyCandidate ? $this->getProxyDumper()->getProxyFactoryCode($definition, $id, "\$this->$methodName(false)") : ''; + } + if ($this->getProxyDumper()->isProxyCandidate($definition)) { + $factoryCode = $asFile ? "\$this->requireInScope(__DIR__.''.'/%s.php', false)" : '$this->%s(false)'; + $code .= $this->getProxyDumper()->getProxyFactoryCode($definition, $id, sprintf($factoryCode, $methodName)); + } if ($definition->isDeprecated()) { $code .= sprintf(" @trigger_error(%s, E_USER_DEPRECATED);\n\n", $this->export($definition->getDeprecationMessage($id))); @@ -694,9 +691,18 @@ private function addService($id, Definition $definition) $this->addServiceProperties($definition). $this->addServiceMethodCalls($definition). $this->addServiceConfigurator($definition). - $this->addServiceReturn($id, $isSimpleInstance) + (!$isSimpleInstance ? "\n return \$instance;\n" : '') ; + if ($asFile) { + $code = implode("\n", array_map(function ($line) { return $line ? substr($line, 8) : $line; }, explode("\n", $code))); + } else { + $code .= " }\n"; + } + if ($this->asFiles) { + $code = str_replace("\$this->requireInScope(__DIR__.''.'", "\$this->requireInScope(__DIR__.'".($asFile ? '' : '/'.$this->class), $code); + } + $this->definitionVariables = null; $this->referenceVariables = null; @@ -708,12 +714,28 @@ private function addService($id, Definition $definition) * * @return string */ - private function addServices() + private function addServiceMethods() { $publicServices = $privateServices = ''; + if ($this->asFiles) { + $publicServices = <<docStar} + * {@inheritdoc} + */ + protected function requireInScope(\$file, \$lazyLoad = true) + { + return require \$file; + } + +EOF; + } $definitions = $this->container->getDefinitions(); ksort($definitions); foreach ($definitions as $id => $definition) { + if ($definition->isSynthetic() || ($this->asFiles && $definition->isShared())) { + continue; + } if ($definition->isPublic()) { $publicServices .= $this->addService($id, $definition); } elseif (!$this->isTrivialInstance($definition)) { @@ -724,6 +746,18 @@ private function addServices() return $publicServices.$privateServices; } + private function generateServiceFiles() + { + $definitions = $this->container->getDefinitions(); + ksort($definitions); + foreach ($definitions as $id => $definition) { + if (!$definition->isSynthetic() && $definition->isShared() && !$this->isTrivialInstance($definition)) { + $code = $this->addService($id, $definition, $file); + yield $file => $code; + } + } + } + private function addNewInstance(Definition $definition, $return, $instantiation, $id) { $class = $this->dumpValue($definition->getClass()); @@ -773,15 +807,13 @@ private function addNewInstance(Definition $definition, $return, $instantiation, } /** - * Adds the class headers. + * Adds the PHP file headers. * - * @param string $class Class name - * @param string $baseClass The name of the base class * @param string $namespace The class namespace * * @return string */ - private function startClass($class, $baseClass, $namespace) + private function startFile($namespace) { $namespaceLine = $namespace ? "\nnamespace $namespace;\n" : ''; @@ -796,6 +828,21 @@ private function startClass($class, $baseClass, $namespace) use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag; +EOF; + } + + /** + * Adds the class headers. + * + * @param string $class Class name + * @param string $baseClass The name of the base class + * + * @return string + */ + private function startClass($class, $baseClass) + { + $code = <<docStar} * $class. * @@ -811,18 +858,10 @@ class $class extends $baseClass private \$privates = array(); EOF; - } - /** - * Adds the constructor for a compiled container. - * - * @return string - */ - private function addConstructor() - { $targetDirs = $this->exportTargetDirs(); - $code = <<docStar} * Constructor. @@ -837,25 +876,12 @@ public function __construct() $code .= "\n \$this->services = \$this->privates = array();\n"; $code .= $this->addMethodMap(); + $code .= $this->asFiles ? $this->addFileMap() : ''; $code .= $this->addAliases(); - $code .= <<<'EOF' - } - -EOF; - - return $code; + $code .= <<docStar} * {@inheritdoc} */ @@ -865,18 +891,6 @@ public function reset() parent::reset(); } -EOF; - } - - /** - * Adds the compile method for a compiled container. - * - * @return string - */ - private function addCompile() - { - return <<docStar} * {@inheritdoc} */ @@ -885,18 +899,6 @@ public function compile() throw new LogicException('You cannot compile a dumped container that was already compiled.'); } -EOF; - } - - /** - * Adds the isCompiled method for a compiled container. - * - * @return string - */ - private function addIsCompiled() - { - return <<docStar} * {@inheritdoc} */ @@ -906,6 +908,8 @@ public function isCompiled() } EOF; + + return $code; } /** @@ -915,20 +919,35 @@ public function isCompiled() */ private function addMethodMap() { + $code = ''; $definitions = $this->container->getDefinitions(); - if (!$definitions || !$definitions = array_filter($definitions, function ($def) { return !$def->isSynthetic(); })) { - return ''; + ksort($definitions); + foreach ($definitions as $id => $definition) { + if (!$definition->isSynthetic() && $definition->isPublic() && (!$this->asFiles || !$definition->isShared())) { + $code .= ' '.$this->export($id).' => '.$this->export($this->generateMethodName($id)).",\n"; + } } - $code = " \$this->methodMap = array(\n"; + return $code ? " \$this->methodMap = array(\n{$code} );\n" : ''; + } + + /** + * Adds the fileMap property definition. + * + * @return string + */ + private function addFileMap() + { + $code = ''; + $definitions = $this->container->getDefinitions(); ksort($definitions); foreach ($definitions as $id => $definition) { - if ($definition->isPublic()) { - $code .= ' '.$this->export($id).' => '.$this->export($this->generateMethodName($id)).",\n"; + if (!$definition->isSynthetic() && $definition->isPublic() && $definition->isShared()) { + $code .= sprintf(" %s => __DIR__.'/%s/%s.php',\n", $this->export($id), $this->class, $this->generateMethodName($id)); } } - return $code." );\n"; + return $code ? " \$this->fileMap = array(\n{$code} );\n" : ''; } /** @@ -1547,13 +1566,13 @@ private function getServiceCall($id, Reference $reference = null) if ($this->container->hasDefinition($id)) { $definition = $this->container->getDefinition($id); - if ($definition->isPublic() || !$this->isTrivialInstance($definition)) { - $code = sprintf('$this->%s()', $this->generateMethodName($id)); - } else { + if ($this->isTrivialInstance($definition)) { $code = substr($this->addNewInstance($definition, '', '', $id), 8, -2); - if ($definition->isShared()) { - $code = sprintf('($this->privates[\'%s\'] = %s)', $id, $code); - } + $code = sprintf('($this->privates[\'%s\'] = %s)', $id, $code); + } elseif ($this->asFiles && $definition->isShared()) { + $code = sprintf("\$this->requireInScope(__DIR__.''.'/%s.php')", $this->generateMethodName($id)); + } else { + $code = sprintf('$this->%s()', $this->generateMethodName($id)); } if ($definition->isShared()) { $code = sprintf('($this->%s[\'%s\'] ?? %s)', $definition->isPublic() ? 'services' : 'privates', $id, $code); @@ -1595,6 +1614,11 @@ private function initializeMethodNamesMap($class) */ private function generateMethodName($id) { + $i = strrpos($id, '\\'); + if (false !== $i && isset($id[1 + $i])) { + $id = substr($id, 1 + $i); + } + if (isset($this->serviceIdToMethodNameMap[$id])) { return $this->serviceIdToMethodNameMap[$id]; } @@ -1682,9 +1706,11 @@ private function getExpressionLanguage() private function exportTargetDirs() { + $targetDir0 = $this->asFiles ? '$this->targetDirs[] =' : ''; + return null === $this->targetDirRegex ? '' : <<targetDirMaxMatches}; ++\$i) { \$this->targetDirs[\$i] = \$dir = dirname(\$dir); } @@ -1698,8 +1724,9 @@ private function export($value) $suffix = $matches[0][1] + strlen($matches[0][0]); $suffix = isset($value[$suffix]) ? '.'.$this->doExport(substr($value, $suffix)) : ''; $dirname = '__DIR__'; + $offset = 1 + $this->targetDirMaxMatches - count($matches); - if (0 < $offset = 1 + $this->targetDirMaxMatches - count($matches)) { + if ($this->asFiles || 0 < $offset) { $dirname = sprintf('$this->targetDirs[%d]', $offset); } diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 4bec02a8871c5..c9b0228b14e11 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -391,7 +391,7 @@ private function processAnonymousServices(\DOMDocument $xml, $file, $defaults) foreach ($nodes as $node) { if ($services = $this->getChildren($node, 'service')) { // give it a unique name - $id = sprintf('%d_%s', ++$count, hash('sha256', $file)); + $id = sprintf('%d_%s', ++$count, substr(hash('sha256', $file), 0, 7)); $node->setAttribute('id', $id); $node->setAttribute('service', $id); diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 1c0359509e674..8ae14c7aeae4e 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -673,7 +673,7 @@ private function resolveServices($value, $file, $isParameter = false) $instanceof = $this->instanceof; $this->instanceof = array(); - $id = sprintf('%d_%s', ++$this->anonymousServicesCount, hash('sha256', $file)); + $id = sprintf('%d_%s', ++$this->anonymousServicesCount, substr(hash('sha256', $file), 0, 7)); $this->parseDefinition($id, $argument, $file, array()); if (!$this->container->hasDefinition($id)) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index 8a70f8d381a56..b5599103e448b 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -160,6 +160,14 @@ public function testAddService() } } + public function testDumpAsFiles() + { + $container = include self::$fixturesPath.'/containers/container9.php'; + $container->compile(); + $dumper = new PhpDumper($container); + $this->assertStringEqualsFile(self::$fixturesPath.'/php/services9_as_files.txt', str_replace(str_replace('\\', '\\\\', self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR), '%path%', print_r($dumper->dump(array('as_files' => true)), true))); + } + public function testServicesWithAnonymousFactories() { $container = include self::$fixturesPath.'/containers/container19.php'; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php index b662cf53c1211..98036586b61b4 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php @@ -34,6 +34,7 @@ ; $container ->register('foo_bar', '%foo_class%') + ->addArgument(new Reference('deprecated_service')) ->setShared(false) ; $container->getParameterBag()->clear(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/graphviz/services9.dot b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/graphviz/services9.dot index e6b4de7d85e83..9ee105da5b6cb 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/graphviz/services9.dot +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/graphviz/services9.dot @@ -41,6 +41,7 @@ digraph sc { node_foo -> node_foo_baz [label="" style="dashed"]; node_foo -> node_bar [label="setBar()" style="dashed"]; node_bar -> node_foo_baz [label="" style="filled"]; + node_foo_bar -> node_deprecated_service [label="" style="filled"]; node_method_call1 -> node_foo [label="setBar()" style="dashed"]; node_method_call1 -> node_foo2 [label="setBar()" style="dashed"]; node_method_call1 -> node_foo3 [label="setBar()" style="dashed"]; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services33.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services33.php index 5b3552d4df270..0c871ecd78501 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services33.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services33.php @@ -29,7 +29,7 @@ public function __construct() { $this->services = $this->privates = array(); $this->methodMap = array( - 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\Container33\\Foo' => 'getSymfony_Component_DependencyInjection_Tests_Fixtures_Container33_FooService', + 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\Container33\\Foo' => 'getFooService', ); $this->aliases = array(); @@ -65,7 +65,7 @@ public function isCompiled() * * @return \Symfony\Component\DependencyInjection\Tests\Fixtures\Container33\Foo */ - protected function getSymfony_Component_DependencyInjection_Tests_Fixtures_Container33_FooService() + protected function getFooService() { return $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\Container33\Foo'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\Container33\Foo(); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt new file mode 100644 index 0000000000000..1347b158f6787 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt @@ -0,0 +1,608 @@ +Array +( + [ProjectServiceContainer.php] => parameters = $this->getDefaultParameters(); + + $this->services = $this->privates = array(); + $this->methodMap = array( + 'foo_bar' => 'getFooBarService', + ); + $this->fileMap = array( + 'BAR' => __DIR__.'/ProjectServiceContainer/getBARService.php', + 'BAR2' => __DIR__.'/ProjectServiceContainer/getBAR2Service.php', + 'bar' => __DIR__.'/ProjectServiceContainer/getBar3Service.php', + 'bar2' => __DIR__.'/ProjectServiceContainer/getBar22Service.php', + 'baz' => __DIR__.'/ProjectServiceContainer/getBazService.php', + 'configured_service' => __DIR__.'/ProjectServiceContainer/getConfiguredServiceService.php', + 'configured_service_simple' => __DIR__.'/ProjectServiceContainer/getConfiguredServiceSimpleService.php', + 'decorator_service' => __DIR__.'/ProjectServiceContainer/getDecoratorServiceService.php', + 'decorator_service_with_name' => __DIR__.'/ProjectServiceContainer/getDecoratorServiceWithNameService.php', + 'deprecated_service' => __DIR__.'/ProjectServiceContainer/getDeprecatedServiceService.php', + 'factory_service' => __DIR__.'/ProjectServiceContainer/getFactoryServiceService.php', + 'factory_service_simple' => __DIR__.'/ProjectServiceContainer/getFactoryServiceSimpleService.php', + 'foo' => __DIR__.'/ProjectServiceContainer/getFooService.php', + 'foo.baz' => __DIR__.'/ProjectServiceContainer/getFoo_BazService.php', + 'foo_with_inline' => __DIR__.'/ProjectServiceContainer/getFooWithInlineService.php', + 'lazy_context' => __DIR__.'/ProjectServiceContainer/getLazyContextService.php', + 'lazy_context_ignore_invalid_ref' => __DIR__.'/ProjectServiceContainer/getLazyContextIgnoreInvalidRefService.php', + 'method_call1' => __DIR__.'/ProjectServiceContainer/getMethodCall1Service.php', + 'new_factory_service' => __DIR__.'/ProjectServiceContainer/getNewFactoryServiceService.php', + 'service_from_static_method' => __DIR__.'/ProjectServiceContainer/getServiceFromStaticMethodService.php', + ); + $this->aliases = array( + 'alias_for_alias' => 'foo', + 'alias_for_foo' => 'foo', + 'decorated' => 'decorator_service_with_name', + ); + } + + /** + * {@inheritdoc} + */ + public function reset() + { + $this->privates = array(); + parent::reset(); + } + + /** + * {@inheritdoc} + */ + public function compile() + { + throw new LogicException('You cannot compile a dumped container that was already compiled.'); + } + + /** + * {@inheritdoc} + */ + public function isCompiled() + { + return true; + } + + /** + * {@inheritdoc} + */ + protected function requireInScope($file, $lazyLoad = true) + { + return require $file; + } + + /** + * Gets the public 'foo_bar' service. + * + * @return \Bar\FooClass + */ + protected function getFooBarService() + { + return new \Bar\FooClass(($this->services['deprecated_service'] ?? $this->requireInScope(__DIR__.'/ProjectServiceContainer/getDeprecatedServiceService.php'))); + } + + /** + * {@inheritdoc} + */ + public function getParameter($name) + { + if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { + $name = strtolower($name); + + if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { + throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); + } + } + if (isset($this->loadedDynamicParameters[$name])) { + return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); + } + + return $this->parameters[$name]; + } + + /** + * {@inheritdoc} + */ + public function hasParameter($name) + { + $name = strtolower($name); + + return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); + } + + /** + * {@inheritdoc} + */ + public function setParameter($name, $value) + { + throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); + } + + /** + * {@inheritdoc} + */ + public function getParameterBag() + { + if (null === $this->parameterBag) { + $parameters = $this->parameters; + foreach ($this->loadedDynamicParameters as $name => $loaded) { + $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); + } + $this->parameterBag = new FrozenParameterBag($parameters); + } + + return $this->parameterBag; + } + + private $loadedDynamicParameters = array(); + private $dynamicParameters = array(); + + /** + * Computes a dynamic parameter. + * + * @param string The name of the dynamic parameter to load + * + * @return mixed The value of the dynamic parameter + * + * @throws InvalidArgumentException When the dynamic parameter does not exist + */ + private function getDynamicParameter($name) + { + throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); + } + + /** + * Gets the default parameters. + * + * @return array An array of the default parameters + */ + protected function getDefaultParameters() + { + return array( + 'baz_class' => 'BazClass', + 'foo_class' => 'Bar\\FooClass', + 'foo' => 'bar', + ); + } +} + + [ProjectServiceContainer/getBARService.php] => services['BAR'] = $instance = new \stdClass(); + +$instance->bar = ($this->services['bar'] ?? $this->requireInScope(__DIR__.'/getBar3Service.php')); + +return $instance; + + [ProjectServiceContainer/getBAR2Service.php] => services['BAR2'] = new \stdClass(); + + [ProjectServiceContainer/getBar3Service.php] => services['foo.baz'] ?? $this->requireInScope(__DIR__.'/getFoo_BazService.php')); + +$this->services['bar'] = $instance = new \Bar\FooClass('foo', $a, $this->getParameter('foo_bar')); + +$a->configure($instance); + +return $instance; + + [ProjectServiceContainer/getBar22Service.php] => services['bar2'] = new \stdClass(); + + [ProjectServiceContainer/getBazService.php] => services['baz'] = $instance = new \Baz(); + +$instance->setFoo(($this->services['foo_with_inline'] ?? $this->requireInScope(__DIR__.'/getFooWithInlineService.php'))); + +return $instance; + + [ProjectServiceContainer/getConfiguredServiceService.php] => setFoo(($this->services['baz'] ?? $this->requireInScope(__DIR__.'/getBazService.php'))); + +$this->services['configured_service'] = $instance = new \stdClass(); + +$a->configureStdClass($instance); + +return $instance; + + [ProjectServiceContainer/getConfiguredServiceSimpleService.php] => services['configured_service_simple'] = $instance = new \stdClass(); + +(new \ConfClass('bar'))->configureStdClass($instance); + +return $instance; + + [ProjectServiceContainer/getDecoratorServiceService.php] => services['decorator_service'] = new \stdClass(); + + [ProjectServiceContainer/getDecoratorServiceWithNameService.php] => services['decorator_service_with_name'] = new \stdClass(); + + [ProjectServiceContainer/getDeprecatedServiceService.php] => services['deprecated_service'] = new \stdClass(); + + [ProjectServiceContainer/getFactoryServiceService.php] => services['factory_service'] = ($this->services['foo.baz'] ?? $this->requireInScope(__DIR__.'/getFoo_BazService.php'))->getInstance(); + + [ProjectServiceContainer/getFactoryServiceSimpleService.php] => services['factory_service_simple'] = ($this->privates['factory_simple'] ?? $this->requireInScope(__DIR__.'/getFactorySimpleService.php'))->getInstance(); + + [ProjectServiceContainer/getFactorySimpleService.php] => privates['factory_simple'] = new \SimpleFactoryClass('foo'); + + [ProjectServiceContainer/getFooService.php] => services['foo.baz'] ?? $this->requireInScope(__DIR__.'/getFoo_BazService.php')); + +$this->services['foo'] = $instance = \Bar\FooClass::getInstance('foo', $a, array('bar' => 'foo is bar', 'foobar' => 'bar'), true, $this); + +$instance->foo = 'bar'; +$instance->moo = $a; +$instance->qux = array('bar' => 'foo is bar', 'foobar' => 'bar'); +$instance->setBar(($this->services['bar'] ?? $this->requireInScope(__DIR__.'/getBar3Service.php'))); +$instance->initialize(); +sc_configure($instance); + +return $instance; + + [ProjectServiceContainer/getFoo_BazService.php] => services['foo.baz'] = $instance = \BazClass::getInstance(); + +\BazClass::configureStatic1($instance); + +return $instance; + + [ProjectServiceContainer/getFooWithInlineService.php] => services['foo_with_inline'] = $instance = new \Foo(); + +$a->pub = 'pub'; +$a->setBaz(($this->services['baz'] ?? $this->requireInScope(__DIR__.'/getBazService.php'))); + +$instance->setBar($a); + +return $instance; + + [ProjectServiceContainer/getLazyContextService.php] => services['lazy_context'] = new \LazyContext(new RewindableGenerator(function () { + yield 'k1' => ($this->services['foo.baz'] ?? $this->requireInScope(__DIR__.'/getFoo_BazService.php')); + yield 'k2' => $this; +}, 2), new RewindableGenerator(function () { + return new \EmptyIterator(); +}, 0)); + + [ProjectServiceContainer/getLazyContextIgnoreInvalidRefService.php] => services['lazy_context_ignore_invalid_ref'] = new \LazyContext(new RewindableGenerator(function () { + yield 0 => ($this->services['foo.baz'] ?? $this->requireInScope(__DIR__.'/getFoo_BazService.php')); +}, 1), new RewindableGenerator(function () { + return new \EmptyIterator(); +}, 0)); + + [ProjectServiceContainer/getMethodCall1Service.php] => services['method_call1'] = $instance = new \Bar\FooClass(); + +$instance->setBar(($this->services['foo'] ?? $this->requireInScope(__DIR__.'/getFooService.php'))); +$instance->setBar(NULL); +$instance->setBar((($this->services['foo'] ?? $this->requireInScope(__DIR__.'/getFooService.php'))->foo() . (($this->hasParameter("foo")) ? ($this->getParameter("foo")) : ("default")))); + +return $instance; + + [ProjectServiceContainer/getNewFactoryServiceService.php] => foo = 'bar'; + +$this->services['new_factory_service'] = $instance = $a->getInstance(); + +$instance->foo = 'bar'; + +return $instance; + + [ProjectServiceContainer/getServiceFromStaticMethodService.php] => services['service_from_static_method'] = \Bar\FooClass::getInstance(); + +) diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php index e59b6fed95da5..847b7227925ba 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php @@ -276,7 +276,7 @@ protected function getFoo_BazService() */ protected function getFooBarService() { - return new \Bar\FooClass(); + return new \Bar\FooClass(($this->services['deprecated_service'] ?? $this->getDeprecatedServiceService())); } /** @@ -379,7 +379,7 @@ protected function getServiceFromStaticMethodService() * * @deprecated The "factory_simple" service is deprecated. You should stop using it, as it will soon be removed. */ - private function getFactorySimpleService() + protected function getFactorySimpleService() { @trigger_error('The "factory_simple" service is deprecated. You should stop using it, as it will soon be removed.', E_USER_DEPRECATED); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php index e29fed9d2a727..b6b39bb15a749 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php @@ -29,7 +29,7 @@ public function __construct() { $this->services = $this->privates = array(); $this->methodMap = array( - 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber' => 'getSymfony_Component_DependencyInjection_Tests_Fixtures_TestServiceSubscriberService', + 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber' => 'getTestServiceSubscriberService', 'foo_service' => 'getFooServiceService', ); @@ -66,7 +66,7 @@ public function isCompiled() * * @return \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber */ - protected function getSymfony_Component_DependencyInjection_Tests_Fixtures_TestServiceSubscriberService() + protected function getTestServiceSubscriberService() { return $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber(); } @@ -81,9 +81,9 @@ protected function getFooServiceService() return $this->services['foo_service'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber(new \Symfony\Component\DependencyInjection\ServiceLocator(array('Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => function (): \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition { return ($this->privates['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] ?? ($this->privates['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition())); }, 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber' => function (): \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber { - return ($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] ?? $this->getSymfony_Component_DependencyInjection_Tests_Fixtures_TestServiceSubscriberService()); + return ($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] ?? $this->getTestServiceSubscriberService()); }, 'bar' => function (): \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition { - return ($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] ?? $this->getSymfony_Component_DependencyInjection_Tests_Fixtures_TestServiceSubscriberService()); + return ($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] ?? $this->getTestServiceSubscriberService()); }, 'baz' => function (): \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition { return ($this->privates['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] ?? ($this->privates['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition())); }))); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml index 9b78f7d9eed3f..093a766d9b778 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml @@ -41,7 +41,9 @@ %foo_bar% - + + + %path%foo.php diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml index ddd4c25dd5188..a3a95deeb34c7 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml @@ -31,6 +31,7 @@ services: foo_bar: class: '%foo_class%' shared: false + arguments: ['@deprecated_service'] method_call1: class: Bar\FooClass file: '%path%foo.php' diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 7b935fb4c72b3..1f92b3009c4e0 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -503,7 +503,7 @@ public function testAnonymousServices() $this->assertCount(1, $args); $this->assertInstanceOf(Reference::class, $args[0]); $this->assertTrue($container->has((string) $args[0])); - $this->assertRegExp('/^\d+_[A-Za-z0-9]{64}$/', (string) $args[0]); + $this->assertRegExp('/^\d+_[A-Za-z0-9]{7}$/', (string) $args[0]); $anonymous = $container->getDefinition((string) $args[0]); $this->assertEquals('Bar', $anonymous->getClass()); @@ -515,7 +515,7 @@ public function testAnonymousServices() $this->assertInternalType('array', $factory); $this->assertInstanceOf(Reference::class, $factory[0]); $this->assertTrue($container->has((string) $factory[0])); - $this->assertRegExp('/^\d+_[A-Za-z0-9]{64}$/', (string) $factory[0]); + $this->assertRegExp('/^\d+_[A-Za-z0-9]{7}$/', (string) $factory[0]); $this->assertEquals('constructFoo', $factory[1]); $anonymous = $container->getDefinition((string) $factory[0]); diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index baaf0f8eee5fa..5c0199c60e0eb 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -671,9 +671,29 @@ protected function dumpContainer(ConfigCache $cache, ContainerBuilder $container $dumper->setProxyDumper(new ProxyDumper(md5($cache->getPath()))); } - $content = $dumper->dump(array('class' => $class, 'base_class' => $baseClass, 'file' => $cache->getPath(), 'debug' => $this->debug)); + $content = $dumper->dump(array('class' => $class, 'base_class' => $baseClass, 'file' => $cache->getPath(), 'as_files' => true, 'debug' => $this->debug)); - $cache->write($content, $container->getResources()); + if (is_array($content)) { + foreach ($content as $file => $code) { + $cache->write($code, $container->getResources()); + unset($content[$file]); + break; + } + if (!$content) { + return; + } + $dir = dirname($cache->getPath()).'/'.substr($file, 0, -4); + if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) { + throw new \RuntimeException(sprintf("Unable to create the container directory (%s)\n", $dir)); + } + $dir = dirname($dir).'/'; + foreach ($content as $file => $code) { + file_put_contents($dir.$file, $code); + } + } else { + // BC with di v3.4 + $cache->write($content, $container->getResources()); + } } /**