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 |
ContainerBuilder.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;
0013
0014 use Symfony\Component\DependencyInjection\Compiler\Compiler;
0015 use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
0016 use Symfony\Component\DependencyInjection\Compiler\PassConfig;
0017 use Symfony\Component\DependencyInjection\Exception\BadMethodCallException;
0018 use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
0019 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
0020 use Symfony\Component\DependencyInjection\Exception\LogicException;
0021 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
0022 use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
0023 use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
0024 use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
0025 use Symfony\Component\Config\Resource\FileResource;
0026 use Symfony\Component\Config\Resource\ResourceInterface;
0027 use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;
0028 use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator;
0029 use Symfony\Component\ExpressionLanguage\Expression;
0030 use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
0031
0032 /**
0033 * ContainerBuilder is a DI container that provides an API to easily describe services.
0034 *
0035 * @author Fabien Potencier <fabien@symfony.com>
0036 */
0037 class ContainerBuilder extends Container implements TaggedContainerInterface
0038 {
0039 /**
0040 * @var ExtensionInterface[]
0041 */
0042 private $extensions = array();
0043
0044 /**
0045 * @var ExtensionInterface[]
0046 */
0047 private $extensionsByNs = array();
0048
0049 /**
0050 * @var Definition[]
0051 */
0052 private $definitions = array();
0053
0054 /**
0055 * @var Definition[]
0056 */
0057 private $obsoleteDefinitions = array();
0058
0059 /**
0060 * @var Alias[]
0061 */
0062 private $aliasDefinitions = array();
0063
0064 /**
0065 * @var ResourceInterface[]
0066 */
0067 private $resources = array();
0068
0069 private $extensionConfigs = array();
0070
0071 /**
0072 * @var Compiler
0073 */
0074 private $compiler;
0075
0076 private $trackResources = true;
0077
0078 /**
0079 * @var InstantiatorInterface|null
0080 */
0081 private $proxyInstantiator;
0082
0083 /**
0084 * @var ExpressionLanguage|null
0085 */
0086 private $expressionLanguage;
0087
0088 /**
0089 * @var ExpressionFunctionProviderInterface[]
0090 */
0091 private $expressionLanguageProviders = array();
0092
0093 /**
0094 * @var string[] with tag names used by findTaggedServiceIds
0095 */
0096 private $usedTags = array();
0097
0098 /**
0099 * Sets the track resources flag.
0100 *
0101 * If you are not using the loaders and therefore don't want
0102 * to depend on the Config component, set this flag to false.
0103 *
0104 * @param bool $track true if you want to track resources, false otherwise
0105 */
0106 public function setResourceTracking($track)
0107 {
0108 $this->trackResources = (bool) $track;
0109 }
0110
0111 /**
0112 * Checks if resources are tracked.
0113 *
0114 * @return bool true if resources are tracked, false otherwise
0115 */
0116 public function isTrackingResources()
0117 {
0118 return $this->trackResources;
0119 }
0120
0121 /**
0122 * Sets the instantiator to be used when fetching proxies.
0123 *
0124 * @param InstantiatorInterface $proxyInstantiator
0125 */
0126 public function setProxyInstantiator(InstantiatorInterface $proxyInstantiator)
0127 {
0128 $this->proxyInstantiator = $proxyInstantiator;
0129 }
0130
0131 /**
0132 * Registers an extension.
0133 *
0134 * @param ExtensionInterface $extension An extension instance
0135 */
0136 public function registerExtension(ExtensionInterface $extension)
0137 {
0138 $this->extensions[$extension->getAlias()] = $extension;
0139
0140 if (false !== $extension->getNamespace()) {
0141 $this->extensionsByNs[$extension->getNamespace()] = $extension;
0142 }
0143 }
0144
0145 /**
0146 * Returns an extension by alias or namespace.
0147 *
0148 * @param string $name An alias or a namespace
0149 *
0150 * @return ExtensionInterface An extension instance
0151 *
0152 * @throws LogicException if the extension is not registered
0153 */
0154 public function getExtension($name)
0155 {
0156 if (isset($this->extensions[$name])) {
0157 return $this->extensions[$name];
0158 }
0159
0160 if (isset($this->extensionsByNs[$name])) {
0161 return $this->extensionsByNs[$name];
0162 }
0163
0164 throw new LogicException(sprintf('Container extension "%s" is not registered', $name));
0165 }
0166
0167 /**
0168 * Returns all registered extensions.
0169 *
0170 * @return ExtensionInterface[] An array of ExtensionInterface
0171 */
0172 public function getExtensions()
0173 {
0174 return $this->extensions;
0175 }
0176
0177 /**
0178 * Checks if we have an extension.
0179 *
0180 * @param string $name The name of the extension
0181 *
0182 * @return bool If the extension exists
0183 */
0184 public function hasExtension($name)
0185 {
0186 return isset($this->extensions[$name]) || isset($this->extensionsByNs[$name]);
0187 }
0188
0189 /**
0190 * Returns an array of resources loaded to build this configuration.
0191 *
0192 * @return ResourceInterface[] An array of resources
0193 */
0194 public function getResources()
0195 {
0196 return array_unique($this->resources);
0197 }
0198
0199 /**
0200 * Adds a resource for this configuration.
0201 *
0202 * @param ResourceInterface $resource A resource instance
0203 *
0204 * @return ContainerBuilder The current instance
0205 */
0206 public function addResource(ResourceInterface $resource)
0207 {
0208 if (!$this->trackResources) {
0209 return $this;
0210 }
0211
0212 $this->resources[] = $resource;
0213
0214 return $this;
0215 }
0216
0217 /**
0218 * Sets the resources for this configuration.
0219 *
0220 * @param ResourceInterface[] $resources An array of resources
0221 *
0222 * @return ContainerBuilder The current instance
0223 */
0224 public function setResources(array $resources)
0225 {
0226 if (!$this->trackResources) {
0227 return $this;
0228 }
0229
0230 $this->resources = $resources;
0231
0232 return $this;
0233 }
0234
0235 /**
0236 * Adds the object class hierarchy as resources.
0237 *
0238 * @param object $object An object instance
0239 *
0240 * @return ContainerBuilder The current instance
0241 */
0242 public function addObjectResource($object)
0243 {
0244 if ($this->trackResources) {
0245 $this->addClassResource(new \ReflectionClass($object));
0246 }
0247
0248 return $this;
0249 }
0250
0251 /**
0252 * Adds the given class hierarchy as resources.
0253 *
0254 * @param \ReflectionClass $class
0255 *
0256 * @return ContainerBuilder The current instance
0257 */
0258 public function addClassResource(\ReflectionClass $class)
0259 {
0260 if (!$this->trackResources) {
0261 return $this;
0262 }
0263
0264 do {
0265 if (is_file($class->getFileName())) {
0266 $this->addResource(new FileResource($class->getFileName()));
0267 }
0268 } while ($class = $class->getParentClass());
0269
0270 return $this;
0271 }
0272
0273 /**
0274 * Loads the configuration for an extension.
0275 *
0276 * @param string $extension The extension alias or namespace
0277 * @param array $values An array of values that customizes the extension
0278 *
0279 * @return ContainerBuilder The current instance
0280 *
0281 * @throws BadMethodCallException When this ContainerBuilder is frozen
0282 * @throws \LogicException if the container is frozen
0283 */
0284 public function loadFromExtension($extension, array $values = array())
0285 {
0286 if ($this->isFrozen()) {
0287 throw new BadMethodCallException('Cannot load from an extension on a frozen container.');
0288 }
0289
0290 $namespace = $this->getExtension($extension)->getAlias();
0291
0292 $this->extensionConfigs[$namespace][] = $values;
0293
0294 return $this;
0295 }
0296
0297 /**
0298 * Adds a compiler pass.
0299 *
0300 * @param CompilerPassInterface $pass A compiler pass
0301 * @param string $type The type of compiler pass
0302 *
0303 * @return ContainerBuilder The current instance
0304 */
0305 public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION)
0306 {
0307 $this->getCompiler()->addPass($pass, $type);
0308
0309 $this->addObjectResource($pass);
0310
0311 return $this;
0312 }
0313
0314 /**
0315 * Returns the compiler pass config which can then be modified.
0316 *
0317 * @return PassConfig The compiler pass config
0318 */
0319 public function getCompilerPassConfig()
0320 {
0321 return $this->getCompiler()->getPassConfig();
0322 }
0323
0324 /**
0325 * Returns the compiler.
0326 *
0327 * @return Compiler The compiler
0328 */
0329 public function getCompiler()
0330 {
0331 if (null === $this->compiler) {
0332 $this->compiler = new Compiler();
0333 }
0334
0335 return $this->compiler;
0336 }
0337
0338 /**
0339 * Returns all Scopes.
0340 *
0341 * @return array An array of scopes
0342 *
0343 * @deprecated since version 2.8, to be removed in 3.0.
0344 */
0345 public function getScopes($triggerDeprecationError = true)
0346 {
0347 if ($triggerDeprecationError) {
0348 @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
0349 }
0350
0351 return $this->scopes;
0352 }
0353
0354 /**
0355 * Returns all Scope children.
0356 *
0357 * @return array An array of scope children
0358 *
0359 * @deprecated since version 2.8, to be removed in 3.0.
0360 */
0361 public function getScopeChildren($triggerDeprecationError = true)
0362 {
0363 if ($triggerDeprecationError) {
0364 @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
0365 }
0366
0367 return $this->scopeChildren;
0368 }
0369
0370 /**
0371 * Sets a service.
0372 *
0373 * Note: The $scope parameter is deprecated since version 2.8 and will be removed in 3.0.
0374 *
0375 * @param string $id The service identifier
0376 * @param object $service The service instance
0377 * @param string $scope The scope
0378 *
0379 * @throws BadMethodCallException When this ContainerBuilder is frozen
0380 */
0381 public function set($id, $service, $scope = self::SCOPE_CONTAINER)
0382 {
0383 $id = strtolower($id);
0384 $set = isset($this->definitions[$id]);
0385
0386 if ($this->isFrozen() && ($set || isset($this->obsoleteDefinitions[$id])) && !$this->{$set ? 'definitions' : 'obsoleteDefinitions'}[$id]->isSynthetic()) {
0387 // setting a synthetic service on a frozen container is alright
0388 throw new BadMethodCallException(sprintf('Setting service "%s" on a frozen container is not allowed.', $id));
0389 }
0390
0391 if ($set) {
0392 $this->obsoleteDefinitions[$id] = $this->definitions[$id];
0393 }
0394
0395 unset($this->definitions[$id], $this->aliasDefinitions[$id]);
0396
0397 parent::set($id, $service, $scope);
0398
0399 if (isset($this->obsoleteDefinitions[$id]) && $this->obsoleteDefinitions[$id]->isSynchronized(false)) {
0400 $this->synchronize($id);
0401 }
0402 }
0403
0404 /**
0405 * Removes a service definition.
0406 *
0407 * @param string $id The service identifier
0408 */
0409 public function removeDefinition($id)
0410 {
0411 unset($this->definitions[strtolower($id)]);
0412 }
0413
0414 /**
0415 * Returns true if the given service is defined.
0416 *
0417 * @param string $id The service identifier
0418 *
0419 * @return bool true if the service is defined, false otherwise
0420 */
0421 public function has($id)
0422 {
0423 $id = strtolower($id);
0424
0425 return isset($this->definitions[$id]) || isset($this->aliasDefinitions[$id]) || parent::has($id);
0426 }
0427
0428 /**
0429 * Gets a service.
0430 *
0431 * @param string $id The service identifier
0432 * @param int $invalidBehavior The behavior when the service does not exist
0433 *
0434 * @return object The associated service
0435 *
0436 * @throws InvalidArgumentException when no definitions are available
0437 * @throws ServiceCircularReferenceException When a circular reference is detected
0438 * @throws ServiceNotFoundException When the service is not defined
0439 * @throws \Exception
0440 *
0441 * @see Reference
0442 */
0443 public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
0444 {
0445 $id = strtolower($id);
0446
0447 if ($service = parent::get($id, ContainerInterface::NULL_ON_INVALID_REFERENCE)) {
0448 return $service;
0449 }
0450
0451 if (!array_key_exists($id, $this->definitions) && isset($this->aliasDefinitions[$id])) {
0452 return $this->get($this->aliasDefinitions[$id]);
0453 }
0454
0455 try {
0456 $definition = $this->getDefinition($id);
0457 } catch (ServiceNotFoundException $e) {
0458 if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
0459 return;
0460 }
0461
0462 throw $e;
0463 }
0464
0465 $this->loading[$id] = true;
0466
0467 try {
0468 $service = $this->createService($definition, $id);
0469 } catch (\Exception $e) {
0470 unset($this->loading[$id]);
0471
0472 if ($e instanceof InactiveScopeException && self::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
0473 return;
0474 }
0475
0476 throw $e;
0477 } catch (\Throwable $e) {
0478 unset($this->loading[$id]);
0479
0480 throw $e;
0481 }
0482
0483 unset($this->loading[$id]);
0484
0485 return $service;
0486 }
0487
0488 /**
0489 * Merges a ContainerBuilder with the current ContainerBuilder configuration.
0490 *
0491 * Service definitions overrides the current defined ones.
0492 *
0493 * But for parameters, they are overridden by the current ones. It allows
0494 * the parameters passed to the container constructor to have precedence
0495 * over the loaded ones.
0496 *
0497 * $container = new ContainerBuilder(array('foo' => 'bar'));
0498 * $loader = new LoaderXXX($container);
0499 * $loader->load('resource_name');
0500 * $container->register('foo', new stdClass());
0501 *
0502 * In the above example, even if the loaded resource defines a foo
0503 * parameter, the value will still be 'bar' as defined in the ContainerBuilder
0504 * constructor.
0505 *
0506 * @param ContainerBuilder $container The ContainerBuilder instance to merge
0507 *
0508 * @throws BadMethodCallException When this ContainerBuilder is frozen
0509 */
0510 public function merge(ContainerBuilder $container)
0511 {
0512 if ($this->isFrozen()) {
0513 throw new BadMethodCallException('Cannot merge on a frozen container.');
0514 }
0515
0516 $this->addDefinitions($container->getDefinitions());
0517 $this->addAliases($container->getAliases());
0518 $this->getParameterBag()->add($container->getParameterBag()->all());
0519
0520 if ($this->trackResources) {
0521 foreach ($container->getResources() as $resource) {
0522 $this->addResource($resource);
0523 }
0524 }
0525
0526 foreach ($this->extensions as $name => $extension) {
0527 if (!isset($this->extensionConfigs[$name])) {
0528 $this->extensionConfigs[$name] = array();
0529 }
0530
0531 $this->extensionConfigs[$name] = array_merge($this->extensionConfigs[$name], $container->getExtensionConfig($name));
0532 }
0533 }
0534
0535 /**
0536 * Returns the configuration array for the given extension.
0537 *
0538 * @param string $name The name of the extension
0539 *
0540 * @return array An array of configuration
0541 */
0542 public function getExtensionConfig($name)
0543 {
0544 if (!isset($this->extensionConfigs[$name])) {
0545 $this->extensionConfigs[$name] = array();
0546 }
0547
0548 return $this->extensionConfigs[$name];
0549 }
0550
0551 /**
0552 * Prepends a config array to the configs of the given extension.
0553 *
0554 * @param string $name The name of the extension
0555 * @param array $config The config to set
0556 */
0557 public function prependExtensionConfig($name, array $config)
0558 {
0559 if (!isset($this->extensionConfigs[$name])) {
0560 $this->extensionConfigs[$name] = array();
0561 }
0562
0563 array_unshift($this->extensionConfigs[$name], $config);
0564 }
0565
0566 /**
0567 * Compiles the container.
0568 *
0569 * This method passes the container to compiler
0570 * passes whose job is to manipulate and optimize
0571 * the container.
0572 *
0573 * The main compiler passes roughly do four things:
0574 *
0575 * * The extension configurations are merged;
0576 * * Parameter values are resolved;
0577 * * The parameter bag is frozen;
0578 * * Extension loading is disabled.
0579 */
0580 public function compile()
0581 {
0582 $compiler = $this->getCompiler();
0583
0584 if ($this->trackResources) {
0585 foreach ($compiler->getPassConfig()->getPasses() as $pass) {
0586 $this->addObjectResource($pass);
0587 }
0588 }
0589
0590 $compiler->compile($this);
0591
0592 if ($this->trackResources) {
0593 foreach ($this->definitions as $definition) {
0594 if ($definition->isLazy() && ($class = $definition->getClass()) && class_exists($class)) {
0595 $this->addClassResource(new \ReflectionClass($class));
0596 }
0597 }
0598 }
0599
0600 $this->extensionConfigs = array();
0601
0602 parent::compile();
0603 }
0604
0605 /**
0606 * Gets all service ids.
0607 *
0608 * @return array An array of all defined service ids
0609 */
0610 public function getServiceIds()
0611 {
0612 return array_unique(array_merge(array_keys($this->getDefinitions()), array_keys($this->aliasDefinitions), parent::getServiceIds()));
0613 }
0614
0615 /**
0616 * Adds the service aliases.
0617 *
0618 * @param array $aliases An array of aliases
0619 */
0620 public function addAliases(array $aliases)
0621 {
0622 foreach ($aliases as $alias => $id) {
0623 $this->setAlias($alias, $id);
0624 }
0625 }
0626
0627 /**
0628 * Sets the service aliases.
0629 *
0630 * @param array $aliases An array of aliases
0631 */
0632 public function setAliases(array $aliases)
0633 {
0634 $this->aliasDefinitions = array();
0635 $this->addAliases($aliases);
0636 }
0637
0638 /**
0639 * Sets an alias for an existing service.
0640 *
0641 * @param string $alias The alias to create
0642 * @param string|Alias $id The service to alias
0643 *
0644 * @throws InvalidArgumentException if the id is not a string or an Alias
0645 * @throws InvalidArgumentException if the alias is for itself
0646 */
0647 public function setAlias($alias, $id)
0648 {
0649 $alias = strtolower($alias);
0650
0651 if (is_string($id)) {
0652 $id = new Alias($id);
0653 } elseif (!$id instanceof Alias) {
0654 throw new InvalidArgumentException('$id must be a string, or an Alias object.');
0655 }
0656
0657 if ($alias === (string) $id) {
0658 throw new InvalidArgumentException(sprintf('An alias can not reference itself, got a circular reference on "%s".', $alias));
0659 }
0660
0661 unset($this->definitions[$alias]);
0662
0663 $this->aliasDefinitions[$alias] = $id;
0664 }
0665
0666 /**
0667 * Removes an alias.
0668 *
0669 * @param string $alias The alias to remove
0670 */
0671 public function removeAlias($alias)
0672 {
0673 unset($this->aliasDefinitions[strtolower($alias)]);
0674 }
0675
0676 /**
0677 * Returns true if an alias exists under the given identifier.
0678 *
0679 * @param string $id The service identifier
0680 *
0681 * @return bool true if the alias exists, false otherwise
0682 */
0683 public function hasAlias($id)
0684 {
0685 return isset($this->aliasDefinitions[strtolower($id)]);
0686 }
0687
0688 /**
0689 * Gets all defined aliases.
0690 *
0691 * @return Alias[] An array of aliases
0692 */
0693 public function getAliases()
0694 {
0695 return $this->aliasDefinitions;
0696 }
0697
0698 /**
0699 * Gets an alias.
0700 *
0701 * @param string $id The service identifier
0702 *
0703 * @return Alias An Alias instance
0704 *
0705 * @throws InvalidArgumentException if the alias does not exist
0706 */
0707 public function getAlias($id)
0708 {
0709 $id = strtolower($id);
0710
0711 if (!isset($this->aliasDefinitions[$id])) {
0712 throw new InvalidArgumentException(sprintf('The service alias "%s" does not exist.', $id));
0713 }
0714
0715 return $this->aliasDefinitions[$id];
0716 }
0717
0718 /**
0719 * Registers a service definition.
0720 *
0721 * This methods allows for simple registration of service definition
0722 * with a fluid interface.
0723 *
0724 * @param string $id The service identifier
0725 * @param string $class The service class
0726 *
0727 * @return Definition A Definition instance
0728 */
0729 public function register($id, $class = null)
0730 {
0731 return $this->setDefinition($id, new Definition($class));
0732 }
0733
0734 /**
0735 * Adds the service definitions.
0736 *
0737 * @param Definition[] $definitions An array of service definitions
0738 */
0739 public function addDefinitions(array $definitions)
0740 {
0741 foreach ($definitions as $id => $definition) {
0742 $this->setDefinition($id, $definition);
0743 }
0744 }
0745
0746 /**
0747 * Sets the service definitions.
0748 *
0749 * @param Definition[] $definitions An array of service definitions
0750 */
0751 public function setDefinitions(array $definitions)
0752 {
0753 $this->definitions = array();
0754 $this->addDefinitions($definitions);
0755 }
0756
0757 /**
0758 * Gets all service definitions.
0759 *
0760 * @return Definition[] An array of Definition instances
0761 */
0762 public function getDefinitions()
0763 {
0764 return $this->definitions;
0765 }
0766
0767 /**
0768 * Sets a service definition.
0769 *
0770 * @param string $id The service identifier
0771 * @param Definition $definition A Definition instance
0772 *
0773 * @return Definition the service definition
0774 *
0775 * @throws BadMethodCallException When this ContainerBuilder is frozen
0776 */
0777 public function setDefinition($id, Definition $definition)
0778 {
0779 if ($this->isFrozen()) {
0780 throw new BadMethodCallException('Adding definition to a frozen container is not allowed');
0781 }
0782
0783 $id = strtolower($id);
0784
0785 unset($this->aliasDefinitions[$id]);
0786
0787 return $this->definitions[$id] = $definition;
0788 }
0789
0790 /**
0791 * Returns true if a service definition exists under the given identifier.
0792 *
0793 * @param string $id The service identifier
0794 *
0795 * @return bool true if the service definition exists, false otherwise
0796 */
0797 public function hasDefinition($id)
0798 {
0799 return array_key_exists(strtolower($id), $this->definitions);
0800 }
0801
0802 /**
0803 * Gets a service definition.
0804 *
0805 * @param string $id The service identifier
0806 *
0807 * @return Definition A Definition instance
0808 *
0809 * @throws ServiceNotFoundException if the service definition does not exist
0810 */
0811 public function getDefinition($id)
0812 {
0813 $id = strtolower($id);
0814
0815 if (!array_key_exists($id, $this->definitions)) {
0816 throw new ServiceNotFoundException($id);
0817 }
0818
0819 return $this->definitions[$id];
0820 }
0821
0822 /**
0823 * Gets a service definition by id or alias.
0824 *
0825 * The method "unaliases" recursively to return a Definition instance.
0826 *
0827 * @param string $id The service identifier or alias
0828 *
0829 * @return Definition A Definition instance
0830 *
0831 * @throws ServiceNotFoundException if the service definition does not exist
0832 */
0833 public function findDefinition($id)
0834 {
0835 $id = strtolower($id);
0836
0837 while (isset($this->aliasDefinitions[$id])) {
0838 $id = (string) $this->aliasDefinitions[$id];
0839 }
0840
0841 return $this->getDefinition($id);
0842 }
0843
0844 /**
0845 * Creates a service for a service definition.
0846 *
0847 * @param Definition $definition A service definition instance
0848 * @param string $id The service identifier
0849 * @param bool $tryProxy Whether to try proxying the service with a lazy proxy
0850 *
0851 * @return object The service described by the service definition
0852 *
0853 * @throws RuntimeException When the scope is inactive
0854 * @throws RuntimeException When the factory definition is incomplete
0855 * @throws RuntimeException When the service is a synthetic service
0856 * @throws InvalidArgumentException When configure callable is not callable
0857 *
0858 * @internal this method is public because of PHP 5.3 limitations, do not use it explicitly in your code
0859 */
0860 public function createService(Definition $definition, $id, $tryProxy = true)
0861 {
0862 if ('Symfony\Component\DependencyInjection\Definition' !== get_class($definition)) {
0863 throw new RuntimeException(sprintf('Constructing service "%s" from a %s is not supported at build time.', $id, get_class($definition)));
0864 }
0865
0866 if ($definition->isSynthetic()) {
0867 throw new RuntimeException(sprintf('You have requested a synthetic service ("%s"). The DIC does not know how to construct this service.', $id));
0868 }
0869
0870 if ($definition->isDeprecated()) {
0871 @trigger_error($definition->getDeprecationMessage($id), E_USER_DEPRECATED);
0872 }
0873
0874 if ($tryProxy && $definition->isLazy()) {
0875 $container = $this;
0876
0877 $proxy = $this
0878 ->getProxyInstantiator()
0879 ->instantiateProxy(
0880 $container,
0881 $definition,
0882 $id, function () use ($definition, $id, $container) {
0883 return $container->createService($definition, $id, false);
0884 }
0885 );
0886 $this->shareService($definition, $proxy, $id);
0887
0888 return $proxy;
0889 }
0890
0891 $parameterBag = $this->getParameterBag();
0892
0893 if (null !== $definition->getFile()) {
0894 require_once $parameterBag->resolveValue($definition->getFile());
0895 }
0896
0897 $arguments = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())));
0898
0899 if (null !== $factory = $definition->getFactory()) {
0900 if (is_array($factory)) {
0901 $factory = array($this->resolveServices($parameterBag->resolveValue($factory[0])), $factory[1]);
0902 } elseif (!is_string($factory)) {
0903 throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id));
0904 }
0905
0906 $service = call_user_func_array($factory, $arguments);
0907
0908 if (!$definition->isDeprecated() && is_array($factory) && is_string($factory[0])) {
0909 $r = new \ReflectionClass($factory[0]);
0910
0911 if (0 < strpos($r->getDocComment(), "\n * @deprecated ")) {
0912 @trigger_error(sprintf('The "%s" service relies on the deprecated "%s" factory class. It should either be deprecated or its factory upgraded.', $id, $r->name), E_USER_DEPRECATED);
0913 }
0914 }
0915 } elseif (null !== $definition->getFactoryMethod(false)) {
0916 if (null !== $definition->getFactoryClass(false)) {
0917 $factory = $parameterBag->resolveValue($definition->getFactoryClass(false));
0918 } elseif (null !== $definition->getFactoryService(false)) {
0919 $factory = $this->get($parameterBag->resolveValue($definition->getFactoryService(false)));
0920 } else {
0921 throw new RuntimeException(sprintf('Cannot create service "%s" from factory method without a factory service or factory class.', $id));
0922 }
0923
0924 $service = call_user_func_array(array($factory, $definition->getFactoryMethod(false)), $arguments);
0925 } else {
0926 $r = new \ReflectionClass($parameterBag->resolveValue($definition->getClass()));
0927
0928 $service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs($arguments);
0929
0930 if (!$definition->isDeprecated() && 0 < strpos($r->getDocComment(), "\n * @deprecated ")) {
0931 @trigger_error(sprintf('The "%s" service relies on the deprecated "%s" class. It should either be deprecated or its implementation upgraded.', $id, $r->name), E_USER_DEPRECATED);
0932 }
0933 }
0934
0935 if ($tryProxy || !$definition->isLazy()) {
0936 // share only if proxying failed, or if not a proxy
0937 $this->shareService($definition, $service, $id);
0938 }
0939
0940 foreach ($definition->getMethodCalls() as $call) {
0941 $this->callMethod($service, $call);
0942 }
0943
0944 $properties = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties())));
0945 foreach ($properties as $name => $value) {
0946 $service->$name = $value;
0947 }
0948
0949 if ($callable = $definition->getConfigurator()) {
0950 if (is_array($callable)) {
0951 $callable[0] = $parameterBag->resolveValue($callable[0]);
0952
0953 if ($callable[0] instanceof Reference) {
0954 $callable[0] = $this->get((string) $callable[0], $callable[0]->getInvalidBehavior());
0955 } elseif ($callable[0] instanceof Definition) {
0956 $callable[0] = $this->createService($callable[0], null);
0957 }
0958 }
0959
0960 if (!is_callable($callable)) {
0961 throw new InvalidArgumentException(sprintf('The configure callable for class "%s" is not a callable.', get_class($service)));
0962 }
0963
0964 call_user_func($callable, $service);
0965 }
0966
0967 return $service;
0968 }
0969
0970 /**
0971 * Replaces service references by the real service instance and evaluates expressions.
0972 *
0973 * @param mixed $value A value
0974 *
0975 * @return mixed The same value with all service references replaced by
0976 * the real service instances and all expressions evaluated
0977 */
0978 public function resolveServices($value)
0979 {
0980 if (is_array($value)) {
0981 foreach ($value as $k => $v) {
0982 $value[$k] = $this->resolveServices($v);
0983 }
0984 } elseif ($value instanceof Reference) {
0985 $value = $this->get((string) $value, $value->getInvalidBehavior());
0986 } elseif ($value instanceof Definition) {
0987 $value = $this->createService($value, null);
0988 } elseif ($value instanceof Expression) {
0989 $value = $this->getExpressionLanguage()->evaluate($value, array('container' => $this));
0990 }
0991
0992 return $value;
0993 }
0994
0995 /**
0996 * Returns service ids for a given tag.
0997 *
0998 * Example:
0999 *
1000 * $container->register('foo')->addTag('my.tag', array('hello' => 'world'));
1001 *
1002 * $serviceIds = $container->findTaggedServiceIds('my.tag');
1003 * foreach ($serviceIds as $serviceId => $tags) {
1004 * foreach ($tags as $tag) {
1005 * echo $tag['hello'];
1006 * }
1007 * }
1008 *
1009 * @param string $name The tag name
1010 *
1011 * @return array An array of tags with the tagged service as key, holding a list of attribute arrays
1012 */
1013 public function findTaggedServiceIds($name)
1014 {
1015 $this->usedTags[] = $name;
1016 $tags = array();
1017 foreach ($this->getDefinitions() as $id => $definition) {
1018 if ($definition->hasTag($name)) {
1019 $tags[$id] = $definition->getTag($name);
1020 }
1021 }
1022
1023 return $tags;
1024 }
1025
1026 /**
1027 * Returns all tags the defined services use.
1028 *
1029 * @return array An array of tags
1030 */
1031 public function findTags()
1032 {
1033 $tags = array();
1034 foreach ($this->getDefinitions() as $id => $definition) {
1035 $tags = array_merge(array_keys($definition->getTags()), $tags);
1036 }
1037
1038 return array_unique($tags);
1039 }
1040
1041 /**
1042 * Returns all tags not queried by findTaggedServiceIds.
1043 *
1044 * @return string[] An array of tags
1045 */
1046 public function findUnusedTags()
1047 {
1048 return array_values(array_diff($this->findTags(), $this->usedTags));
1049 }
1050
1051 public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
1052 {
1053 $this->expressionLanguageProviders[] = $provider;
1054 }
1055
1056 /**
1057 * @return ExpressionFunctionProviderInterface[]
1058 */
1059 public function getExpressionLanguageProviders()
1060 {
1061 return $this->expressionLanguageProviders;
1062 }
1063
1064 /**
1065 * Returns the Service Conditionals.
1066 *
1067 * @param mixed $value An array of conditionals to return
1068 *
1069 * @return array An array of Service conditionals
1070 */
1071 public static function getServiceConditionals($value)
1072 {
1073 $services = array();
1074
1075 if (is_array($value)) {
1076 foreach ($value as $v) {
1077 $services = array_unique(array_merge($services, self::getServiceConditionals($v)));
1078 }
1079 } elseif ($value instanceof Reference && $value->getInvalidBehavior() === ContainerInterface::IGNORE_ON_INVALID_REFERENCE) {
1080 $services[] = (string) $value;
1081 }
1082
1083 return $services;
1084 }
1085
1086 /**
1087 * Retrieves the currently set proxy instantiator or instantiates one.
1088 *
1089 * @return InstantiatorInterface
1090 */
1091 private function getProxyInstantiator()
1092 {
1093 if (!$this->proxyInstantiator) {
1094 $this->proxyInstantiator = new RealServiceInstantiator();
1095 }
1096
1097 return $this->proxyInstantiator;
1098 }
1099
1100 /**
1101 * Synchronizes a service change.
1102 *
1103 * This method updates all services that depend on the given
1104 * service by calling all methods referencing it.
1105 *
1106 * @param string $id A service id
1107 *
1108 * @deprecated since version 2.7, will be removed in 3.0.
1109 */
1110 private function synchronize($id)
1111 {
1112 if ('request' !== $id) {
1113 @trigger_error('The '.__METHOD__.' method is deprecated in version 2.7 and will be removed in version 3.0.', E_USER_DEPRECATED);
1114 }
1115
1116 foreach ($this->definitions as $definitionId => $definition) {
1117 // only check initialized services
1118 if (!$this->initialized($definitionId)) {
1119 continue;
1120 }
1121
1122 foreach ($definition->getMethodCalls() as $call) {
1123 foreach ($call[1] as $argument) {
1124 if ($argument instanceof Reference && $id == (string) $argument) {
1125 $this->callMethod($this->get($definitionId), $call);
1126 }
1127 }
1128 }
1129 }
1130 }
1131
1132 private function callMethod($service, $call)
1133 {
1134 $services = self::getServiceConditionals($call[1]);
1135
1136 foreach ($services as $s) {
1137 if (!$this->has($s)) {
1138 return;
1139 }
1140 }
1141
1142 call_user_func_array(array($service, $call[0]), $this->resolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1]))));
1143 }
1144
1145 /**
1146 * Shares a given service in the container.
1147 *
1148 * @param Definition $definition
1149 * @param mixed $service
1150 * @param string $id
1151 *
1152 * @throws InactiveScopeException
1153 */
1154 private function shareService(Definition $definition, $service, $id)
1155 {
1156 if ($definition->isShared() && self::SCOPE_PROTOTYPE !== $scope = $definition->getScope(false)) {
1157 if (self::SCOPE_CONTAINER !== $scope && !isset($this->scopedServices[$scope])) {
1158 throw new InactiveScopeException($id, $scope);
1159 }
1160
1161 $this->services[$lowerId = strtolower($id)] = $service;
1162
1163 if (self::SCOPE_CONTAINER !== $scope) {
1164 $this->scopedServices[$scope][$lowerId] = $service;
1165 }
1166 }
1167 }
1168
1169 private function getExpressionLanguage()
1170 {
1171 if (null === $this->expressionLanguage) {
1172 if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
1173 throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
1174 }
1175 $this->expressionLanguage = new ExpressionLanguage(null, $this->expressionLanguageProviders);
1176 }
1177
1178 return $this->expressionLanguage;
1179 }
1180 }
1181