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