Verzeichnisstruktur phpBB-3.2.0
- Veröffentlicht
- 06.01.2017
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
PhpDumper.php
0001 <?php
0002
0003 /*
0004 * This file is part of the Symfony package.
0005 *
0006 * (c) Fabien Potencier <fabien@symfony.com>
0007 *
0008 * For the full copyright and license information, please view the LICENSE
0009 * file that was distributed with this source code.
0010 */
0011
0012 namespace Symfony\Component\DependencyInjection\Dumper;
0013
0014 use Symfony\Component\DependencyInjection\Variable;
0015 use Symfony\Component\DependencyInjection\Definition;
0016 use Symfony\Component\DependencyInjection\ContainerBuilder;
0017 use Symfony\Component\DependencyInjection\Container;
0018 use Symfony\Component\DependencyInjection\ContainerInterface;
0019 use Symfony\Component\DependencyInjection\Reference;
0020 use Symfony\Component\DependencyInjection\Parameter;
0021 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
0022 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
0023 use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
0024 use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface as ProxyDumper;
0025 use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper;
0026 use Symfony\Component\DependencyInjection\ExpressionLanguage;
0027 use Symfony\Component\ExpressionLanguage\Expression;
0028 use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
0029 use Symfony\Component\HttpKernel\Kernel;
0030
0031 /**
0032 * PhpDumper dumps a service container as a PHP class.
0033 *
0034 * @author Fabien Potencier <fabien@symfony.com>
0035 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
0036 */
0037 class PhpDumper extends Dumper
0038 {
0039 /**
0040 * Characters that might appear in the generated variable name as first character.
0041 *
0042 * @var string
0043 */
0044 const FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz';
0045
0046 /**
0047 * Characters that might appear in the generated variable name as any but the first character.
0048 *
0049 * @var string
0050 */
0051 const NON_FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789_';
0052
0053 private $inlinedDefinitions;
0054 private $definitionVariables;
0055 private $referenceVariables;
0056 private $variableCount;
0057 private $reservedVariables = array('instance', 'class');
0058 private $expressionLanguage;
0059 private $targetDirRegex;
0060 private $targetDirMaxMatches;
0061 private $docStar;
0062
0063 /**
0064 * @var ExpressionFunctionProviderInterface[]
0065 */
0066 private $expressionLanguageProviders = array();
0067
0068 /**
0069 * @var \Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface
0070 */
0071 private $proxyDumper;
0072
0073 /**
0074 * {@inheritdoc}
0075 */
0076 public function __construct(ContainerBuilder $container)
0077 {
0078 parent::__construct($container);
0079
0080 $this->inlinedDefinitions = new \SplObjectStorage();
0081 }
0082
0083 /**
0084 * Sets the dumper to be used when dumping proxies in the generated container.
0085 *
0086 * @param ProxyDumper $proxyDumper
0087 */
0088 public function setProxyDumper(ProxyDumper $proxyDumper)
0089 {
0090 $this->proxyDumper = $proxyDumper;
0091 }
0092
0093 /**
0094 * Dumps the service container as a PHP class.
0095 *
0096 * Available options:
0097 *
0098 * * class: The class name
0099 * * base_class: The base class name
0100 * * namespace: The class namespace
0101 *
0102 * @param array $options An array of options
0103 *
0104 * @return string A PHP class representing of the service container
0105 */
0106 public function dump(array $options = array())
0107 {
0108 $this->targetDirRegex = null;
0109 $options = array_merge(array(
0110 'class' => 'ProjectServiceContainer',
0111 'base_class' => 'Container',
0112 'namespace' => '',
0113 'debug' => true,
0114 ), $options);
0115 $this->docStar = $options['debug'] ? '*' : '';
0116
0117 if (!empty($options['file']) && is_dir($dir = dirname($options['file']))) {
0118 // Build a regexp where the first root dirs are mandatory,
0119 // but every other sub-dir is optional up to the full path in $dir
0120 // Mandate at least 2 root dirs and not more that 5 optional dirs.
0121
0122 $dir = explode(DIRECTORY_SEPARATOR, realpath($dir));
0123 $i = count($dir);
0124
0125 if (3 <= $i) {
0126 $regex = '';
0127 $lastOptionalDir = $i > 8 ? $i - 5 : 3;
0128 $this->targetDirMaxMatches = $i - $lastOptionalDir;
0129
0130 while (--$i >= $lastOptionalDir) {
0131 $regex = sprintf('(%s%s)?', preg_quote(DIRECTORY_SEPARATOR.$dir[$i], '#'), $regex);
0132 }
0133
0134 do {
0135 $regex = preg_quote(DIRECTORY_SEPARATOR.$dir[$i], '#').$regex;
0136 } while (0 < --$i);
0137
0138 $this->targetDirRegex = '#'.preg_quote($dir[0], '#').$regex.'#';
0139 }
0140 }
0141
0142 $code = $this->startClass($options['class'], $options['base_class'], $options['namespace']);
0143
0144 if ($this->container->isFrozen()) {
0145 $code .= $this->addFrozenConstructor();
0146 $code .= $this->addFrozenCompile();
0147 $code .= $this->addIsFrozenMethod();
0148 } else {
0149 $code .= $this->addConstructor();
0150 }
0151
0152 $code .=
0153 $this->addServices().
0154 $this->addDefaultParametersMethod().
0155 $this->endClass().
0156 $this->addProxyClasses()
0157 ;
0158 $this->targetDirRegex = null;
0159
0160 return $code;
0161 }
0162
0163 /**
0164 * Retrieves the currently set proxy dumper or instantiates one.
0165 *
0166 * @return ProxyDumper
0167 */
0168 private function getProxyDumper()
0169 {
0170 if (!$this->proxyDumper) {
0171 $this->proxyDumper = new NullDumper();
0172 }
0173
0174 return $this->proxyDumper;
0175 }
0176
0177 /**
0178 * Generates Service local temp variables.
0179 *
0180 * @param string $cId
0181 * @param string $definition
0182 *
0183 * @return string
0184 */
0185 private function addServiceLocalTempVariables($cId, $definition)
0186 {
0187 static $template = " \$%s = %s;\n";
0188
0189 $localDefinitions = array_merge(
0190 array($definition),
0191 $this->getInlinedDefinitions($definition)
0192 );
0193
0194 $calls = $behavior = array();
0195 foreach ($localDefinitions as $iDefinition) {
0196 $this->getServiceCallsFromArguments($iDefinition->getArguments(), $calls, $behavior);
0197 $this->getServiceCallsFromArguments($iDefinition->getMethodCalls(), $calls, $behavior);
0198 $this->getServiceCallsFromArguments($iDefinition->getProperties(), $calls, $behavior);
0199 $this->getServiceCallsFromArguments(array($iDefinition->getConfigurator()), $calls, $behavior);
0200 $this->getServiceCallsFromArguments(array($iDefinition->getFactory()), $calls, $behavior);
0201 }
0202
0203 $code = '';
0204 foreach ($calls as $id => $callCount) {
0205 if ('service_container' === $id || $id === $cId) {
0206 continue;
0207 }
0208
0209 if ($callCount > 1) {
0210 $name = $this->getNextVariableName();
0211 $this->referenceVariables[$id] = new Variable($name);
0212
0213 if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $behavior[$id]) {
0214 $code .= sprintf($template, $name, $this->getServiceCall($id));
0215 } else {
0216 $code .= sprintf($template, $name, $this->getServiceCall($id, new Reference($id, ContainerInterface::NULL_ON_INVALID_REFERENCE)));
0217 }
0218 }
0219 }
0220
0221 if ('' !== $code) {
0222 $code .= "\n";
0223 }
0224
0225 return $code;
0226 }
0227
0228 /**
0229 * Generates code for the proxies to be attached after the container class.
0230 *
0231 * @return string
0232 */
0233 private function addProxyClasses()
0234 {
0235 /* @var $definitions Definition[] */
0236 $definitions = array_filter(
0237 $this->container->getDefinitions(),
0238 array($this->getProxyDumper(), 'isProxyCandidate')
0239 );
0240 $code = '';
0241 $strip = '' === $this->docStar && method_exists('Symfony\Component\HttpKernel\Kernel', 'stripComments');
0242
0243 foreach ($definitions as $definition) {
0244 $proxyCode = "\n".$this->getProxyDumper()->getProxyCode($definition);
0245 if ($strip) {
0246 $proxyCode = "<?php\n".$proxyCode;
0247 $proxyCode = substr(Kernel::stripComments($proxyCode), 5);
0248 }
0249 $code .= $proxyCode;
0250 }
0251
0252 return $code;
0253 }
0254
0255 /**
0256 * Generates the require_once statement for service includes.
0257 *
0258 * @param string $id The service id
0259 * @param Definition $definition
0260 *
0261 * @return string
0262 */
0263 private function addServiceInclude($id, $definition)
0264 {
0265 $template = " require_once %s;\n";
0266 $code = '';
0267
0268 if (null !== $file = $definition->getFile()) {
0269 $code .= sprintf($template, $this->dumpValue($file));
0270 }
0271
0272 foreach ($this->getInlinedDefinitions($definition) as $definition) {
0273 if (null !== $file = $definition->getFile()) {
0274 $code .= sprintf($template, $this->dumpValue($file));
0275 }
0276 }
0277
0278 if ('' !== $code) {
0279 $code .= "\n";
0280 }
0281
0282 return $code;
0283 }
0284
0285 /**
0286 * Generates the inline definition of a service.
0287 *
0288 * @param string $id
0289 * @param Definition $definition
0290 *
0291 * @return string
0292 *
0293 * @throws RuntimeException When the factory definition is incomplete
0294 * @throws ServiceCircularReferenceException When a circular reference is detected
0295 */
0296 private function addServiceInlinedDefinitions($id, $definition)
0297 {
0298 $code = '';
0299 $variableMap = $this->definitionVariables;
0300 $nbOccurrences = new \SplObjectStorage();
0301 $processed = new \SplObjectStorage();
0302 $inlinedDefinitions = $this->getInlinedDefinitions($definition);
0303
0304 foreach ($inlinedDefinitions as $definition) {
0305 if (false === $nbOccurrences->contains($definition)) {
0306 $nbOccurrences->offsetSet($definition, 1);
0307 } else {
0308 $i = $nbOccurrences->offsetGet($definition);
0309 $nbOccurrences->offsetSet($definition, $i + 1);
0310 }
0311 }
0312
0313 foreach ($inlinedDefinitions as $sDefinition) {
0314 if ($processed->contains($sDefinition)) {
0315 continue;
0316 }
0317 $processed->offsetSet($sDefinition);
0318
0319 $class = $this->dumpValue($sDefinition->getClass());
0320 if ($nbOccurrences->offsetGet($sDefinition) > 1 || $sDefinition->getMethodCalls() || $sDefinition->getProperties() || null !== $sDefinition->getConfigurator() || false !== strpos($class, '$')) {
0321 $name = $this->getNextVariableName();
0322 $variableMap->offsetSet($sDefinition, new Variable($name));
0323
0324 // a construct like:
0325 // $a = new ServiceA(ServiceB $b); $b = new ServiceB(ServiceA $a);
0326 // this is an indication for a wrong implementation, you can circumvent this problem
0327 // by setting up your service structure like this:
0328 // $b = new ServiceB();
0329 // $a = new ServiceA(ServiceB $b);
0330 // $b->setServiceA(ServiceA $a);
0331 if ($this->hasReference($id, $sDefinition->getArguments())) {
0332 throw new ServiceCircularReferenceException($id, array($id));
0333 }
0334
0335 $code .= $this->addNewInstance($id, $sDefinition, '$'.$name, ' = ');
0336
0337 if (!$this->hasReference($id, $sDefinition->getMethodCalls(), true) && !$this->hasReference($id, $sDefinition->getProperties(), true)) {
0338 $code .= $this->addServiceMethodCalls(null, $sDefinition, $name);
0339 $code .= $this->addServiceProperties(null, $sDefinition, $name);
0340 $code .= $this->addServiceConfigurator(null, $sDefinition, $name);
0341 }
0342
0343 $code .= "\n";
0344 }
0345 }
0346
0347 return $code;
0348 }
0349
0350 /**
0351 * Adds the service return statement.
0352 *
0353 * @param string $id Service id
0354 * @param Definition $definition
0355 *
0356 * @return string
0357 */
0358 private function addServiceReturn($id, $definition)
0359 {
0360 if ($this->isSimpleInstance($id, $definition)) {
0361 return " }\n";
0362 }
0363
0364 return "\n return \$instance;\n }\n";
0365 }
0366
0367 /**
0368 * Generates the service instance.
0369 *
0370 * @param string $id
0371 * @param Definition $definition
0372 *
0373 * @return string
0374 *
0375 * @throws InvalidArgumentException
0376 * @throws RuntimeException
0377 */
0378 private function addServiceInstance($id, Definition $definition)
0379 {
0380 $class = $definition->getClass();
0381
0382 if ('\\' === substr($class, 0, 1)) {
0383 $class = substr($class, 1);
0384 }
0385
0386 $class = $this->dumpValue($class);
0387
0388 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)) {
0389 throw new InvalidArgumentException(sprintf('"%s" is not a valid class name for the "%s" service.', $class, $id));
0390 }
0391
0392 $simple = $this->isSimpleInstance($id, $definition);
0393 $isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition);
0394 $instantiation = '';
0395
0396 if (!$isProxyCandidate && $definition->isShared() && ContainerInterface::SCOPE_CONTAINER === $definition->getScope(false)) {
0397 $instantiation = "\$this->services['$id'] = ".($simple ? '' : '$instance');
0398 } elseif (!$isProxyCandidate && $definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope(false)) {
0399 $instantiation = "\$this->services['$id'] = \$this->scopedServices['$scope']['$id'] = ".($simple ? '' : '$instance');
0400 } elseif (!$simple) {
0401 $instantiation = '$instance';
0402 }
0403
0404 $return = '';
0405 if ($simple) {
0406 $return = 'return ';
0407 } else {
0408 $instantiation .= ' = ';
0409 }
0410
0411 $code = $this->addNewInstance($id, $definition, $return, $instantiation);
0412
0413 if (!$simple) {
0414 $code .= "\n";
0415 }
0416
0417 return $code;
0418 }
0419
0420 /**
0421 * Checks if the definition is a simple instance.
0422 *
0423 * @param string $id
0424 * @param Definition $definition
0425 *
0426 * @return bool
0427 */
0428 private function isSimpleInstance($id, Definition $definition)
0429 {
0430 foreach (array_merge(array($definition), $this->getInlinedDefinitions($definition)) as $sDefinition) {
0431 if ($definition !== $sDefinition && !$this->hasReference($id, $sDefinition->getMethodCalls())) {
0432 continue;
0433 }
0434
0435 if ($sDefinition->getMethodCalls() || $sDefinition->getProperties() || $sDefinition->getConfigurator()) {
0436 return false;
0437 }
0438 }
0439
0440 return true;
0441 }
0442
0443 /**
0444 * Adds method calls to a service definition.
0445 *
0446 * @param string $id
0447 * @param Definition $definition
0448 * @param string $variableName
0449 *
0450 * @return string
0451 */
0452 private function addServiceMethodCalls($id, Definition $definition, $variableName = 'instance')
0453 {
0454 $calls = '';
0455 foreach ($definition->getMethodCalls() as $call) {
0456 $arguments = array();
0457 foreach ($call[1] as $value) {
0458 $arguments[] = $this->dumpValue($value);
0459 }
0460
0461 $calls .= $this->wrapServiceConditionals($call[1], sprintf(" \$%s->%s(%s);\n", $variableName, $call[0], implode(', ', $arguments)));
0462 }
0463
0464 return $calls;
0465 }
0466
0467 private function addServiceProperties($id, Definition $definition, $variableName = 'instance')
0468 {
0469 $code = '';
0470 foreach ($definition->getProperties() as $name => $value) {
0471 $code .= sprintf(" \$%s->%s = %s;\n", $variableName, $name, $this->dumpValue($value));
0472 }
0473
0474 return $code;
0475 }
0476
0477 /**
0478 * Generates the inline definition setup.
0479 *
0480 * @param string $id
0481 * @param Definition $definition
0482 *
0483 * @return string
0484 *
0485 * @throws ServiceCircularReferenceException when the container contains a circular reference
0486 */
0487 private function addServiceInlinedDefinitionsSetup($id, Definition $definition)
0488 {
0489 $this->referenceVariables[$id] = new Variable('instance');
0490
0491 $code = '';
0492 $processed = new \SplObjectStorage();
0493 foreach ($this->getInlinedDefinitions($definition) as $iDefinition) {
0494 if ($processed->contains($iDefinition)) {
0495 continue;
0496 }
0497 $processed->offsetSet($iDefinition);
0498
0499 if (!$this->hasReference($id, $iDefinition->getMethodCalls(), true) && !$this->hasReference($id, $iDefinition->getProperties(), true)) {
0500 continue;
0501 }
0502
0503 // if the instance is simple, the return statement has already been generated
0504 // so, the only possible way to get there is because of a circular reference
0505 if ($this->isSimpleInstance($id, $definition)) {
0506 throw new ServiceCircularReferenceException($id, array($id));
0507 }
0508
0509 $name = (string) $this->definitionVariables->offsetGet($iDefinition);
0510 $code .= $this->addServiceMethodCalls(null, $iDefinition, $name);
0511 $code .= $this->addServiceProperties(null, $iDefinition, $name);
0512 $code .= $this->addServiceConfigurator(null, $iDefinition, $name);
0513 }
0514
0515 if ('' !== $code) {
0516 $code .= "\n";
0517 }
0518
0519 return $code;
0520 }
0521
0522 /**
0523 * Adds configurator definition.
0524 *
0525 * @param string $id
0526 * @param Definition $definition
0527 * @param string $variableName
0528 *
0529 * @return string
0530 */
0531 private function addServiceConfigurator($id, Definition $definition, $variableName = 'instance')
0532 {
0533 if (!$callable = $definition->getConfigurator()) {
0534 return '';
0535 }
0536
0537 if (is_array($callable)) {
0538 if ($callable[0] instanceof Reference
0539 || ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) {
0540 return sprintf(" %s->%s(\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
0541 }
0542
0543 $class = $this->dumpValue($callable[0]);
0544 // If the class is a string we can optimize call_user_func away
0545 if (strpos($class, "'") === 0) {
0546 return sprintf(" %s::%s(\$%s);\n", $this->dumpLiteralClass($class), $callable[1], $variableName);
0547 }
0548
0549 return sprintf(" call_user_func(array(%s, '%s'), \$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
0550 }
0551
0552 return sprintf(" %s(\$%s);\n", $callable, $variableName);
0553 }
0554
0555 /**
0556 * Adds a service.
0557 *
0558 * @param string $id
0559 * @param Definition $definition
0560 *
0561 * @return string
0562 */
0563 private function addService($id, Definition $definition)
0564 {
0565 $this->definitionVariables = new \SplObjectStorage();
0566 $this->referenceVariables = array();
0567 $this->variableCount = 0;
0568
0569 $return = array();
0570
0571 if ($definition->isSynthetic()) {
0572 $return[] = '@throws RuntimeException always since this service is expected to be injected dynamically';
0573 } elseif ($class = $definition->getClass()) {
0574 $return[] = sprintf('@return %s A %s instance', 0 === strpos($class, '%') ? 'object' : '\\'.ltrim($class, '\\'), ltrim($class, '\\'));
0575 } elseif ($definition->getFactory()) {
0576 $factory = $definition->getFactory();
0577 if (is_string($factory)) {
0578 $return[] = sprintf('@return object An instance returned by %s()', $factory);
0579 } elseif (is_array($factory) && (is_string($factory[0]) || $factory[0] instanceof Definition || $factory[0] instanceof Reference)) {
0580 if (is_string($factory[0]) || $factory[0] instanceof Reference) {
0581 $return[] = sprintf('@return object An instance returned by %s::%s()', (string) $factory[0], $factory[1]);
0582 } elseif ($factory[0] instanceof Definition) {
0583 $return[] = sprintf('@return object An instance returned by %s::%s()', $factory[0]->getClass(), $factory[1]);
0584 }
0585 }
0586 } elseif ($definition->getFactoryClass(false)) {
0587 $return[] = sprintf('@return object An instance returned by %s::%s()', $definition->getFactoryClass(false), $definition->getFactoryMethod(false));
0588 } elseif ($definition->getFactoryService(false)) {
0589 $return[] = sprintf('@return object An instance returned by %s::%s()', $definition->getFactoryService(false), $definition->getFactoryMethod(false));
0590 }
0591
0592 $scope = $definition->getScope(false);
0593 if (!in_array($scope, array(ContainerInterface::SCOPE_CONTAINER, ContainerInterface::SCOPE_PROTOTYPE))) {
0594 if ($return && 0 === strpos($return[count($return) - 1], '@return')) {
0595 $return[] = '';
0596 }
0597 $return[] = sprintf("@throws InactiveScopeException when the '%s' service is requested while the '%s' scope is not active", $id, $scope);
0598 }
0599
0600 if ($definition->isDeprecated()) {
0601 if ($return && 0 === strpos($return[count($return) - 1], '@return')) {
0602 $return[] = '';
0603 }
0604
0605 $return[] = sprintf('@deprecated %s', $definition->getDeprecationMessage($id));
0606 }
0607
0608 $return = str_replace("\n * \n", "\n *\n", implode("\n * ", $return));
0609
0610 $doc = '';
0611 if ($definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $scope) {
0612 $doc .= <<<'EOF'
0613
0614 *
0615 * This service is shared.
0616 * This method always returns the same instance of the service.
0617 EOF;
0618
0619 }
0620
0621 if (!$definition->isPublic()) {
0622 $doc .= <<<'EOF'
0623
0624 *
0625 * This service is private.
0626 * If you want to be able to request this service from the container directly,
0627 * make it public, otherwise you might end up with broken code.
0628 EOF;
0629
0630 }
0631
0632 if ($definition->isAutowired()) {
0633 $doc = <<<EOF
0634
0635 *
0636 * This service is autowired.
0637 EOF;
0638
0639 }
0640
0641 if ($definition->isLazy()) {
0642 $lazyInitialization = '$lazyLoad = true';
0643 $lazyInitializationDoc = "\n * @param bool \$lazyLoad whether to try lazy-loading the service with a proxy\n *";
0644 } else {
0645 $lazyInitialization = '';
0646 $lazyInitializationDoc = '';
0647 }
0648
0649 // with proxies, for 5.3.3 compatibility, the getter must be public to be accessible to the initializer
0650 $isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition);
0651 $visibility = $isProxyCandidate ? 'public' : 'protected';
0652 $code = <<<EOF
0653
0654 /*{$this->docStar}
0655 * Gets the '$id' service.$doc
0656 *$lazyInitializationDoc
0657 * $return
0658 */
0659 {$visibility} function get{$this->camelize($id)}Service($lazyInitialization)
0660 {
0661
0662 EOF;
0663
0664
0665 $code .= $isProxyCandidate ? $this->getProxyDumper()->getProxyFactoryCode($definition, $id) : '';
0666
0667 if (!in_array($scope, array(ContainerInterface::SCOPE_CONTAINER, ContainerInterface::SCOPE_PROTOTYPE))) {
0668 $code .= <<<EOF
0669 if (!isset(\$this->scopedServices['$scope'])) {
0670 throw new InactiveScopeException('$id', '$scope');
0671 }
0672
0673
0674 EOF;
0675
0676 }
0677
0678 if ($definition->isSynthetic()) {
0679 $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);
0680 } else {
0681 if ($definition->isDeprecated()) {
0682 $code .= sprintf(" @trigger_error(%s, E_USER_DEPRECATED);\n\n", var_export($definition->getDeprecationMessage($id), true));
0683 }
0684
0685 $code .=
0686 $this->addServiceInclude($id, $definition).
0687 $this->addServiceLocalTempVariables($id, $definition).
0688 $this->addServiceInlinedDefinitions($id, $definition).
0689 $this->addServiceInstance($id, $definition).
0690 $this->addServiceInlinedDefinitionsSetup($id, $definition).
0691 $this->addServiceMethodCalls($id, $definition).
0692 $this->addServiceProperties($id, $definition).
0693 $this->addServiceConfigurator($id, $definition).
0694 $this->addServiceReturn($id, $definition)
0695 ;
0696 }
0697
0698 $this->definitionVariables = null;
0699 $this->referenceVariables = null;
0700
0701 return $code;
0702 }
0703
0704 /**
0705 * Adds multiple services.
0706 *
0707 * @return string
0708 */
0709 private function addServices()
0710 {
0711 $publicServices = $privateServices = $synchronizers = '';
0712 $definitions = $this->container->getDefinitions();
0713 ksort($definitions);
0714 foreach ($definitions as $id => $definition) {
0715 if ($definition->isPublic()) {
0716 $publicServices .= $this->addService($id, $definition);
0717 } else {
0718 $privateServices .= $this->addService($id, $definition);
0719 }
0720
0721 $synchronizers .= $this->addServiceSynchronizer($id, $definition);
0722 }
0723
0724 return $publicServices.$synchronizers.$privateServices;
0725 }
0726
0727 /**
0728 * Adds synchronizer methods.
0729 *
0730 * @param string $id A service identifier
0731 * @param Definition $definition A Definition instance
0732 *
0733 * @return string|null
0734 *
0735 * @deprecated since version 2.7, will be removed in 3.0.
0736 */
0737 private function addServiceSynchronizer($id, Definition $definition)
0738 {
0739 if (!$definition->isSynchronized(false)) {
0740 return;
0741 }
0742
0743 if ('request' !== $id) {
0744 @trigger_error('Synchronized services were deprecated in version 2.7 and won\'t work anymore in 3.0.', E_USER_DEPRECATED);
0745 }
0746
0747 $code = '';
0748 foreach ($this->container->getDefinitions() as $definitionId => $definition) {
0749 foreach ($definition->getMethodCalls() as $call) {
0750 foreach ($call[1] as $argument) {
0751 if ($argument instanceof Reference && $id == (string) $argument) {
0752 $arguments = array();
0753 foreach ($call[1] as $value) {
0754 $arguments[] = $this->dumpValue($value);
0755 }
0756
0757 $call = $this->wrapServiceConditionals($call[1], sprintf("\$this->get('%s')->%s(%s);", $definitionId, $call[0], implode(', ', $arguments)));
0758
0759 $code .= <<<EOF
0760 if (\$this->initialized('$definitionId')) {
0761 $call
0762 }
0763
0764 EOF;
0765
0766 }
0767 }
0768 }
0769 }
0770
0771 if (!$code) {
0772 return;
0773 }
0774
0775 return <<<EOF
0776
0777 /*{$this->docStar}
0778 * Updates the '$id' service.
0779 */
0780 protected function synchronize{$this->camelize($id)}Service()
0781 {
0782 $code }
0783
0784 EOF;
0785
0786 }
0787
0788 private function addNewInstance($id, Definition $definition, $return, $instantiation)
0789 {
0790 $class = $this->dumpValue($definition->getClass());
0791
0792 $arguments = array();
0793 foreach ($definition->getArguments() as $value) {
0794 $arguments[] = $this->dumpValue($value);
0795 }
0796
0797 if (null !== $definition->getFactory()) {
0798 $callable = $definition->getFactory();
0799 if (is_array($callable)) {
0800 if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $callable[1])) {
0801 throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s)', $callable[1] ?: 'n/a'));
0802 }
0803
0804 if ($callable[0] instanceof Reference
0805 || ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) {
0806 return sprintf(" $return{$instantiation}%s->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : '');
0807 }
0808
0809 $class = $this->dumpValue($callable[0]);
0810 // If the class is a string we can optimize call_user_func away
0811 if (strpos($class, "'") === 0) {
0812 return sprintf(" $return{$instantiation}%s::%s(%s);\n", $this->dumpLiteralClass($class), $callable[1], $arguments ? implode(', ', $arguments) : '');
0813 }
0814
0815 return sprintf(" $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? ', '.implode(', ', $arguments) : '');
0816 }
0817
0818 return sprintf(" $return{$instantiation}\\%s(%s);\n", $callable, $arguments ? implode(', ', $arguments) : '');
0819 } elseif (null !== $definition->getFactoryMethod(false)) {
0820 if (null !== $definition->getFactoryClass(false)) {
0821 $class = $this->dumpValue($definition->getFactoryClass(false));
0822
0823 // If the class is a string we can optimize call_user_func away
0824 if (strpos($class, "'") === 0) {
0825 return sprintf(" $return{$instantiation}%s::%s(%s);\n", $this->dumpLiteralClass($class), $definition->getFactoryMethod(false), $arguments ? implode(', ', $arguments) : '');
0826 }
0827
0828 return sprintf(" $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($definition->getFactoryClass(false)), $definition->getFactoryMethod(false), $arguments ? ', '.implode(', ', $arguments) : '');
0829 }
0830
0831 if (null !== $definition->getFactoryService(false)) {
0832 return sprintf(" $return{$instantiation}%s->%s(%s);\n", $this->getServiceCall($definition->getFactoryService(false)), $definition->getFactoryMethod(false), implode(', ', $arguments));
0833 }
0834
0835 throw new RuntimeException(sprintf('Factory method requires a factory service or factory class in service definition for %s', $id));
0836 }
0837
0838 if (false !== strpos($class, '$')) {
0839 return sprintf(" \$class = %s;\n\n $return{$instantiation}new \$class(%s);\n", $class, implode(', ', $arguments));
0840 }
0841
0842 return sprintf(" $return{$instantiation}new %s(%s);\n", $this->dumpLiteralClass($class), implode(', ', $arguments));
0843 }
0844
0845 /**
0846 * Adds the class headers.
0847 *
0848 * @param string $class Class name
0849 * @param string $baseClass The name of the base class
0850 * @param string $namespace The class namespace
0851 *
0852 * @return string
0853 */
0854 private function startClass($class, $baseClass, $namespace)
0855 {
0856 $bagClass = $this->container->isFrozen() ? 'use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;' : 'use Symfony\Component\DependencyInjection\ParameterBag\\ParameterBag;';
0857 $namespaceLine = $namespace ? "namespace $namespace;\n" : '';
0858
0859 return <<<EOF
0860 <?php
0861 $namespaceLine
0862 use Symfony\Component\DependencyInjection\ContainerInterface;
0863 use Symfony\Component\DependencyInjection\Container;
0864 use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
0865 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
0866 use Symfony\Component\DependencyInjection\Exception\LogicException;
0867 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
0868 $bagClass
0869
0870 /*{$this->docStar}
0871 * $class.
0872 *
0873 * This class has been auto-generated
0874 * by the Symfony Dependency Injection Component.
0875 */
0876 class $class extends $baseClass
0877 {
0878 private \$parameters;
0879 private \$targetDirs = array();
0880
0881 EOF;
0882
0883 }
0884
0885 /**
0886 * Adds the constructor.
0887 *
0888 * @return string
0889 */
0890 private function addConstructor()
0891 {
0892 $targetDirs = $this->exportTargetDirs();
0893 $arguments = $this->container->getParameterBag()->all() ? 'new ParameterBag($this->getDefaultParameters())' : null;
0894
0895 $code = <<<EOF
0896
0897 /*{$this->docStar}
0898 * Constructor.
0899 */
0900 public function __construct()
0901 {{$targetDirs}
0902 parent::__construct($arguments);
0903
0904 EOF;
0905
0906
0907 if (count($scopes = $this->container->getScopes(false)) > 0) {
0908 $code .= "\n";
0909 $code .= ' $this->scopes = '.$this->dumpValue($scopes).";\n";
0910 $code .= ' $this->scopeChildren = '.$this->dumpValue($this->container->getScopeChildren(false)).";\n";
0911 }
0912
0913 $code .= $this->addMethodMap();
0914 $code .= $this->addAliases();
0915
0916 $code .= <<<'EOF'
0917 }
0918
0919 EOF;
0920
0921
0922 return $code;
0923 }
0924
0925 /**
0926 * Adds the constructor for a frozen container.
0927 *
0928 * @return string
0929 */
0930 private function addFrozenConstructor()
0931 {
0932 $targetDirs = $this->exportTargetDirs();
0933
0934 $code = <<<EOF
0935
0936 /*{$this->docStar}
0937 * Constructor.
0938 */
0939 public function __construct()
0940 {{$targetDirs}
0941 EOF;
0942
0943
0944 if ($this->container->getParameterBag()->all()) {
0945 $code .= "\n \$this->parameters = \$this->getDefaultParameters();\n";
0946 }
0947
0948 $code .= <<<'EOF'
0949
0950 $this->services =
0951 $this->scopedServices =
0952 $this->scopeStacks = array();
0953 EOF;
0954
0955
0956 $code .= "\n";
0957 if (count($scopes = $this->container->getScopes(false)) > 0) {
0958 $code .= ' $this->scopes = '.$this->dumpValue($scopes).";\n";
0959 $code .= ' $this->scopeChildren = '.$this->dumpValue($this->container->getScopeChildren(false)).";\n";
0960 } else {
0961 $code .= " \$this->scopes = array();\n";
0962 $code .= " \$this->scopeChildren = array();\n";
0963 }
0964
0965 $code .= $this->addMethodMap();
0966 $code .= $this->addAliases();
0967
0968 $code .= <<<'EOF'
0969 }
0970
0971 EOF;
0972
0973
0974 return $code;
0975 }
0976
0977 /**
0978 * Adds the constructor for a frozen container.
0979 *
0980 * @return string
0981 */
0982 private function addFrozenCompile()
0983 {
0984 return <<<EOF
0985
0986 /*{$this->docStar}
0987 * {@inheritdoc}
0988 */
0989 public function compile()
0990 {
0991 throw new LogicException('You cannot compile a dumped frozen container.');
0992 }
0993
0994 EOF;
0995
0996 }
0997
0998 /**
0999 * Adds the isFrozen method for a frozen container.
1000 *
1001 * @return string
1002 */
1003 private function addIsFrozenMethod()
1004 {
1005 return <<<EOF
1006
1007 /*{$this->docStar}
1008 * {@inheritdoc}
1009 */
1010 public function isFrozen()
1011 {
1012 return true;
1013 }
1014
1015 EOF;
1016
1017 }
1018
1019 /**
1020 * Adds the methodMap property definition.
1021 *
1022 * @return string
1023 */
1024 private function addMethodMap()
1025 {
1026 if (!$definitions = $this->container->getDefinitions()) {
1027 return '';
1028 }
1029
1030 $code = " \$this->methodMap = array(\n";
1031 ksort($definitions);
1032 foreach ($definitions as $id => $definition) {
1033 $code .= ' '.var_export($id, true).' => '.var_export('get'.$this->camelize($id).'Service', true).",\n";
1034 }
1035
1036 return $code." );\n";
1037 }
1038
1039 /**
1040 * Adds the aliases property definition.
1041 *
1042 * @return string
1043 */
1044 private function addAliases()
1045 {
1046 if (!$aliases = $this->container->getAliases()) {
1047 if ($this->container->isFrozen()) {
1048 return "\n \$this->aliases = array();\n";
1049 } else {
1050 return '';
1051 }
1052 }
1053
1054 $code = " \$this->aliases = array(\n";
1055 ksort($aliases);
1056 foreach ($aliases as $alias => $id) {
1057 $id = (string) $id;
1058 while (isset($aliases[$id])) {
1059 $id = (string) $aliases[$id];
1060 }
1061 $code .= ' '.var_export($alias, true).' => '.var_export($id, true).",\n";
1062 }
1063
1064 return $code." );\n";
1065 }
1066
1067 /**
1068 * Adds default parameters method.
1069 *
1070 * @return string
1071 */
1072 private function addDefaultParametersMethod()
1073 {
1074 if (!$this->container->getParameterBag()->all()) {
1075 return '';
1076 }
1077
1078 $parameters = $this->exportParameters($this->container->getParameterBag()->all());
1079
1080 $code = '';
1081 if ($this->container->isFrozen()) {
1082 $code .= <<<'EOF'
1083
1084 /**
1085 * {@inheritdoc}
1086 */
1087 public function getParameter($name)
1088 {
1089 $name = strtolower($name);
1090
1091 if (!(isset($this->parameters[$name]) || array_key_exists($name, $this->parameters))) {
1092 throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
1093 }
1094
1095 return $this->parameters[$name];
1096 }
1097
1098 /**
1099 * {@inheritdoc}
1100 */
1101 public function hasParameter($name)
1102 {
1103 $name = strtolower($name);
1104
1105 return isset($this->parameters[$name]) || array_key_exists($name, $this->parameters);
1106 }
1107
1108 /**
1109 * {@inheritdoc}
1110 */
1111 public function setParameter($name, $value)
1112 {
1113 throw new LogicException('Impossible to call set() on a frozen ParameterBag.');
1114 }
1115
1116 /**
1117 * {@inheritdoc}
1118 */
1119 public function getParameterBag()
1120 {
1121 if (null === $this->parameterBag) {
1122 $this->parameterBag = new FrozenParameterBag($this->parameters);
1123 }
1124
1125 return $this->parameterBag;
1126 }
1127
1128 EOF;
1129
1130 if ('' === $this->docStar) {
1131 $code = str_replace('/**', '/*', $code);
1132 }
1133 }
1134
1135 $code .= <<<EOF
1136
1137 /*{$this->docStar}
1138 * Gets the default parameters.
1139 *
1140 * @return array An array of the default parameters
1141 */
1142 protected function getDefaultParameters()
1143 {
1144 return $parameters;
1145 }
1146
1147 EOF;
1148
1149
1150 return $code;
1151 }
1152
1153 /**
1154 * Exports parameters.
1155 *
1156 * @param array $parameters
1157 * @param string $path
1158 * @param int $indent
1159 *
1160 * @return string
1161 *
1162 * @throws InvalidArgumentException
1163 */
1164 private function exportParameters(array $parameters, $path = '', $indent = 12)
1165 {
1166 $php = array();
1167 foreach ($parameters as $key => $value) {
1168 if (is_array($value)) {
1169 $value = $this->exportParameters($value, $path.'/'.$key, $indent + 4);
1170 } elseif ($value instanceof Variable) {
1171 throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain variable references. Variable "%s" found in "%s".', $value, $path.'/'.$key));
1172 } elseif ($value instanceof Definition) {
1173 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));
1174 } elseif ($value instanceof Reference) {
1175 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));
1176 } elseif ($value instanceof Expression) {
1177 throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain expressions. Expression "%s" found in "%s".', $value, $path.'/'.$key));
1178 } else {
1179 $value = $this->export($value);
1180 }
1181
1182 $php[] = sprintf('%s%s => %s,', str_repeat(' ', $indent), var_export($key, true), $value);
1183 }
1184
1185 return sprintf("array(\n%s\n%s)", implode("\n", $php), str_repeat(' ', $indent - 4));
1186 }
1187
1188 /**
1189 * Ends the class definition.
1190 *
1191 * @return string
1192 */
1193 private function endClass()
1194 {
1195 return <<<'EOF'
1196 }
1197
1198 EOF;
1199
1200 }
1201
1202 /**
1203 * Wraps the service conditionals.
1204 *
1205 * @param string $value
1206 * @param string $code
1207 *
1208 * @return string
1209 */
1210 private function wrapServiceConditionals($value, $code)
1211 {
1212 if (!$services = ContainerBuilder::getServiceConditionals($value)) {
1213 return $code;
1214 }
1215
1216 $conditions = array();
1217 foreach ($services as $service) {
1218 $conditions[] = sprintf("\$this->has('%s')", $service);
1219 }
1220
1221 // re-indent the wrapped code
1222 $code = implode("\n", array_map(function ($line) { return $line ? ' '.$line : $line; }, explode("\n", $code)));
1223
1224 return sprintf(" if (%s) {\n%s }\n", implode(' && ', $conditions), $code);
1225 }
1226
1227 /**
1228 * Builds service calls from arguments.
1229 *
1230 * @param array $arguments
1231 * @param array &$calls By reference
1232 * @param array &$behavior By reference
1233 */
1234 private function getServiceCallsFromArguments(array $arguments, array &$calls, array &$behavior)
1235 {
1236 foreach ($arguments as $argument) {
1237 if (is_array($argument)) {
1238 $this->getServiceCallsFromArguments($argument, $calls, $behavior);
1239 } elseif ($argument instanceof Reference) {
1240 $id = (string) $argument;
1241
1242 if (!isset($calls[$id])) {
1243 $calls[$id] = 0;
1244 }
1245 if (!isset($behavior[$id])) {
1246 $behavior[$id] = $argument->getInvalidBehavior();
1247 } elseif (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $behavior[$id]) {
1248 $behavior[$id] = $argument->getInvalidBehavior();
1249 }
1250
1251 ++$calls[$id];
1252 }
1253 }
1254 }
1255
1256 /**
1257 * Returns the inline definition.
1258 *
1259 * @param Definition $definition
1260 *
1261 * @return array
1262 */
1263 private function getInlinedDefinitions(Definition $definition)
1264 {
1265 if (false === $this->inlinedDefinitions->contains($definition)) {
1266 $definitions = array_merge(
1267 $this->getDefinitionsFromArguments($definition->getArguments()),
1268 $this->getDefinitionsFromArguments($definition->getMethodCalls()),
1269 $this->getDefinitionsFromArguments($definition->getProperties()),
1270 $this->getDefinitionsFromArguments(array($definition->getConfigurator())),
1271 $this->getDefinitionsFromArguments(array($definition->getFactory()))
1272 );
1273
1274 $this->inlinedDefinitions->offsetSet($definition, $definitions);
1275
1276 return $definitions;
1277 }
1278
1279 return $this->inlinedDefinitions->offsetGet($definition);
1280 }
1281
1282 /**
1283 * Gets the definition from arguments.
1284 *
1285 * @param array $arguments
1286 *
1287 * @return array
1288 */
1289 private function getDefinitionsFromArguments(array $arguments)
1290 {
1291 $definitions = array();
1292 foreach ($arguments as $argument) {
1293 if (is_array($argument)) {
1294 $definitions = array_merge($definitions, $this->getDefinitionsFromArguments($argument));
1295 } elseif ($argument instanceof Definition) {
1296 $definitions = array_merge(
1297 $definitions,
1298 $this->getInlinedDefinitions($argument),
1299 array($argument)
1300 );
1301 }
1302 }
1303
1304 return $definitions;
1305 }
1306
1307 /**
1308 * Checks if a service id has a reference.
1309 *
1310 * @param string $id
1311 * @param array $arguments
1312 * @param bool $deep
1313 * @param array $visited
1314 *
1315 * @return bool
1316 */
1317 private function hasReference($id, array $arguments, $deep = false, array &$visited = array())
1318 {
1319 foreach ($arguments as $argument) {
1320 if (is_array($argument)) {
1321 if ($this->hasReference($id, $argument, $deep, $visited)) {
1322 return true;
1323 }
1324 } elseif ($argument instanceof Reference) {
1325 $argumentId = (string) $argument;
1326 if ($id === $argumentId) {
1327 return true;
1328 }
1329
1330 if ($deep && !isset($visited[$argumentId]) && 'service_container' !== $argumentId) {
1331 $visited[$argumentId] = true;
1332
1333 $service = $this->container->getDefinition($argumentId);
1334 $arguments = array_merge($service->getMethodCalls(), $service->getArguments(), $service->getProperties());
1335
1336 if ($this->hasReference($id, $arguments, $deep, $visited)) {
1337 return true;
1338 }
1339 }
1340 }
1341 }
1342
1343 return false;
1344 }
1345
1346 /**
1347 * Dumps values.
1348 *
1349 * @param mixed $value
1350 * @param bool $interpolate
1351 *
1352 * @return string
1353 *
1354 * @throws RuntimeException
1355 */
1356 private function dumpValue($value, $interpolate = true)
1357 {
1358 if (is_array($value)) {
1359 $code = array();
1360 foreach ($value as $k => $v) {
1361 $code[] = sprintf('%s => %s', $this->dumpValue($k, $interpolate), $this->dumpValue($v, $interpolate));
1362 }
1363
1364 return sprintf('array(%s)', implode(', ', $code));
1365 } elseif ($value instanceof Definition) {
1366 if (null !== $this->definitionVariables && $this->definitionVariables->contains($value)) {
1367 return $this->dumpValue($this->definitionVariables->offsetGet($value), $interpolate);
1368 }
1369 if (count($value->getMethodCalls()) > 0) {
1370 throw new RuntimeException('Cannot dump definitions which have method calls.');
1371 }
1372 if (null !== $value->getConfigurator()) {
1373 throw new RuntimeException('Cannot dump definitions which have a configurator.');
1374 }
1375
1376 $arguments = array();
1377 foreach ($value->getArguments() as $argument) {
1378 $arguments[] = $this->dumpValue($argument);
1379 }
1380
1381 if (null !== $value->getFactory()) {
1382 $factory = $value->getFactory();
1383
1384 if (is_string($factory)) {
1385 return sprintf('\\%s(%s)', $factory, implode(', ', $arguments));
1386 }
1387
1388 if (is_array($factory)) {
1389 if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $factory[1])) {
1390 throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s)', $factory[1] ?: 'n/a'));
1391 }
1392
1393 if (is_string($factory[0])) {
1394 return sprintf('%s::%s(%s)', $this->dumpLiteralClass($this->dumpValue($factory[0])), $factory[1], implode(', ', $arguments));
1395 }
1396
1397 if ($factory[0] instanceof Definition) {
1398 return sprintf("call_user_func(array(%s, '%s')%s)", $this->dumpValue($factory[0]), $factory[1], count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
1399 }
1400
1401 if ($factory[0] instanceof Reference) {
1402 return sprintf('%s->%s(%s)', $this->dumpValue($factory[0]), $factory[1], implode(', ', $arguments));
1403 }
1404 }
1405
1406 throw new RuntimeException('Cannot dump definition because of invalid factory');
1407 }
1408
1409 if (null !== $value->getFactoryMethod(false)) {
1410 if (null !== $value->getFactoryClass(false)) {
1411 return sprintf("call_user_func(array(%s, '%s')%s)", $this->dumpValue($value->getFactoryClass(false)), $value->getFactoryMethod(false), count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
1412 } elseif (null !== $value->getFactoryService(false)) {
1413 $service = $this->dumpValue($value->getFactoryService(false));
1414
1415 return sprintf('%s->%s(%s)', 0 === strpos($service, '$') ? sprintf('$this->get(%s)', $service) : $this->getServiceCall($value->getFactoryService(false)), $value->getFactoryMethod(false), implode(', ', $arguments));
1416 } else {
1417 throw new RuntimeException('Cannot dump definitions which have factory method without factory service or factory class.');
1418 }
1419 }
1420
1421 $class = $value->getClass();
1422 if (null === $class) {
1423 throw new RuntimeException('Cannot dump definitions which have no class nor factory.');
1424 }
1425
1426 return sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments));
1427 } elseif ($value instanceof Variable) {
1428 return '$'.$value;
1429 } elseif ($value instanceof Reference) {
1430 if (null !== $this->referenceVariables && isset($this->referenceVariables[$id = (string) $value])) {
1431 return $this->dumpValue($this->referenceVariables[$id], $interpolate);
1432 }
1433
1434 return $this->getServiceCall((string) $value, $value);
1435 } elseif ($value instanceof Expression) {
1436 return $this->getExpressionLanguage()->compile((string) $value, array('this' => 'container'));
1437 } elseif ($value instanceof Parameter) {
1438 return $this->dumpParameter($value);
1439 } elseif (true === $interpolate && is_string($value)) {
1440 if (preg_match('/^%([^%]+)%$/', $value, $match)) {
1441 // we do this to deal with non string values (Boolean, integer, ...)
1442 // the preg_replace_callback converts them to strings
1443 return $this->dumpParameter(strtolower($match[1]));
1444 } else {
1445 $that = $this;
1446 $replaceParameters = function ($match) use ($that) {
1447 return "'.".$that->dumpParameter(strtolower($match[2])).".'";
1448 };
1449
1450 $code = str_replace('%%', '%', preg_replace_callback('/(?<!%)(%)([^%]+)\1/', $replaceParameters, $this->export($value)));
1451
1452 return $code;
1453 }
1454 } elseif (is_object($value) || is_resource($value)) {
1455 throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
1456 } else {
1457 return $this->export($value);
1458 }
1459 }
1460
1461 /**
1462 * Dumps a string to a literal (aka PHP Code) class value.
1463 *
1464 * @param string $class
1465 *
1466 * @return string
1467 *
1468 * @throws RuntimeException
1469 */
1470 private function dumpLiteralClass($class)
1471 {
1472 if (false !== strpos($class, '$')) {
1473 throw new RuntimeException('Cannot dump definitions which have a variable class name.');
1474 }
1475 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)) {
1476 throw new RuntimeException(sprintf('Cannot dump definition because of invalid class name (%s)', $class ?: 'n/a'));
1477 }
1478
1479 return '\\'.substr(str_replace('\\\\', '\\', $class), 1, -1);
1480 }
1481
1482 /**
1483 * Dumps a parameter.
1484 *
1485 * @param string $name
1486 *
1487 * @return string
1488 */
1489 public function dumpParameter($name)
1490 {
1491 if ($this->container->isFrozen() && $this->container->hasParameter($name)) {
1492 return $this->dumpValue($this->container->getParameter($name), false);
1493 }
1494
1495 return sprintf("\$this->getParameter('%s')", strtolower($name));
1496 }
1497
1498 /**
1499 * @deprecated since version 2.6.2, to be removed in 3.0.
1500 * Use \Symfony\Component\DependencyInjection\ContainerBuilder::addExpressionLanguageProvider instead.
1501 *
1502 * @param ExpressionFunctionProviderInterface $provider
1503 */
1504 public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
1505 {
1506 @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);
1507
1508 $this->expressionLanguageProviders[] = $provider;
1509 }
1510
1511 /**
1512 * Gets a service call.
1513 *
1514 * @param string $id
1515 * @param Reference $reference
1516 *
1517 * @return string
1518 */
1519 private function getServiceCall($id, Reference $reference = null)
1520 {
1521 if ('service_container' === $id) {
1522 return '$this';
1523 }
1524
1525 if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
1526 return sprintf('$this->get(\'%s\', ContainerInterface::NULL_ON_INVALID_REFERENCE)', $id);
1527 } else {
1528 if ($this->container->hasAlias($id)) {
1529 $id = (string) $this->container->getAlias($id);
1530 }
1531
1532 return sprintf('$this->get(\'%s\')', $id);
1533 }
1534 }
1535
1536 /**
1537 * Convert a service id to a valid PHP method name.
1538 *
1539 * @param string $id
1540 *
1541 * @return string
1542 *
1543 * @throws InvalidArgumentException
1544 */
1545 private function camelize($id)
1546 {
1547 $name = Container::camelize($id);
1548
1549 if (!preg_match('/^[a-zA-Z0-9_\x7f-\xff]+$/', $name)) {
1550 throw new InvalidArgumentException(sprintf('Service id "%s" cannot be converted to a valid PHP method name.', $id));
1551 }
1552
1553 return $name;
1554 }
1555
1556 /**
1557 * Returns the next name to use.
1558 *
1559 * @return string
1560 */
1561 private function getNextVariableName()
1562 {
1563 $firstChars = self::FIRST_CHARS;
1564 $firstCharsLength = strlen($firstChars);
1565 $nonFirstChars = self::NON_FIRST_CHARS;
1566 $nonFirstCharsLength = strlen($nonFirstChars);
1567
1568 while (true) {
1569 $name = '';
1570 $i = $this->variableCount;
1571
1572 if ('' === $name) {
1573 $name .= $firstChars[$i % $firstCharsLength];
1574 $i = (int) ($i / $firstCharsLength);
1575 }
1576
1577 while ($i > 0) {
1578 --$i;
1579 $name .= $nonFirstChars[$i % $nonFirstCharsLength];
1580 $i = (int) ($i / $nonFirstCharsLength);
1581 }
1582
1583 ++$this->variableCount;
1584
1585 // check that the name is not reserved
1586 if (in_array($name, $this->reservedVariables, true)) {
1587 continue;
1588 }
1589
1590 return $name;
1591 }
1592 }
1593
1594 private function getExpressionLanguage()
1595 {
1596 if (null === $this->expressionLanguage) {
1597 if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
1598 throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
1599 }
1600 $providers = array_merge($this->container->getExpressionLanguageProviders(), $this->expressionLanguageProviders);
1601 $this->expressionLanguage = new ExpressionLanguage(null, $providers);
1602
1603 if ($this->container->isTrackingResources()) {
1604 foreach ($providers as $provider) {
1605 $this->container->addObjectResource($provider);
1606 }
1607 }
1608 }
1609
1610 return $this->expressionLanguage;
1611 }
1612
1613 private function exportTargetDirs()
1614 {
1615 return null === $this->targetDirRegex ? '' : <<<EOF
1616
1617 \$dir = __DIR__;
1618 for (\$i = 1; \$i <= {$this->targetDirMaxMatches}; ++\$i) {
1619 \$this->targetDirs[\$i] = \$dir = dirname(\$dir);
1620 }
1621 EOF;
1622
1623 }
1624
1625 private function export($value)
1626 {
1627 if (null !== $this->targetDirRegex && is_string($value) && preg_match($this->targetDirRegex, $value, $matches, PREG_OFFSET_CAPTURE)) {
1628 $prefix = $matches[0][1] ? var_export(substr($value, 0, $matches[0][1]), true).'.' : '';
1629 $suffix = $matches[0][1] + strlen($matches[0][0]);
1630 $suffix = isset($value[$suffix]) ? '.'.var_export(substr($value, $suffix), true) : '';
1631 $dirname = '__DIR__';
1632
1633 if (0 < $offset = 1 + $this->targetDirMaxMatches - count($matches)) {
1634 $dirname = sprintf('$this->targetDirs[%d]', $offset);
1635 }
1636
1637 if ($prefix || $suffix) {
1638 return sprintf('(%s%s%s)', $prefix, $dirname, $suffix);
1639 }
1640
1641 return $dirname;
1642 }
1643
1644 return var_export($value, true);
1645 }
1646 }
1647