4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\DependencyInjection\Dumper;
14 use Symfony\Component\DependencyInjection\Variable;
15 use Symfony\Component\DependencyInjection\Definition;
16 use Symfony\Component\DependencyInjection\ContainerBuilder;
17 use Symfony\Component\DependencyInjection\Container;
18 use Symfony\Component\DependencyInjection\ContainerInterface;
19 use Symfony\Component\DependencyInjection\Reference;
20 use Symfony\Component\DependencyInjection\Parameter;
21 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
22 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
23 use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
24 use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface as ProxyDumper;
25 use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper;
26 use Symfony\Component\DependencyInjection\ExpressionLanguage;
27 use Symfony\Component\ExpressionLanguage\Expression;
28 use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
29 use Symfony\Component\HttpKernel\Kernel;
32 * PhpDumper dumps a service container as a PHP class.
34 * @author Fabien Potencier <fabien@symfony.com>
35 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
37 class PhpDumper extends Dumper
40 * Characters that might appear in the generated variable name as first character.
44 const FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz';
47 * Characters that might appear in the generated variable name as any but the first character.
51 const NON_FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789_';
53 private $inlinedDefinitions;
54 private $definitionVariables;
55 private $referenceVariables;
56 private $variableCount;
57 private $reservedVariables = array('instance', 'class');
58 private $expressionLanguage;
59 private $targetDirRegex;
60 private $targetDirMaxMatches;
64 * @var ExpressionFunctionProviderInterface[]
66 private $expressionLanguageProviders = array();
69 * @var \Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface
76 public function __construct(ContainerBuilder $container)
78 parent::__construct($container);
80 $this->inlinedDefinitions = new \SplObjectStorage();
84 * Sets the dumper to be used when dumping proxies in the generated container.
86 * @param ProxyDumper $proxyDumper
88 public function setProxyDumper(ProxyDumper $proxyDumper)
90 $this->proxyDumper = $proxyDumper;
94 * Dumps the service container as a PHP class.
98 * * class: The class name
99 * * base_class: The base class name
100 * * namespace: The class namespace
102 * @param array $options An array of options
104 * @return string A PHP class representing of the service container
106 public function dump(array $options = array())
108 $this->targetDirRegex = null;
109 $options = array_merge(array(
110 'class' => 'ProjectServiceContainer',
111 'base_class' => 'Container',
115 $this->docStar = $options['debug'] ? '*' : '';
117 if (!empty($options['file']) && is_dir($dir = dirname($options['file']))) {
118 // Build a regexp where the first root dirs are mandatory,
119 // but every other sub-dir is optional up to the full path in $dir
120 // Mandate at least 2 root dirs and not more that 5 optional dirs.
122 $dir = explode(DIRECTORY_SEPARATOR, realpath($dir));
127 $lastOptionalDir = $i > 8 ? $i - 5 : 3;
128 $this->targetDirMaxMatches = $i - $lastOptionalDir;
130 while (--$i >= $lastOptionalDir) {
131 $regex = sprintf('(%s%s)?', preg_quote(DIRECTORY_SEPARATOR.$dir[$i], '#'), $regex);
135 $regex = preg_quote(DIRECTORY_SEPARATOR.$dir[$i], '#').$regex;
138 $this->targetDirRegex = '#'.preg_quote($dir[0], '#').$regex.'#';
142 $code = $this->startClass($options['class'], $options['base_class'], $options['namespace']);
144 if ($this->container->isFrozen()) {
145 $code .= $this->addFrozenConstructor();
146 $code .= $this->addFrozenCompile();
147 $code .= $this->addIsFrozenMethod();
149 $code .= $this->addConstructor();
153 $this->addServices().
154 $this->addDefaultParametersMethod().
156 $this->addProxyClasses()
158 $this->targetDirRegex = null;
164 * Retrieves the currently set proxy dumper or instantiates one.
166 * @return ProxyDumper
168 private function getProxyDumper()
170 if (!$this->proxyDumper) {
171 $this->proxyDumper = new NullDumper();
174 return $this->proxyDumper;
178 * Generates Service local temp variables.
181 * @param string $definition
185 private function addServiceLocalTempVariables($cId, $definition)
187 static $template = " \$%s = %s;\n";
189 $localDefinitions = array_merge(
191 $this->getInlinedDefinitions($definition)
194 $calls = $behavior = array();
195 foreach ($localDefinitions as $iDefinition) {
196 $this->getServiceCallsFromArguments($iDefinition->getArguments(), $calls, $behavior);
197 $this->getServiceCallsFromArguments($iDefinition->getMethodCalls(), $calls, $behavior);
198 $this->getServiceCallsFromArguments($iDefinition->getProperties(), $calls, $behavior);
199 $this->getServiceCallsFromArguments(array($iDefinition->getConfigurator()), $calls, $behavior);
200 $this->getServiceCallsFromArguments(array($iDefinition->getFactory()), $calls, $behavior);
204 foreach ($calls as $id => $callCount) {
205 if ('service_container' === $id || $id === $cId) {
209 if ($callCount > 1) {
210 $name = $this->getNextVariableName();
211 $this->referenceVariables[$id] = new Variable($name);
213 if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $behavior[$id]) {
214 $code .= sprintf($template, $name, $this->getServiceCall($id));
216 $code .= sprintf($template, $name, $this->getServiceCall($id, new Reference($id, ContainerInterface::NULL_ON_INVALID_REFERENCE)));
229 * Generates code for the proxies to be attached after the container class.
233 private function addProxyClasses()
235 /* @var $definitions Definition[] */
236 $definitions = array_filter(
237 $this->container->getDefinitions(),
238 array($this->getProxyDumper(), 'isProxyCandidate')
241 $strip = '' === $this->docStar && method_exists('Symfony\Component\HttpKernel\Kernel', 'stripComments');
243 foreach ($definitions as $definition) {
244 $proxyCode = "\n".$this->getProxyDumper()->getProxyCode($definition);
246 $proxyCode = "<?php\n".$proxyCode;
247 $proxyCode = substr(Kernel::stripComments($proxyCode), 5);
256 * Generates the require_once statement for service includes.
258 * @param string $id The service id
259 * @param Definition $definition
263 private function addServiceInclude($id, $definition)
265 $template = " require_once %s;\n";
268 if (null !== $file = $definition->getFile()) {
269 $code .= sprintf($template, $this->dumpValue($file));
272 foreach ($this->getInlinedDefinitions($definition) as $definition) {
273 if (null !== $file = $definition->getFile()) {
274 $code .= sprintf($template, $this->dumpValue($file));
286 * Generates the inline definition of a service.
289 * @param Definition $definition
293 * @throws RuntimeException When the factory definition is incomplete
294 * @throws ServiceCircularReferenceException When a circular reference is detected
296 private function addServiceInlinedDefinitions($id, $definition)
299 $variableMap = $this->definitionVariables;
300 $nbOccurrences = new \SplObjectStorage();
301 $processed = new \SplObjectStorage();
302 $inlinedDefinitions = $this->getInlinedDefinitions($definition);
304 foreach ($inlinedDefinitions as $definition) {
305 if (false === $nbOccurrences->contains($definition)) {
306 $nbOccurrences->offsetSet($definition, 1);
308 $i = $nbOccurrences->offsetGet($definition);
309 $nbOccurrences->offsetSet($definition, $i + 1);
313 foreach ($inlinedDefinitions as $sDefinition) {
314 if ($processed->contains($sDefinition)) {
317 $processed->offsetSet($sDefinition);
319 $class = $this->dumpValue($sDefinition->getClass());
320 if ($nbOccurrences->offsetGet($sDefinition) > 1 || $sDefinition->getMethodCalls() || $sDefinition->getProperties() || null !== $sDefinition->getConfigurator() || false !== strpos($class, '$')) {
321 $name = $this->getNextVariableName();
322 $variableMap->offsetSet($sDefinition, new Variable($name));
325 // $a = new ServiceA(ServiceB $b); $b = new ServiceB(ServiceA $a);
326 // this is an indication for a wrong implementation, you can circumvent this problem
327 // by setting up your service structure like this:
328 // $b = new ServiceB();
329 // $a = new ServiceA(ServiceB $b);
330 // $b->setServiceA(ServiceA $a);
331 if ($this->hasReference($id, $sDefinition->getArguments())) {
332 throw new ServiceCircularReferenceException($id, array($id));
335 $code .= $this->addNewInstance($id, $sDefinition, '$'.$name, ' = ');
337 if (!$this->hasReference($id, $sDefinition->getMethodCalls(), true) && !$this->hasReference($id, $sDefinition->getProperties(), true)) {
338 $code .= $this->addServiceProperties(null, $sDefinition, $name);
339 $code .= $this->addServiceMethodCalls(null, $sDefinition, $name);
340 $code .= $this->addServiceConfigurator(null, $sDefinition, $name);
351 * Adds the service return statement.
353 * @param string $id Service id
354 * @param Definition $definition
358 private function addServiceReturn($id, $definition)
360 if ($this->isSimpleInstance($id, $definition)) {
364 return "\n return \$instance;\n }\n";
368 * Generates the service instance.
371 * @param Definition $definition
375 * @throws InvalidArgumentException
376 * @throws RuntimeException
378 private function addServiceInstance($id, Definition $definition)
380 $class = $definition->getClass();
382 if ('\\' === substr($class, 0, 1)) {
383 $class = substr($class, 1);
386 $class = $this->dumpValue($class);
388 if (0 === strpos($class, "'") && !preg_match('/^\'[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) {
389 throw new InvalidArgumentException(sprintf('"%s" is not a valid class name for the "%s" service.', $class, $id));
392 $simple = $this->isSimpleInstance($id, $definition);
393 $isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition);
396 if (!$isProxyCandidate && $definition->isShared() && ContainerInterface::SCOPE_CONTAINER === $definition->getScope(false)) {
397 $instantiation = "\$this->services['$id'] = ".($simple ? '' : '$instance');
398 } elseif (!$isProxyCandidate && $definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope(false)) {
399 $instantiation = "\$this->services['$id'] = \$this->scopedServices['$scope']['$id'] = ".($simple ? '' : '$instance');
400 } elseif (!$simple) {
401 $instantiation = '$instance';
408 $instantiation .= ' = ';
411 $code = $this->addNewInstance($id, $definition, $return, $instantiation);
421 * Checks if the definition is a simple instance.
424 * @param Definition $definition
428 private function isSimpleInstance($id, Definition $definition)
430 foreach (array_merge(array($definition), $this->getInlinedDefinitions($definition)) as $sDefinition) {
431 if ($definition !== $sDefinition && !$this->hasReference($id, $sDefinition->getMethodCalls())) {
435 if ($sDefinition->getMethodCalls() || $sDefinition->getProperties() || $sDefinition->getConfigurator()) {
444 * Adds method calls to a service definition.
447 * @param Definition $definition
448 * @param string $variableName
452 private function addServiceMethodCalls($id, Definition $definition, $variableName = 'instance')
455 foreach ($definition->getMethodCalls() as $call) {
456 $arguments = array();
457 foreach ($call[1] as $value) {
458 $arguments[] = $this->dumpValue($value);
461 $calls .= $this->wrapServiceConditionals($call[1], sprintf(" \$%s->%s(%s);\n", $variableName, $call[0], implode(', ', $arguments)));
467 private function addServiceProperties($id, Definition $definition, $variableName = 'instance')
470 foreach ($definition->getProperties() as $name => $value) {
471 $code .= sprintf(" \$%s->%s = %s;\n", $variableName, $name, $this->dumpValue($value));
478 * Generates the inline definition setup.
481 * @param Definition $definition
485 * @throws ServiceCircularReferenceException when the container contains a circular reference
487 private function addServiceInlinedDefinitionsSetup($id, Definition $definition)
489 $this->referenceVariables[$id] = new Variable('instance');
492 $processed = new \SplObjectStorage();
493 foreach ($this->getInlinedDefinitions($definition) as $iDefinition) {
494 if ($processed->contains($iDefinition)) {
497 $processed->offsetSet($iDefinition);
499 if (!$this->hasReference($id, $iDefinition->getMethodCalls(), true) && !$this->hasReference($id, $iDefinition->getProperties(), true)) {
503 // if the instance is simple, the return statement has already been generated
504 // so, the only possible way to get there is because of a circular reference
505 if ($this->isSimpleInstance($id, $definition)) {
506 throw new ServiceCircularReferenceException($id, array($id));
509 $name = (string) $this->definitionVariables->offsetGet($iDefinition);
510 $code .= $this->addServiceProperties(null, $iDefinition, $name);
511 $code .= $this->addServiceMethodCalls(null, $iDefinition, $name);
512 $code .= $this->addServiceConfigurator(null, $iDefinition, $name);
523 * Adds configurator definition.
526 * @param Definition $definition
527 * @param string $variableName
531 private function addServiceConfigurator($id, Definition $definition, $variableName = 'instance')
533 if (!$callable = $definition->getConfigurator()) {
537 if (is_array($callable)) {
538 if ($callable[0] instanceof Reference
539 || ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) {
540 return sprintf(" %s->%s(\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
543 $class = $this->dumpValue($callable[0]);
544 // If the class is a string we can optimize call_user_func away
545 if (strpos($class, "'") === 0) {
546 return sprintf(" %s::%s(\$%s);\n", $this->dumpLiteralClass($class), $callable[1], $variableName);
549 return sprintf(" call_user_func(array(%s, '%s'), \$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
552 return sprintf(" %s(\$%s);\n", $callable, $variableName);
559 * @param Definition $definition
563 private function addService($id, Definition $definition)
565 $this->definitionVariables = new \SplObjectStorage();
566 $this->referenceVariables = array();
567 $this->variableCount = 0;
571 if ($definition->isSynthetic()) {
572 $return[] = '@throws RuntimeException always since this service is expected to be injected dynamically';
573 } elseif ($class = $definition->getClass()) {
574 $return[] = sprintf('@return %s A %s instance', 0 === strpos($class, '%') ? 'object' : '\\'.ltrim($class, '\\'), ltrim($class, '\\'));
575 } elseif ($definition->getFactory()) {
576 $factory = $definition->getFactory();
577 if (is_string($factory)) {
578 $return[] = sprintf('@return object An instance returned by %s()', $factory);
579 } elseif (is_array($factory) && (is_string($factory[0]) || $factory[0] instanceof Definition || $factory[0] instanceof Reference)) {
580 if (is_string($factory[0]) || $factory[0] instanceof Reference) {
581 $return[] = sprintf('@return object An instance returned by %s::%s()', (string) $factory[0], $factory[1]);
582 } elseif ($factory[0] instanceof Definition) {
583 $return[] = sprintf('@return object An instance returned by %s::%s()', $factory[0]->getClass(), $factory[1]);
586 } elseif ($definition->getFactoryClass(false)) {
587 $return[] = sprintf('@return object An instance returned by %s::%s()', $definition->getFactoryClass(false), $definition->getFactoryMethod(false));
588 } elseif ($definition->getFactoryService(false)) {
589 $return[] = sprintf('@return object An instance returned by %s::%s()', $definition->getFactoryService(false), $definition->getFactoryMethod(false));
592 $scope = $definition->getScope(false);
593 if (!in_array($scope, array(ContainerInterface::SCOPE_CONTAINER, ContainerInterface::SCOPE_PROTOTYPE))) {
594 if ($return && 0 === strpos($return[count($return) - 1], '@return')) {
597 $return[] = sprintf("@throws InactiveScopeException when the '%s' service is requested while the '%s' scope is not active", $id, $scope);
600 if ($definition->isDeprecated()) {
601 if ($return && 0 === strpos($return[count($return) - 1], '@return')) {
605 $return[] = sprintf('@deprecated %s', $definition->getDeprecationMessage($id));
608 $return = str_replace("\n * \n", "\n *\n", implode("\n * ", $return));
611 if ($definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $scope) {
615 * This service is shared.
616 * This method always returns the same instance of the service.
620 if (!$definition->isPublic()) {
624 * This service is private.
625 * If you want to be able to request this service from the container directly,
626 * make it public, otherwise you might end up with broken code.
630 if ($definition->isAutowired()) {
634 * This service is autowired.
638 if ($definition->isLazy()) {
639 $lazyInitialization = '$lazyLoad = true';
640 $lazyInitializationDoc = "\n * @param bool \$lazyLoad whether to try lazy-loading the service with a proxy\n *";
642 $lazyInitialization = '';
643 $lazyInitializationDoc = '';
646 // with proxies, for 5.3.3 compatibility, the getter must be public to be accessible to the initializer
647 $isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition);
648 $visibility = $isProxyCandidate ? 'public' : 'protected';
652 * Gets the '$id' service.$doc
653 *$lazyInitializationDoc
656 {$visibility} function get{$this->camelize($id)}Service($lazyInitialization)
661 $code .= $isProxyCandidate ? $this->getProxyDumper()->getProxyFactoryCode($definition, $id) : '';
663 if (!in_array($scope, array(ContainerInterface::SCOPE_CONTAINER, ContainerInterface::SCOPE_PROTOTYPE))) {
665 if (!isset(\$this->scopedServices['$scope'])) {
666 throw new InactiveScopeException('$id', '$scope');
673 if ($definition->isSynthetic()) {
674 $code .= sprintf(" throw new RuntimeException('You have requested a synthetic service (\"%s\"). The DIC does not know how to construct this service.');\n }\n", $id);
676 if ($definition->isDeprecated()) {
677 $code .= sprintf(" @trigger_error(%s, E_USER_DEPRECATED);\n\n", var_export($definition->getDeprecationMessage($id), true));
681 $this->addServiceInclude($id, $definition).
682 $this->addServiceLocalTempVariables($id, $definition).
683 $this->addServiceInlinedDefinitions($id, $definition).
684 $this->addServiceInstance($id, $definition).
685 $this->addServiceInlinedDefinitionsSetup($id, $definition).
686 $this->addServiceProperties($id, $definition).
687 $this->addServiceMethodCalls($id, $definition).
688 $this->addServiceConfigurator($id, $definition).
689 $this->addServiceReturn($id, $definition)
693 $this->definitionVariables = null;
694 $this->referenceVariables = null;
700 * Adds multiple services.
704 private function addServices()
706 $publicServices = $privateServices = $synchronizers = '';
707 $definitions = $this->container->getDefinitions();
709 foreach ($definitions as $id => $definition) {
710 if ($definition->isPublic()) {
711 $publicServices .= $this->addService($id, $definition);
713 $privateServices .= $this->addService($id, $definition);
716 $synchronizers .= $this->addServiceSynchronizer($id, $definition);
719 return $publicServices.$synchronizers.$privateServices;
723 * Adds synchronizer methods.
725 * @param string $id A service identifier
726 * @param Definition $definition A Definition instance
728 * @return string|null
730 * @deprecated since version 2.7, will be removed in 3.0.
732 private function addServiceSynchronizer($id, Definition $definition)
734 if (!$definition->isSynchronized(false)) {
738 if ('request' !== $id) {
739 @trigger_error('Synchronized services were deprecated in version 2.7 and won\'t work anymore in 3.0.', E_USER_DEPRECATED);
743 foreach ($this->container->getDefinitions() as $definitionId => $definition) {
744 foreach ($definition->getMethodCalls() as $call) {
745 foreach ($call[1] as $argument) {
746 if ($argument instanceof Reference && $id == (string) $argument) {
747 $arguments = array();
748 foreach ($call[1] as $value) {
749 $arguments[] = $this->dumpValue($value);
752 $call = $this->wrapServiceConditionals($call[1], sprintf("\$this->get('%s')->%s(%s);", $definitionId, $call[0], implode(', ', $arguments)));
755 if (\$this->initialized('$definitionId')) {
772 * Updates the '$id' service.
774 protected function synchronize{$this->camelize($id)}Service()
781 private function addNewInstance($id, Definition $definition, $return, $instantiation)
783 $class = $this->dumpValue($definition->getClass());
785 $arguments = array();
786 foreach ($definition->getArguments() as $value) {
787 $arguments[] = $this->dumpValue($value);
790 if (null !== $definition->getFactory()) {
791 $callable = $definition->getFactory();
792 if (is_array($callable)) {
793 if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $callable[1])) {
794 throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s)', $callable[1] ?: 'n/a'));
797 if ($callable[0] instanceof Reference
798 || ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) {
799 return sprintf(" $return{$instantiation}%s->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : '');
802 $class = $this->dumpValue($callable[0]);
803 // If the class is a string we can optimize call_user_func away
804 if (strpos($class, "'") === 0) {
805 return sprintf(" $return{$instantiation}%s::%s(%s);\n", $this->dumpLiteralClass($class), $callable[1], $arguments ? implode(', ', $arguments) : '');
808 return sprintf(" $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? ', '.implode(', ', $arguments) : '');
811 return sprintf(" $return{$instantiation}\\%s(%s);\n", $callable, $arguments ? implode(', ', $arguments) : '');
812 } elseif (null !== $definition->getFactoryMethod(false)) {
813 if (null !== $definition->getFactoryClass(false)) {
814 $class = $this->dumpValue($definition->getFactoryClass(false));
816 // If the class is a string we can optimize call_user_func away
817 if (strpos($class, "'") === 0) {
818 return sprintf(" $return{$instantiation}%s::%s(%s);\n", $this->dumpLiteralClass($class), $definition->getFactoryMethod(false), $arguments ? implode(', ', $arguments) : '');
821 return sprintf(" $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($definition->getFactoryClass(false)), $definition->getFactoryMethod(false), $arguments ? ', '.implode(', ', $arguments) : '');
824 if (null !== $definition->getFactoryService(false)) {
825 return sprintf(" $return{$instantiation}%s->%s(%s);\n", $this->getServiceCall($definition->getFactoryService(false)), $definition->getFactoryMethod(false), implode(', ', $arguments));
828 throw new RuntimeException(sprintf('Factory method requires a factory service or factory class in service definition for %s', $id));
831 if (false !== strpos($class, '$')) {
832 return sprintf(" \$class = %s;\n\n $return{$instantiation}new \$class(%s);\n", $class, implode(', ', $arguments));
835 return sprintf(" $return{$instantiation}new %s(%s);\n", $this->dumpLiteralClass($class), implode(', ', $arguments));
839 * Adds the class headers.
841 * @param string $class Class name
842 * @param string $baseClass The name of the base class
843 * @param string $namespace The class namespace
847 private function startClass($class, $baseClass, $namespace)
849 $bagClass = $this->container->isFrozen() ? 'use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;' : 'use Symfony\Component\DependencyInjection\ParameterBag\\ParameterBag;';
850 $namespaceLine = $namespace ? "\nnamespace $namespace;\n" : '';
855 use Symfony\Component\DependencyInjection\ContainerInterface;
856 use Symfony\Component\DependencyInjection\Container;
857 use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
858 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
859 use Symfony\Component\DependencyInjection\Exception\LogicException;
860 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
866 * This class has been auto-generated
867 * by the Symfony Dependency Injection Component.
869 class $class extends $baseClass
871 private \$parameters;
872 private \$targetDirs = array();
878 * Adds the constructor.
882 private function addConstructor()
884 $targetDirs = $this->exportTargetDirs();
885 $arguments = $this->container->getParameterBag()->all() ? 'new ParameterBag($this->getDefaultParameters())' : null;
892 public function __construct()
894 parent::__construct($arguments);
898 if (count($scopes = $this->container->getScopes(false)) > 0) {
900 $code .= ' $this->scopes = '.$this->dumpValue($scopes).";\n";
901 $code .= ' $this->scopeChildren = '.$this->dumpValue($this->container->getScopeChildren(false)).";\n";
904 $code .= $this->addMethodMap();
905 $code .= $this->addAliases();
916 * Adds the constructor for a frozen container.
920 private function addFrozenConstructor()
922 $targetDirs = $this->exportTargetDirs();
929 public function __construct()
933 if ($this->container->getParameterBag()->all()) {
934 $code .= "\n \$this->parameters = \$this->getDefaultParameters();\n";
940 $this->scopedServices =
941 $this->scopeStacks = array();
945 if (count($scopes = $this->container->getScopes(false)) > 0) {
946 $code .= ' $this->scopes = '.$this->dumpValue($scopes).";\n";
947 $code .= ' $this->scopeChildren = '.$this->dumpValue($this->container->getScopeChildren(false)).";\n";
949 $code .= " \$this->scopes = array();\n";
950 $code .= " \$this->scopeChildren = array();\n";
953 $code .= $this->addMethodMap();
954 $code .= $this->addAliases();
965 * Adds the constructor for a frozen container.
969 private function addFrozenCompile()
976 public function compile()
978 throw new LogicException('You cannot compile a dumped frozen container.');
985 * Adds the isFrozen method for a frozen container.
989 private function addIsFrozenMethod()
996 public function isFrozen()
1005 * Adds the methodMap property definition.
1009 private function addMethodMap()
1011 if (!$definitions = $this->container->getDefinitions()) {
1015 $code = " \$this->methodMap = array(\n";
1016 ksort($definitions);
1017 foreach ($definitions as $id => $definition) {
1018 $code .= ' '.var_export($id, true).' => '.var_export('get'.$this->camelize($id).'Service', true).",\n";
1021 return $code." );\n";
1025 * Adds the aliases property definition.
1029 private function addAliases()
1031 if (!$aliases = $this->container->getAliases()) {
1032 return $this->container->isFrozen() ? "\n \$this->aliases = array();\n" : '';
1035 $code = " \$this->aliases = array(\n";
1037 foreach ($aliases as $alias => $id) {
1039 while (isset($aliases[$id])) {
1040 $id = (string) $aliases[$id];
1042 $code .= ' '.var_export($alias, true).' => '.var_export($id, true).",\n";
1045 return $code." );\n";
1049 * Adds default parameters method.
1053 private function addDefaultParametersMethod()
1055 if (!$this->container->getParameterBag()->all()) {
1059 $parameters = $this->exportParameters($this->container->getParameterBag()->all());
1062 if ($this->container->isFrozen()) {
1068 public function getParameter($name)
1070 $name = strtolower($name);
1072 if (!(isset($this->parameters[$name]) || array_key_exists($name, $this->parameters))) {
1073 throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
1076 return $this->parameters[$name];
1082 public function hasParameter($name)
1084 $name = strtolower($name);
1086 return isset($this->parameters[$name]) || array_key_exists($name, $this->parameters);
1092 public function setParameter($name, $value)
1094 throw new LogicException('Impossible to call set() on a frozen ParameterBag.');
1100 public function getParameterBag()
1102 if (null === $this->parameterBag) {
1103 $this->parameterBag = new FrozenParameterBag($this->parameters);
1106 return $this->parameterBag;
1110 if ('' === $this->docStar) {
1111 $code = str_replace('/**', '/*', $code);
1118 * Gets the default parameters.
1120 * @return array An array of the default parameters
1122 protected function getDefaultParameters()
1133 * Exports parameters.
1135 * @param array $parameters
1136 * @param string $path
1137 * @param int $indent
1141 * @throws InvalidArgumentException
1143 private function exportParameters(array $parameters, $path = '', $indent = 12)
1146 foreach ($parameters as $key => $value) {
1147 if (is_array($value)) {
1148 $value = $this->exportParameters($value, $path.'/'.$key, $indent + 4);
1149 } elseif ($value instanceof Variable) {
1150 throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain variable references. Variable "%s" found in "%s".', $value, $path.'/'.$key));
1151 } elseif ($value instanceof Definition) {
1152 throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain service definitions. Definition for "%s" found in "%s".', $value->getClass(), $path.'/'.$key));
1153 } elseif ($value instanceof Reference) {
1154 throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain references to other services (reference to service "%s" found in "%s").', $value, $path.'/'.$key));
1155 } elseif ($value instanceof Expression) {
1156 throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain expressions. Expression "%s" found in "%s".', $value, $path.'/'.$key));
1158 $value = $this->export($value);
1161 $php[] = sprintf('%s%s => %s,', str_repeat(' ', $indent), var_export($key, true), $value);
1164 return sprintf("array(\n%s\n%s)", implode("\n", $php), str_repeat(' ', $indent - 4));
1168 * Ends the class definition.
1172 private function endClass()
1181 * Wraps the service conditionals.
1183 * @param string $value
1184 * @param string $code
1188 private function wrapServiceConditionals($value, $code)
1190 if (!$services = ContainerBuilder::getServiceConditionals($value)) {
1194 $conditions = array();
1195 foreach ($services as $service) {
1196 $conditions[] = sprintf("\$this->has('%s')", $service);
1199 // re-indent the wrapped code
1200 $code = implode("\n", array_map(function ($line) { return $line ? ' '.$line : $line; }, explode("\n", $code)));
1202 return sprintf(" if (%s) {\n%s }\n", implode(' && ', $conditions), $code);
1206 * Builds service calls from arguments.
1208 * @param array $arguments
1209 * @param array &$calls By reference
1210 * @param array &$behavior By reference
1212 private function getServiceCallsFromArguments(array $arguments, array &$calls, array &$behavior)
1214 foreach ($arguments as $argument) {
1215 if (is_array($argument)) {
1216 $this->getServiceCallsFromArguments($argument, $calls, $behavior);
1217 } elseif ($argument instanceof Reference) {
1218 $id = (string) $argument;
1220 if (!isset($calls[$id])) {
1223 if (!isset($behavior[$id])) {
1224 $behavior[$id] = $argument->getInvalidBehavior();
1225 } elseif (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $behavior[$id]) {
1226 $behavior[$id] = $argument->getInvalidBehavior();
1235 * Returns the inline definition.
1237 * @param Definition $definition
1241 private function getInlinedDefinitions(Definition $definition)
1243 if (false === $this->inlinedDefinitions->contains($definition)) {
1244 $definitions = array_merge(
1245 $this->getDefinitionsFromArguments($definition->getArguments()),
1246 $this->getDefinitionsFromArguments($definition->getMethodCalls()),
1247 $this->getDefinitionsFromArguments($definition->getProperties()),
1248 $this->getDefinitionsFromArguments(array($definition->getConfigurator())),
1249 $this->getDefinitionsFromArguments(array($definition->getFactory()))
1252 $this->inlinedDefinitions->offsetSet($definition, $definitions);
1254 return $definitions;
1257 return $this->inlinedDefinitions->offsetGet($definition);
1261 * Gets the definition from arguments.
1263 * @param array $arguments
1267 private function getDefinitionsFromArguments(array $arguments)
1269 $definitions = array();
1270 foreach ($arguments as $argument) {
1271 if (is_array($argument)) {
1272 $definitions = array_merge($definitions, $this->getDefinitionsFromArguments($argument));
1273 } elseif ($argument instanceof Definition) {
1274 $definitions = array_merge(
1276 $this->getInlinedDefinitions($argument),
1282 return $definitions;
1286 * Checks if a service id has a reference.
1289 * @param array $arguments
1291 * @param array $visited
1295 private function hasReference($id, array $arguments, $deep = false, array &$visited = array())
1297 foreach ($arguments as $argument) {
1298 if (is_array($argument)) {
1299 if ($this->hasReference($id, $argument, $deep, $visited)) {
1302 } elseif ($argument instanceof Reference) {
1303 $argumentId = (string) $argument;
1304 if ($id === $argumentId) {
1308 if ($deep && !isset($visited[$argumentId]) && 'service_container' !== $argumentId) {
1309 $visited[$argumentId] = true;
1311 $service = $this->container->getDefinition($argumentId);
1313 // if the proxy manager is enabled, disable searching for references in lazy services,
1314 // as these services will be instantiated lazily and don't have direct related references.
1315 if ($service->isLazy() && !$this->getProxyDumper() instanceof NullDumper) {
1319 $arguments = array_merge($service->getMethodCalls(), $service->getArguments(), $service->getProperties());
1321 if ($this->hasReference($id, $arguments, $deep, $visited)) {
1334 * @param mixed $value
1335 * @param bool $interpolate
1339 * @throws RuntimeException
1341 private function dumpValue($value, $interpolate = true)
1343 if (is_array($value)) {
1345 foreach ($value as $k => $v) {
1346 $code[] = sprintf('%s => %s', $this->dumpValue($k, $interpolate), $this->dumpValue($v, $interpolate));
1349 return sprintf('array(%s)', implode(', ', $code));
1350 } elseif ($value instanceof Definition) {
1351 if (null !== $this->definitionVariables && $this->definitionVariables->contains($value)) {
1352 return $this->dumpValue($this->definitionVariables->offsetGet($value), $interpolate);
1354 if ($value->getMethodCalls()) {
1355 throw new RuntimeException('Cannot dump definitions which have method calls.');
1357 if ($value->getProperties()) {
1358 throw new RuntimeException('Cannot dump definitions which have properties.');
1360 if (null !== $value->getConfigurator()) {
1361 throw new RuntimeException('Cannot dump definitions which have a configurator.');
1364 $arguments = array();
1365 foreach ($value->getArguments() as $argument) {
1366 $arguments[] = $this->dumpValue($argument);
1369 if (null !== $value->getFactory()) {
1370 $factory = $value->getFactory();
1372 if (is_string($factory)) {
1373 return sprintf('\\%s(%s)', $factory, implode(', ', $arguments));
1376 if (is_array($factory)) {
1377 if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $factory[1])) {
1378 throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s)', $factory[1] ?: 'n/a'));
1381 if (is_string($factory[0])) {
1382 return sprintf('%s::%s(%s)', $this->dumpLiteralClass($this->dumpValue($factory[0])), $factory[1], implode(', ', $arguments));
1385 if ($factory[0] instanceof Definition) {
1386 return sprintf("call_user_func(array(%s, '%s')%s)", $this->dumpValue($factory[0]), $factory[1], count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
1389 if ($factory[0] instanceof Reference) {
1390 return sprintf('%s->%s(%s)', $this->dumpValue($factory[0]), $factory[1], implode(', ', $arguments));
1394 throw new RuntimeException('Cannot dump definition because of invalid factory');
1397 if (null !== $value->getFactoryMethod(false)) {
1398 if (null !== $value->getFactoryClass(false)) {
1399 return sprintf("call_user_func(array(%s, '%s')%s)", $this->dumpValue($value->getFactoryClass(false)), $value->getFactoryMethod(false), count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
1400 } elseif (null !== $value->getFactoryService(false)) {
1401 $service = $this->dumpValue($value->getFactoryService(false));
1403 return sprintf('%s->%s(%s)', 0 === strpos($service, '$') ? sprintf('$this->get(%s)', $service) : $this->getServiceCall($value->getFactoryService(false)), $value->getFactoryMethod(false), implode(', ', $arguments));
1406 throw new RuntimeException('Cannot dump definitions which have factory method without factory service or factory class.');
1409 $class = $value->getClass();
1410 if (null === $class) {
1411 throw new RuntimeException('Cannot dump definitions which have no class nor factory.');
1414 return sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments));
1415 } elseif ($value instanceof Variable) {
1417 } elseif ($value instanceof Reference) {
1418 if (null !== $this->referenceVariables && isset($this->referenceVariables[$id = (string) $value])) {
1419 return $this->dumpValue($this->referenceVariables[$id], $interpolate);
1422 return $this->getServiceCall((string) $value, $value);
1423 } elseif ($value instanceof Expression) {
1424 return $this->getExpressionLanguage()->compile((string) $value, array('this' => 'container'));
1425 } elseif ($value instanceof Parameter) {
1426 return $this->dumpParameter($value);
1427 } elseif (true === $interpolate && is_string($value)) {
1428 if (preg_match('/^%([^%]+)%$/', $value, $match)) {
1429 // we do this to deal with non string values (Boolean, integer, ...)
1430 // the preg_replace_callback converts them to strings
1431 return $this->dumpParameter(strtolower($match[1]));
1434 $replaceParameters = function ($match) use ($that) {
1435 return "'.".$that->dumpParameter(strtolower($match[2])).".'";
1438 $code = str_replace('%%', '%', preg_replace_callback('/(?<!%)(%)([^%]+)\1/', $replaceParameters, $this->export($value)));
1442 } elseif (is_object($value) || is_resource($value)) {
1443 throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
1446 return $this->export($value);
1450 * Dumps a string to a literal (aka PHP Code) class value.
1452 * @param string $class
1456 * @throws RuntimeException
1458 private function dumpLiteralClass($class)
1460 if (false !== strpos($class, '$')) {
1461 throw new RuntimeException('Cannot dump definitions which have a variable class name.');
1463 if (0 !== strpos($class, "'") || !preg_match('/^\'[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) {
1464 throw new RuntimeException(sprintf('Cannot dump definition because of invalid class name (%s)', $class ?: 'n/a'));
1467 return '\\'.substr(str_replace('\\\\', '\\', $class), 1, -1);
1471 * Dumps a parameter.
1473 * @param string $name
1477 public function dumpParameter($name)
1479 if ($this->container->isFrozen() && $this->container->hasParameter($name)) {
1480 return $this->dumpValue($this->container->getParameter($name), false);
1483 return sprintf("\$this->getParameter('%s')", strtolower($name));
1487 * @deprecated since version 2.6.2, to be removed in 3.0.
1488 * Use \Symfony\Component\DependencyInjection\ContainerBuilder::addExpressionLanguageProvider instead.
1490 * @param ExpressionFunctionProviderInterface $provider
1492 public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
1494 @trigger_error('The '.__METHOD__.' method is deprecated since version 2.6.2 and will be removed in 3.0. Use the Symfony\Component\DependencyInjection\ContainerBuilder::addExpressionLanguageProvider method instead.', E_USER_DEPRECATED);
1496 $this->expressionLanguageProviders[] = $provider;
1500 * Gets a service call.
1503 * @param Reference $reference
1507 private function getServiceCall($id, Reference $reference = null)
1509 if ('service_container' === $id) {
1513 if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
1514 return sprintf('$this->get(\'%s\', ContainerInterface::NULL_ON_INVALID_REFERENCE)', $id);
1517 if ($this->container->hasAlias($id)) {
1518 $id = (string) $this->container->getAlias($id);
1521 return sprintf('$this->get(\'%s\')', $id);
1525 * Convert a service id to a valid PHP method name.
1531 * @throws InvalidArgumentException
1533 private function camelize($id)
1535 $name = Container::camelize($id);
1537 if (!preg_match('/^[a-zA-Z0-9_\x7f-\xff]+$/', $name)) {
1538 throw new InvalidArgumentException(sprintf('Service id "%s" cannot be converted to a valid PHP method name.', $id));
1545 * Returns the next name to use.
1549 private function getNextVariableName()
1551 $firstChars = self::FIRST_CHARS;
1552 $firstCharsLength = strlen($firstChars);
1553 $nonFirstChars = self::NON_FIRST_CHARS;
1554 $nonFirstCharsLength = strlen($nonFirstChars);
1558 $i = $this->variableCount;
1561 $name .= $firstChars[$i % $firstCharsLength];
1562 $i = (int) ($i / $firstCharsLength);
1567 $name .= $nonFirstChars[$i % $nonFirstCharsLength];
1568 $i = (int) ($i / $nonFirstCharsLength);
1571 ++$this->variableCount;
1573 // check that the name is not reserved
1574 if (in_array($name, $this->reservedVariables, true)) {
1582 private function getExpressionLanguage()
1584 if (null === $this->expressionLanguage) {
1585 if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
1586 throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
1588 $providers = array_merge($this->container->getExpressionLanguageProviders(), $this->expressionLanguageProviders);
1589 $this->expressionLanguage = new ExpressionLanguage(null, $providers);
1591 if ($this->container->isTrackingResources()) {
1592 foreach ($providers as $provider) {
1593 $this->container->addObjectResource($provider);
1598 return $this->expressionLanguage;
1601 private function exportTargetDirs()
1603 return null === $this->targetDirRegex ? '' : <<<EOF
1606 for (\$i = 1; \$i <= {$this->targetDirMaxMatches}; ++\$i) {
1607 \$this->targetDirs[\$i] = \$dir = dirname(\$dir);
1612 private function export($value)
1614 if (null !== $this->targetDirRegex && is_string($value) && preg_match($this->targetDirRegex, $value, $matches, PREG_OFFSET_CAPTURE)) {
1615 $prefix = $matches[0][1] ? var_export(substr($value, 0, $matches[0][1]), true).'.' : '';
1616 $suffix = $matches[0][1] + strlen($matches[0][0]);
1617 $suffix = isset($value[$suffix]) ? '.'.var_export(substr($value, $suffix), true) : '';
1618 $dirname = '__DIR__';
1620 if (0 < $offset = 1 + $this->targetDirMaxMatches - count($matches)) {
1621 $dirname = sprintf('$this->targetDirs[%d]', $offset);
1624 if ($prefix || $suffix) {
1625 return sprintf('(%s%s%s)', $prefix, $dirname, $suffix);
1631 return var_export($value, true);