PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/symfony/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php

https://github.com/casoetan/ServerGroveLiveChat
PHP | 934 lines | 843 code | 45 blank | 46 comment | 33 complexity | 8c934637fa95742b3eea1de0d0f81e79 MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-3.0, ISC, BSD-3-Clause
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\DependencyInjection\Dumper;
  11. use Symfony\Component\DependencyInjection\Variable;
  12. use Symfony\Component\DependencyInjection\Definition;
  13. use Symfony\Component\DependencyInjection\ContainerBuilder;
  14. use Symfony\Component\DependencyInjection\Container;
  15. use Symfony\Component\DependencyInjection\ContainerInterface;
  16. use Symfony\Component\DependencyInjection\Reference;
  17. use Symfony\Component\DependencyInjection\Parameter;
  18. /**
  19. * PhpDumper dumps a service container as a PHP class.
  20. *
  21. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  22. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  23. */
  24. class PhpDumper extends Dumper
  25. {
  26. /**
  27. * Characters that might appear in the generated variable name as first character
  28. * @var string
  29. */
  30. const FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz';
  31. /**
  32. * Characters that might appear in the generated variable name as any but the first character
  33. * @var string
  34. */
  35. const NON_FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789_';
  36. protected $inlinedDefinitions;
  37. protected $definitionVariables;
  38. protected $referenceVariables;
  39. protected $variableCount;
  40. protected $reservedVariables = array('instance', 'class');
  41. public function __construct(ContainerBuilder $container)
  42. {
  43. parent::__construct($container);
  44. $this->inlinedDefinitions = new \SplObjectStorage;
  45. }
  46. /**
  47. * Dumps the service container as a PHP class.
  48. *
  49. * Available options:
  50. *
  51. * * class: The class name
  52. * * base_class: The base class name
  53. *
  54. * @param array $options An array of options
  55. *
  56. * @return string A PHP class representing of the service container
  57. */
  58. public function dump(array $options = array())
  59. {
  60. $options = array_merge(array(
  61. 'class' => 'ProjectServiceContainer',
  62. 'base_class' => 'Container',
  63. ), $options);
  64. $code = $this->startClass($options['class'], $options['base_class']);
  65. if ($this->container->isFrozen()) {
  66. $code .= $this->addFrozenConstructor();
  67. } else {
  68. $code .= $this->addConstructor();
  69. }
  70. $code .=
  71. $this->addServices().
  72. $this->addDefaultParametersMethod().
  73. $this->addInterfaceInjectors().
  74. $this->endClass()
  75. ;
  76. return $code;
  77. }
  78. protected function addInterfaceInjectors()
  79. {
  80. if ($this->container->isFrozen() || 0 === count($this->container->getInterfaceInjectors())) {
  81. return;
  82. }
  83. $code = <<<EOF
  84. /**
  85. * Applies all known interface injection calls
  86. *
  87. * @param Object \$instance
  88. */
  89. protected function applyInterfaceInjectors(\$instance)
  90. {
  91. EOF;
  92. foreach ($this->container->getInterfaceInjectors() as $injector) {
  93. $code .= sprintf(" if (\$instance instanceof \\%s) {\n", $injector->getClass());
  94. foreach ($injector->getMethodCalls() as $call) {
  95. foreach ($call[1] as $value) {
  96. $arguments[] = $this->dumpValue($value);
  97. }
  98. $code .= $this->wrapServiceConditionals($call[1], sprintf(" \$instance->%s(%s);\n", $call[0], implode(', ', $arguments)));
  99. }
  100. $code .= sprintf(" }\n");
  101. }
  102. $code .= <<<EOF
  103. }
  104. EOF;
  105. return $code;
  106. }
  107. protected function addServiceLocalTempVariables($cId, $definition)
  108. {
  109. static $template = " \$%s = %s;\n";
  110. $localDefinitions = array_merge(
  111. array($definition),
  112. $this->getInlinedDefinitions($definition)
  113. );
  114. $calls = $behavior = array();
  115. foreach ($localDefinitions as $iDefinition) {
  116. $this->getServiceCallsFromArguments($iDefinition->getArguments(), $calls, $behavior);
  117. $this->getServiceCallsFromArguments($iDefinition->getMethodCalls(), $calls, $behavior);
  118. }
  119. $code = '';
  120. foreach ($calls as $id => $callCount) {
  121. if ('service_container' === $id || $id === $cId) {
  122. continue;
  123. }
  124. if ($callCount > 1) {
  125. $name = $this->getNextVariableName();
  126. $this->referenceVariables[$id] = new Variable($name);
  127. if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $behavior[$id]) {
  128. $code .= sprintf($template, $name, $this->getServiceCall($id));
  129. } else {
  130. $code .= sprintf($template, $name, $this->getServiceCall($id, new Reference($id, ContainerInterface::NULL_ON_INVALID_REFERENCE)));
  131. }
  132. }
  133. }
  134. if ('' !== $code) {
  135. $code .= "\n";
  136. }
  137. return $code;
  138. }
  139. protected function addServiceInclude($id, $definition)
  140. {
  141. $template = " require_once %s;\n";
  142. $code = '';
  143. if (null !== $file = $definition->getFile()) {
  144. $code .= sprintf($template, $this->dumpValue($file));
  145. }
  146. foreach ($this->getInlinedDefinitions($definition) as $definition) {
  147. if (null !== $file = $definition->getFile()) {
  148. $code .= sprintf($template, $this->dumpValue($file));
  149. }
  150. }
  151. if ('' !== $code) {
  152. $code .= "\n";
  153. }
  154. return $code;
  155. }
  156. protected function addServiceInlinedDefinitions($id, $definition)
  157. {
  158. $code = '';
  159. $variableMap = $this->definitionVariables;
  160. $nbOccurrences = new \SplObjectStorage();
  161. $processed = new \SplObjectStorage();
  162. $inlinedDefinitions = $this->getInlinedDefinitions($definition);
  163. foreach ($inlinedDefinitions as $definition) {
  164. if (false === $nbOccurrences->contains($definition)) {
  165. $nbOccurrences->offsetSet($definition, 1);
  166. } else {
  167. $i = $nbOccurrences->offsetGet($definition);
  168. $nbOccurrences->offsetSet($definition, $i+1);
  169. }
  170. }
  171. foreach ($inlinedDefinitions as $sDefinition) {
  172. if ($processed->contains($sDefinition)) {
  173. continue;
  174. }
  175. $processed->offsetSet($sDefinition);
  176. $class = $this->dumpValue($sDefinition->getClass());
  177. if ($nbOccurrences->offsetGet($sDefinition) > 1 || count($sDefinition->getMethodCalls()) > 0 || null !== $sDefinition->getConfigurator() || false !== strpos($class, '$')) {
  178. $name = $this->getNextVariableName();
  179. $variableMap->offsetSet($sDefinition, new Variable($name));
  180. // a construct like:
  181. // $a = new ServiceA(ServiceB $b); $b = new ServiceB(ServiceA $a);
  182. // this is an indication for a wrong implementation, you can circumvent this problem
  183. // by setting up your service structure like this:
  184. // $b = new ServiceB();
  185. // $a = new ServiceA(ServiceB $b);
  186. // $b->setServiceA(ServiceA $a);
  187. if ($this->hasReference($id, $sDefinition->getArguments())) {
  188. throw new \RuntimeException('Unresolvable reference detected in service definition for '.$id);
  189. }
  190. $arguments = array();
  191. foreach ($sDefinition->getArguments() as $argument) {
  192. $arguments[] = $this->dumpValue($argument);
  193. }
  194. if (null !== $sDefinition->getFactoryMethod()) {
  195. if (null !== $sDefinition->getFactoryService()) {
  196. $code .= sprintf(" \$%s = %s->%s(%s);\n", $name, $this->getServiceCall($sDefinition->getFactoryService()), $sDefinition->getFactoryMethod(), implode(', ', $arguments));
  197. } else {
  198. $code .= sprintf(" \$%s = call_user_func(array(%s, '%s')%s);\n", $name, $class, $sDefinition->getFactoryMethod(), count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
  199. }
  200. } elseif (false !== strpos($class, '$')) {
  201. $code .= sprintf(" \$class = %s;\n \$%s = new \$class(%s);\n", $class, $name, implode(', ', $arguments));
  202. } else {
  203. $code .= sprintf(" \$%s = new \\%s(%s);\n", $name, substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments));
  204. }
  205. if (!$this->hasReference($id, $sDefinition->getMethodCalls())) {
  206. $code .= $this->addServiceMethodCalls(null, $sDefinition, $name);
  207. $code .= $this->addServiceConfigurator(null, $sDefinition, $name);
  208. }
  209. $code .= "\n";
  210. }
  211. }
  212. return $code;
  213. }
  214. protected function addServiceReturn($id, $definition)
  215. {
  216. if ($this->isSimpleInstance($id, $definition)) {
  217. return " }\n";
  218. }
  219. return "\n return \$instance;\n }\n";
  220. }
  221. protected function addServiceInstance($id, $definition)
  222. {
  223. $class = $this->dumpValue($definition->getClass());
  224. 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)) {
  225. throw new \InvalidArgumentException(sprintf('"%s" is not a valid class name for the "%s" service.', $class, $id));
  226. }
  227. $arguments = array();
  228. foreach ($definition->getArguments() as $value) {
  229. $arguments[] = $this->dumpValue($value);
  230. }
  231. $simple = $this->isSimpleInstance($id, $definition);
  232. $instantiation = '';
  233. if (ContainerInterface::SCOPE_CONTAINER === $definition->getScope()) {
  234. $instantiation = "\$this->services['$id'] = ".($simple ? '' : '$instance');
  235. } else if (ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) {
  236. $instantiation = "\$this->services['$id'] = \$this->scopedServices['$scope']['$id'] = ".($simple ? '' : '$instance');
  237. } elseif (!$simple) {
  238. $instantiation = '$instance';
  239. }
  240. $return = '';
  241. if ($simple) {
  242. $return = 'return ';
  243. } else {
  244. $instantiation .= ' = ';
  245. }
  246. if (null !== $definition->getFactoryMethod()) {
  247. if (null !== $definition->getFactoryService()) {
  248. $code = sprintf(" $return{$instantiation}%s->%s(%s);\n", $this->getServiceCall($definition->getFactoryService()), $definition->getFactoryMethod(), implode(', ', $arguments));
  249. } else {
  250. $code = sprintf(" $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $class, $definition->getFactoryMethod(), $arguments ? ', '.implode(', ', $arguments) : '');
  251. }
  252. } elseif (false !== strpos($class, '$')) {
  253. $code = sprintf(" \$class = %s;\n $return{$instantiation}new \$class(%s);\n", $class, implode(', ', $arguments));
  254. } else {
  255. $code = sprintf(" $return{$instantiation}new \\%s(%s);\n", substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments));
  256. }
  257. if (!$simple) {
  258. $code .= "\n";
  259. }
  260. return $code;
  261. }
  262. protected function isSimpleInstance($id, $definition)
  263. {
  264. foreach (array_merge(array($definition), $this->getInlinedDefinitions($definition)) as $sDefinition) {
  265. if ($definition !== $sDefinition && !$this->hasReference($id, $sDefinition->getMethodCalls())) {
  266. continue;
  267. }
  268. if ($sDefinition->getMethodCalls() || $sDefinition->getConfigurator()) {
  269. return false;
  270. }
  271. }
  272. return true;
  273. }
  274. protected function addServiceMethodCalls($id, $definition, $variableName = 'instance')
  275. {
  276. $calls = '';
  277. foreach ($definition->getMethodCalls() as $call) {
  278. $arguments = array();
  279. foreach ($call[1] as $value) {
  280. $arguments[] = $this->dumpValue($value);
  281. }
  282. $calls .= $this->wrapServiceConditionals($call[1], sprintf(" \$%s->%s(%s);\n", $variableName, $call[0], implode(', ', $arguments)));
  283. }
  284. if (!$this->container->isFrozen() && count($this->container->getInterfaceInjectors()) > 0) {
  285. $calls = sprintf("\n \$this->applyInterfaceInjectors(\$%s);\n", $variableName);
  286. }
  287. return $calls;
  288. }
  289. protected function addServiceInlinedDefinitionsSetup($id, $definition)
  290. {
  291. $this->referenceVariables[$id] = new Variable('instance');
  292. $code = '';
  293. $processed = new \SplObjectStorage();
  294. foreach ($this->getInlinedDefinitions($definition) as $iDefinition) {
  295. if ($processed->contains($iDefinition)) {
  296. continue;
  297. }
  298. $processed->offsetSet($iDefinition);
  299. if (!$this->hasReference($id, $iDefinition->getMethodCalls())) {
  300. continue;
  301. }
  302. if ($iDefinition->getMethodCalls()) {
  303. $code .= $this->addServiceMethodCalls(null, $iDefinition, (string) $this->definitionVariables->offsetGet($iDefinition));
  304. }
  305. if ($iDefinition->getConfigurator()) {
  306. $code .= $this->addServiceConfigurator(null, $iDefinition, (string) $this->definitionVariables->offsetGet($iDefinition));
  307. }
  308. }
  309. if ('' !== $code) {
  310. $code .= "\n";
  311. }
  312. return $code;
  313. }
  314. protected function addServiceConfigurator($id, $definition, $variableName = 'instance')
  315. {
  316. if (!$callable = $definition->getConfigurator()) {
  317. return '';
  318. }
  319. if (is_array($callable)) {
  320. if (is_object($callable[0]) && $callable[0] instanceof Reference) {
  321. return sprintf(" %s->%s(\$%s);\n", $this->getServiceCall((string) $callable[0]), $callable[1], $variableName);
  322. } else {
  323. return sprintf(" call_user_func(array(%s, '%s'), \$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
  324. }
  325. } else {
  326. return sprintf(" %s(\$%s);\n", $callable, $variableName);
  327. }
  328. }
  329. protected function addService($id, $definition)
  330. {
  331. $name = Container::camelize($id);
  332. $this->definitionVariables = new \SplObjectStorage();
  333. $this->referenceVariables = array();
  334. $this->variableCount = 0;
  335. $return = '';
  336. if ($definition->isSynthetic()) {
  337. $return = sprintf('@throws \RuntimeException always since this service is expected to be injected dynamically');
  338. } else if ($class = $definition->getClass()) {
  339. $return = sprintf("@return %s A %s instance.", 0 === strpos($class, '%') ? 'Object' : $class, $class);
  340. } elseif ($definition->getFactoryService()) {
  341. $return = sprintf('@return Object An instance returned by %s::%s().', $definition->getFactoryService(), $definition->getFactoryMethod());
  342. }
  343. $doc = '';
  344. if (ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope()) {
  345. $doc .= <<<EOF
  346. *
  347. * This service is shared.
  348. * This method always returns the same instance of the service.
  349. EOF;
  350. }
  351. if (!$definition->isPublic()) {
  352. $doc .= <<<EOF
  353. *
  354. * This service is private.
  355. * If you want to be able to request this service from the container directly,
  356. * make it public, otherwise you might end up with broken code.
  357. EOF;
  358. }
  359. $code = <<<EOF
  360. /**
  361. * Gets the '$id' service.$doc
  362. *
  363. * $return
  364. */
  365. protected function get{$name}Service()
  366. {
  367. EOF;
  368. $scope = $definition->getScope();
  369. if (ContainerInterface::SCOPE_CONTAINER !== $scope && ContainerInterface::SCOPE_PROTOTYPE !== $scope) {
  370. $code .= <<<EOF
  371. if (!isset(\$this->scopedServices['$scope'])) {
  372. throw new \RuntimeException('You cannot create a service ("$id") of an inactive scope ("$scope").');
  373. }
  374. EOF;
  375. }
  376. if ($definition->isSynthetic()) {
  377. $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);
  378. } else {
  379. $code .=
  380. $this->addServiceInclude($id, $definition).
  381. $this->addServiceLocalTempVariables($id, $definition).
  382. $this->addServiceInlinedDefinitions($id, $definition).
  383. $this->addServiceInstance($id, $definition).
  384. $this->addServiceInlinedDefinitionsSetup($id, $definition).
  385. $this->addServiceMethodCalls($id, $definition).
  386. $this->addServiceConfigurator($id, $definition).
  387. $this->addServiceReturn($id, $definition)
  388. ;
  389. }
  390. $this->definitionVariables = null;
  391. $this->referenceVariables = null;
  392. return $code;
  393. }
  394. protected function addServiceAlias($alias, $id)
  395. {
  396. $name = Container::camelize($alias);
  397. $type = 'Object';
  398. if ($this->container->hasDefinition($id)) {
  399. $class = $this->container->getDefinition($id)->getClass();
  400. $type = 0 === strpos($class, '%') ? 'Object' : $class;
  401. }
  402. return <<<EOF
  403. /**
  404. * Gets the $alias service alias.
  405. *
  406. * @return $type An instance of the $id service
  407. */
  408. protected function get{$name}Service()
  409. {
  410. return {$this->getServiceCall($id)};
  411. }
  412. EOF;
  413. }
  414. protected function addServices()
  415. {
  416. $publicServices = $privateServices = $aliasServices = '';
  417. $definitions = $this->container->getDefinitions();
  418. ksort($definitions);
  419. foreach ($definitions as $id => $definition) {
  420. if ($definition->isPublic()) {
  421. $publicServices .= $this->addService($id, $definition);
  422. } else {
  423. $privateServices .= $this->addService($id, $definition);
  424. }
  425. }
  426. $aliases = $this->container->getAliases();
  427. ksort($aliases);
  428. foreach ($aliases as $alias => $id) {
  429. $aliasServices .= $this->addServiceAlias($alias, $id);
  430. }
  431. return $publicServices.$aliasServices.$privateServices;
  432. }
  433. protected function startClass($class, $baseClass)
  434. {
  435. $bagClass = $this->container->isFrozen() ? '' : 'use Symfony\Component\DependencyInjection\ParameterBag\\ParameterBag;';
  436. return <<<EOF
  437. <?php
  438. use Symfony\Component\DependencyInjection\ContainerInterface;
  439. use Symfony\Component\DependencyInjection\Container;
  440. use Symfony\Component\DependencyInjection\Reference;
  441. use Symfony\Component\DependencyInjection\Parameter;
  442. $bagClass
  443. /**
  444. * $class
  445. *
  446. * This class has been auto-generated
  447. * by the Symfony Dependency Injection Component.
  448. */
  449. class $class extends $baseClass
  450. {
  451. EOF;
  452. }
  453. protected function addConstructor()
  454. {
  455. $code = <<<EOF
  456. /**
  457. * Constructor.
  458. */
  459. public function __construct()
  460. {
  461. parent::__construct(new ParameterBag(\$this->getDefaultParameters()));
  462. EOF;
  463. if (count($scopes = $this->container->getScopes()) > 0) {
  464. $code .= "\n";
  465. $code .= " \$this->scopes = ".$this->dumpValue($scopes).";\n";
  466. $code .= " \$this->scopeChildren = ".$this->dumpValue($this->container->getScopeChildren()).";\n";
  467. }
  468. $code .= <<<EOF
  469. }
  470. EOF;
  471. return $code;
  472. }
  473. protected function addFrozenConstructor()
  474. {
  475. $code = <<<EOF
  476. /**
  477. * Constructor.
  478. */
  479. public function __construct()
  480. {
  481. \$this->parameters = \$this->getDefaultParameters();
  482. \$this->services =
  483. \$this->scopedServices =
  484. \$this->scopeStacks = array();
  485. \$this->set('service_container', \$this);
  486. EOF;
  487. $code .= "\n";
  488. if (count($scopes = $this->container->getScopes()) > 0) {
  489. $code .= " \$this->scopes = ".$this->dumpValue($scopes).";\n";
  490. $code .= " \$this->scopeChildren = ".$this->dumpValue($this->container->getScopeChildren()).";\n";
  491. } else {
  492. $code .= " \$this->scopes = array();\n";
  493. $code .= " \$this->scopeChildren = array();\n";
  494. }
  495. $code .= <<<EOF
  496. }
  497. EOF;
  498. return $code;
  499. }
  500. protected function addDefaultParametersMethod()
  501. {
  502. if (!$this->container->getParameterBag()->all()) {
  503. return '';
  504. }
  505. $parameters = $this->exportParameters($this->container->getParameterBag()->all());
  506. $code = '';
  507. if ($this->container->isFrozen()) {
  508. $code .= <<<EOF
  509. /**
  510. * {@inheritdoc}
  511. */
  512. public function getParameter(\$name)
  513. {
  514. \$name = strtolower(\$name);
  515. if (!array_key_exists(\$name, \$this->parameters)) {
  516. throw new \InvalidArgumentException(sprintf('The parameter "%s" must be defined.', \$name));
  517. }
  518. return \$this->parameters[\$name];
  519. }
  520. /**
  521. * {@inheritdoc}
  522. */
  523. public function hasParameter(\$name)
  524. {
  525. return array_key_exists(strtolower(\$name), \$this->parameters);
  526. }
  527. /**
  528. * {@inheritdoc}
  529. */
  530. public function setParameter(\$name, \$value)
  531. {
  532. throw new \LogicException('Impossible to call set() on a frozen ParameterBag.');
  533. }
  534. EOF;
  535. }
  536. $code .= <<<EOF
  537. /**
  538. * Gets the default parameters.
  539. *
  540. * @return array An array of the default parameters
  541. */
  542. protected function getDefaultParameters()
  543. {
  544. return $parameters;
  545. }
  546. EOF;
  547. return $code;
  548. }
  549. protected function exportParameters($parameters, $indent = 12)
  550. {
  551. $php = array();
  552. foreach ($parameters as $key => $value) {
  553. if (is_array($value)) {
  554. $value = $this->exportParameters($value, $indent + 4);
  555. } elseif ($value instanceof Variable) {
  556. throw new \InvalidArgumentException(sprintf('you cannot dump a container with parameters that contain variable references. Variable "%s" found.', $value));
  557. } elseif ($value instanceof Definition) {
  558. throw new \InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain service definitions. Definition for "%s" found.', $value->getClass()));
  559. } elseif ($value instanceof Reference) {
  560. throw new \InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain references to other services (reference to service %s found).', $value));
  561. } else {
  562. $value = var_export($value, true);
  563. }
  564. $php[] = sprintf('%s%s => %s,', str_repeat(' ', $indent), var_export($key, true), $value);
  565. }
  566. return sprintf("array(\n%s\n%s)", implode("\n", $php), str_repeat(' ', $indent - 4));
  567. }
  568. protected function endClass()
  569. {
  570. return <<<EOF
  571. }
  572. EOF;
  573. }
  574. protected function wrapServiceConditionals($value, $code)
  575. {
  576. if (!$services = ContainerBuilder::getServiceConditionals($value)) {
  577. return $code;
  578. }
  579. $conditions = array();
  580. foreach ($services as $service) {
  581. $conditions[] = sprintf("\$this->has('%s')", $service);
  582. }
  583. // re-indent the wrapped code
  584. $code = implode("\n", array_map(function ($line) { return $line ? ' '.$line : $line; }, explode("\n", $code)));
  585. return sprintf(" if (%s) {\n%s }\n", implode(' && ', $conditions), $code);
  586. }
  587. protected function getServiceCallsFromArguments(array $arguments, array &$calls, array &$behavior)
  588. {
  589. foreach ($arguments as $argument) {
  590. if (is_array($argument)) {
  591. $this->getServiceCallsFromArguments($argument, $calls, $behavior);
  592. } else if ($argument instanceof Reference) {
  593. $id = (string) $argument;
  594. if (!isset($calls[$id])) {
  595. $calls[$id] = 0;
  596. }
  597. if (!isset($behavior[$id])) {
  598. $behavior[$id] = $argument->getInvalidBehavior();
  599. } else if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $behavior[$id]) {
  600. $behavior[$id] = $argument->getInvalidBehavior();
  601. }
  602. $calls[$id] += 1;
  603. }
  604. }
  605. }
  606. protected function getInlinedDefinitions(Definition $definition)
  607. {
  608. if (false === $this->inlinedDefinitions->contains($definition)) {
  609. $definitions = $this->getDefinitionsFromArguments($definition->getArguments());
  610. foreach ($definition->getMethodCalls() as $arguments) {
  611. $definitions = array_merge($definitions, $this->getDefinitionsFromArguments($arguments));
  612. }
  613. $this->inlinedDefinitions->offsetSet($definition, $definitions);
  614. return $definitions;
  615. }
  616. return $this->inlinedDefinitions->offsetGet($definition);
  617. }
  618. protected function getDefinitionsFromArguments(array $arguments)
  619. {
  620. $definitions = array();
  621. foreach ($arguments as $argument) {
  622. if (is_array($argument)) {
  623. $definitions = array_merge($definitions, $this->getDefinitionsFromArguments($argument));
  624. } else if ($argument instanceof Definition) {
  625. $definitions = array_merge(
  626. $definitions,
  627. $this->getInlinedDefinitions($argument),
  628. array($argument)
  629. );
  630. }
  631. }
  632. return $definitions;
  633. }
  634. protected function hasReference($id, array $arguments)
  635. {
  636. foreach ($arguments as $argument) {
  637. if (is_array($argument)) {
  638. if ($this->hasReference($id, $argument)) {
  639. return true;
  640. }
  641. } else if ($argument instanceof Reference) {
  642. if ($id === (string) $argument) {
  643. return true;
  644. }
  645. }
  646. }
  647. return false;
  648. }
  649. protected function dumpValue($value, $interpolate = true)
  650. {
  651. if (is_array($value)) {
  652. $code = array();
  653. foreach ($value as $k => $v) {
  654. $code[] = sprintf('%s => %s', $this->dumpValue($k, $interpolate), $this->dumpValue($v, $interpolate));
  655. }
  656. return sprintf('array(%s)', implode(', ', $code));
  657. } elseif (is_object($value) && $value instanceof Definition) {
  658. if (null !== $this->definitionVariables && $this->definitionVariables->contains($value)) {
  659. return $this->dumpValue($this->definitionVariables->offsetGet($value), $interpolate);
  660. }
  661. if (count($value->getMethodCalls()) > 0) {
  662. throw new \RuntimeException('Cannot dump definitions which have method calls.');
  663. }
  664. if (null !== $value->getConfigurator()) {
  665. throw new \RuntimeException('Cannot dump definitions which have a configurator.');
  666. }
  667. $arguments = array();
  668. foreach ($value->getArguments() as $argument) {
  669. $arguments[] = $this->dumpValue($argument);
  670. }
  671. $class = $this->dumpValue($value->getClass());
  672. if (false !== strpos($class, '$')) {
  673. throw new \RuntimeException('Cannot dump definitions which have a variable class name.');
  674. }
  675. if (null !== $value->getFactoryMethod()) {
  676. if (null !== $value->getFactoryService()) {
  677. return sprintf("%s->%s(%s)", $this->getServiceCall($value->getFactoryService()), $value->getFactoryMethod(), implode(', ', $arguments));
  678. } else {
  679. return sprintf("call_user_func(array(%s, '%s')%s)", $class, $value->getFactoryMethod(), count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
  680. }
  681. }
  682. return sprintf("new \\%s(%s)", substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments));
  683. } elseif (is_object($value) && $value instanceof Variable) {
  684. return '$'.$value;
  685. } elseif (is_object($value) && $value instanceof Reference) {
  686. if (null !== $this->referenceVariables && isset($this->referenceVariables[$id = (string) $value])) {
  687. return $this->dumpValue($this->referenceVariables[$id], $interpolate);
  688. }
  689. return $this->getServiceCall((string) $value, $value);
  690. } elseif (is_object($value) && $value instanceof Parameter) {
  691. return $this->dumpParameter($value);
  692. } elseif (true === $interpolate && is_string($value)) {
  693. if (preg_match('/^%([^%]+)%$/', $value, $match)) {
  694. // we do this to deal with non string values (Boolean, integer, ...)
  695. // the preg_replace_callback converts them to strings
  696. return $this->dumpParameter(strtolower($match[1]));
  697. } else {
  698. $that = $this;
  699. $replaceParameters = function ($match) use ($that)
  700. {
  701. return sprintf("'.".$that->dumpParameter(strtolower($match[2])).".'");
  702. };
  703. $code = str_replace('%%', '%', preg_replace_callback('/(?<!%)(%)([^%]+)\1/', $replaceParameters, var_export($value, true)));
  704. // optimize string
  705. $code = preg_replace(array("/^''\./", "/\.''$/", "/'\.'/", "/\.''\./"), array('', '', '', '.'), $code);
  706. return $code;
  707. }
  708. } elseif (is_object($value) || is_resource($value)) {
  709. throw new \RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
  710. } else {
  711. return var_export($value, true);
  712. }
  713. }
  714. public function dumpParameter($name)
  715. {
  716. if ($this->container->isFrozen() && $this->container->hasParameter($name)) {
  717. return $this->dumpValue($this->container->getParameter($name), false);
  718. }
  719. return sprintf("\$this->getParameter('%s')", strtolower($name));
  720. }
  721. protected function getServiceCall($id, Reference $reference = null)
  722. {
  723. if ('service_container' === $id) {
  724. return '$this';
  725. }
  726. if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
  727. return sprintf('$this->get(\'%s\', ContainerInterface::NULL_ON_INVALID_REFERENCE)', $id);
  728. } else {
  729. if ($this->container->hasAlias($id)) {
  730. $id = (string) $this->container->getAlias($id);
  731. }
  732. return sprintf('$this->get(\'%s\')', $id);
  733. }
  734. }
  735. /**
  736. * Returns the next name to use
  737. *
  738. * @return string
  739. */
  740. protected function getNextVariableName()
  741. {
  742. $firstChars = self::FIRST_CHARS;
  743. $firstCharsLength = strlen($firstChars);
  744. $nonFirstChars = self::NON_FIRST_CHARS;
  745. $nonFirstCharsLength = strlen($nonFirstChars);
  746. while (true)
  747. {
  748. $name = '';
  749. $i = $this->variableCount;
  750. if ('' === $name)
  751. {
  752. $name .= $firstChars[$i%$firstCharsLength];
  753. $i = intval($i/$firstCharsLength);
  754. }
  755. while ($i > 0)
  756. {
  757. $i -= 1;
  758. $name .= $nonFirstChars[$i%$nonFirstCharsLength];
  759. $i = intval($i/$nonFirstCharsLength);
  760. }
  761. $this->variableCount += 1;
  762. // check that the name is not reserved
  763. if (in_array($name, $this->reservedVariables, true)) {
  764. continue;
  765. }
  766. return $name;
  767. }
  768. }
  769. }