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