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.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

ContainerBuilder.php

Zuletzt modifiziert: 09.10.2024, 12:58 - Dateigröße: 31.71 KiB


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