[ Index ]

PHP Cross Reference of phpBB-3.1.12-deutsch

title

Body

[close]

/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ -> ContainerBuilder.php (source)

   1  <?php
   2  
   3  /*
   4   * This file is part of the Symfony package.
   5   *
   6   * (c) Fabien Potencier <fabien@symfony.com>
   7   *
   8   * For the full copyright and license information, please view the LICENSE
   9   * file that was distributed with this source code.
  10   */
  11  
  12  namespace Symfony\Component\DependencyInjection;
  13  
  14  use Symfony\Component\DependencyInjection\Compiler\Compiler;
  15  use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
  16  use Symfony\Component\DependencyInjection\Compiler\PassConfig;
  17  use Symfony\Component\DependencyInjection\Exception\BadMethodCallException;
  18  use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
  19  use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
  20  use Symfony\Component\DependencyInjection\Exception\LogicException;
  21  use Symfony\Component\DependencyInjection\Exception\RuntimeException;
  22  use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
  23  use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
  24  use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
  25  use Symfony\Component\Config\Resource\FileResource;
  26  use Symfony\Component\Config\Resource\ResourceInterface;
  27  use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;
  28  use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator;
  29  
  30  /**
  31   * ContainerBuilder is a DI container that provides an API to easily describe services.
  32   *
  33   * @author Fabien Potencier <fabien@symfony.com>
  34   */
  35  class ContainerBuilder extends Container implements TaggedContainerInterface
  36  {
  37      /**
  38       * @var ExtensionInterface[]
  39       */
  40      private $extensions = array();
  41  
  42      /**
  43       * @var ExtensionInterface[]
  44       */
  45      private $extensionsByNs = array();
  46  
  47      /**
  48       * @var Definition[]
  49       */
  50      private $definitions = array();
  51  
  52      /**
  53       * @var Definition[]
  54       */
  55      private $obsoleteDefinitions = array();
  56  
  57      /**
  58       * @var Alias[]
  59       */
  60      private $aliasDefinitions = array();
  61  
  62      /**
  63       * @var ResourceInterface[]
  64       */
  65      private $resources = array();
  66  
  67      private $extensionConfigs = array();
  68  
  69      /**
  70       * @var Compiler
  71       */
  72      private $compiler;
  73  
  74      private $trackResources = true;
  75  
  76      /**
  77       * @var InstantiatorInterface|null
  78       */
  79      private $proxyInstantiator;
  80  
  81      /**
  82       * Sets the track resources flag.
  83       *
  84       * If you are not using the loaders and therefore don't want
  85       * to depend on the Config component, set this flag to false.
  86       *
  87       * @param bool $track true if you want to track resources, false otherwise
  88       */
  89      public function setResourceTracking($track)
  90      {
  91          $this->trackResources = (bool) $track;
  92      }
  93  
  94      /**
  95       * Checks if resources are tracked.
  96       *
  97       * @return bool true if resources are tracked, false otherwise
  98       */
  99      public function isTrackingResources()
 100      {
 101          return $this->trackResources;
 102      }
 103  
 104      /**
 105       * Sets the instantiator to be used when fetching proxies.
 106       *
 107       * @param InstantiatorInterface $proxyInstantiator
 108       */
 109      public function setProxyInstantiator(InstantiatorInterface $proxyInstantiator)
 110      {
 111          $this->proxyInstantiator = $proxyInstantiator;
 112      }
 113  
 114      /**
 115       * Registers an extension.
 116       *
 117       * @param ExtensionInterface $extension An extension instance
 118       */
 119      public function registerExtension(ExtensionInterface $extension)
 120      {
 121          $this->extensions[$extension->getAlias()] = $extension;
 122  
 123          if (false !== $extension->getNamespace()) {
 124              $this->extensionsByNs[$extension->getNamespace()] = $extension;
 125          }
 126      }
 127  
 128      /**
 129       * Returns an extension by alias or namespace.
 130       *
 131       * @param string $name An alias or a namespace
 132       *
 133       * @return ExtensionInterface An extension instance
 134       *
 135       * @throws LogicException if the extension is not registered
 136       */
 137      public function getExtension($name)
 138      {
 139          if (isset($this->extensions[$name])) {
 140              return $this->extensions[$name];
 141          }
 142  
 143          if (isset($this->extensionsByNs[$name])) {
 144              return $this->extensionsByNs[$name];
 145          }
 146  
 147          throw new LogicException(sprintf('Container extension "%s" is not registered', $name));
 148      }
 149  
 150      /**
 151       * Returns all registered extensions.
 152       *
 153       * @return ExtensionInterface[] An array of ExtensionInterface
 154       */
 155      public function getExtensions()
 156      {
 157          return $this->extensions;
 158      }
 159  
 160      /**
 161       * Checks if we have an extension.
 162       *
 163       * @param string $name The name of the extension
 164       *
 165       * @return bool If the extension exists
 166       */
 167      public function hasExtension($name)
 168      {
 169          return isset($this->extensions[$name]) || isset($this->extensionsByNs[$name]);
 170      }
 171  
 172      /**
 173       * Returns an array of resources loaded to build this configuration.
 174       *
 175       * @return ResourceInterface[] An array of resources
 176       */
 177      public function getResources()
 178      {
 179          return array_unique($this->resources);
 180      }
 181  
 182      /**
 183       * Adds a resource for this configuration.
 184       *
 185       * @param ResourceInterface $resource A resource instance
 186       *
 187       * @return ContainerBuilder The current instance
 188       */
 189      public function addResource(ResourceInterface $resource)
 190      {
 191          if (!$this->trackResources) {
 192              return $this;
 193          }
 194  
 195          $this->resources[] = $resource;
 196  
 197          return $this;
 198      }
 199  
 200      /**
 201       * Sets the resources for this configuration.
 202       *
 203       * @param ResourceInterface[] $resources An array of resources
 204       *
 205       * @return ContainerBuilder The current instance
 206       */
 207      public function setResources(array $resources)
 208      {
 209          if (!$this->trackResources) {
 210              return $this;
 211          }
 212  
 213          $this->resources = $resources;
 214  
 215          return $this;
 216      }
 217  
 218      /**
 219       * Adds the object class hierarchy as resources.
 220       *
 221       * @param object $object An object instance
 222       *
 223       * @return ContainerBuilder The current instance
 224       */
 225      public function addObjectResource($object)
 226      {
 227          if ($this->trackResources) {
 228              $this->addClassResource(new \ReflectionClass($object));
 229          }
 230  
 231          return $this;
 232      }
 233  
 234      /**
 235       * Adds the given class hierarchy as resources.
 236       *
 237       * @param \ReflectionClass $class
 238       *
 239       * @return ContainerBuilder The current instance
 240       */
 241      public function addClassResource(\ReflectionClass $class)
 242      {
 243          if (!$this->trackResources) {
 244              return $this;
 245          }
 246  
 247          do {
 248              if (is_file($class->getFileName())) {
 249                  $this->addResource(new FileResource($class->getFileName()));
 250              }
 251          } while ($class = $class->getParentClass());
 252  
 253          return $this;
 254      }
 255  
 256      /**
 257       * Loads the configuration for an extension.
 258       *
 259       * @param string $extension The extension alias or namespace
 260       * @param array  $values    An array of values that customizes the extension
 261       *
 262       * @return ContainerBuilder The current instance
 263       *
 264       * @throws BadMethodCallException When this ContainerBuilder is frozen
 265       * @throws \LogicException        if the container is frozen
 266       */
 267      public function loadFromExtension($extension, array $values = array())
 268      {
 269          if ($this->isFrozen()) {
 270              throw new BadMethodCallException('Cannot load from an extension on a frozen container.');
 271          }
 272  
 273          $namespace = $this->getExtension($extension)->getAlias();
 274  
 275          $this->extensionConfigs[$namespace][] = $values;
 276  
 277          return $this;
 278      }
 279  
 280      /**
 281       * Adds a compiler pass.
 282       *
 283       * @param CompilerPassInterface $pass A compiler pass
 284       * @param string                $type The type of compiler pass
 285       *
 286       * @return ContainerBuilder The current instance
 287       */
 288      public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION)
 289      {
 290          if (null === $this->compiler) {
 291              $this->compiler = new Compiler();
 292          }
 293  
 294          $this->compiler->addPass($pass, $type);
 295  
 296          $this->addObjectResource($pass);
 297  
 298          return $this;
 299      }
 300  
 301      /**
 302       * Returns the compiler pass config which can then be modified.
 303       *
 304       * @return PassConfig The compiler pass config
 305       */
 306      public function getCompilerPassConfig()
 307      {
 308          if (null === $this->compiler) {
 309              $this->compiler = new Compiler();
 310          }
 311  
 312          return $this->compiler->getPassConfig();
 313      }
 314  
 315      /**
 316       * Returns the compiler.
 317       *
 318       * @return Compiler The compiler
 319       */
 320      public function getCompiler()
 321      {
 322          if (null === $this->compiler) {
 323              $this->compiler = new Compiler();
 324          }
 325  
 326          return $this->compiler;
 327      }
 328  
 329      /**
 330       * Returns all Scopes.
 331       *
 332       * @return array An array of scopes
 333       */
 334      public function getScopes()
 335      {
 336          return $this->scopes;
 337      }
 338  
 339      /**
 340       * Returns all Scope children.
 341       *
 342       * @return array An array of scope children.
 343       */
 344      public function getScopeChildren()
 345      {
 346          return $this->scopeChildren;
 347      }
 348  
 349      /**
 350       * Sets a service.
 351       *
 352       * @param string $id      The service identifier
 353       * @param object $service The service instance
 354       * @param string $scope   The scope
 355       *
 356       * @throws BadMethodCallException When this ContainerBuilder is frozen
 357       */
 358      public function set($id, $service, $scope = self::SCOPE_CONTAINER)
 359      {
 360          $id = strtolower($id);
 361  
 362          if ($this->isFrozen()) {
 363              // setting a synthetic service on a frozen container is alright
 364              if (
 365                  (!isset($this->definitions[$id]) && !isset($this->obsoleteDefinitions[$id]))
 366                      ||
 367                  (isset($this->definitions[$id]) && !$this->definitions[$id]->isSynthetic())
 368                      ||
 369                  (isset($this->obsoleteDefinitions[$id]) && !$this->obsoleteDefinitions[$id]->isSynthetic())
 370              ) {
 371                  throw new BadMethodCallException(sprintf('Setting service "%s" on a frozen container is not allowed.', $id));
 372              }
 373          }
 374  
 375          if (isset($this->definitions[$id])) {
 376              $this->obsoleteDefinitions[$id] = $this->definitions[$id];
 377          }
 378  
 379          unset($this->definitions[$id], $this->aliasDefinitions[$id]);
 380  
 381          parent::set($id, $service, $scope);
 382  
 383          if (isset($this->obsoleteDefinitions[$id]) && $this->obsoleteDefinitions[$id]->isSynchronized()) {
 384              $this->synchronize($id);
 385          }
 386      }
 387  
 388      /**
 389       * Removes a service definition.
 390       *
 391       * @param string $id The service identifier
 392       */
 393      public function removeDefinition($id)
 394      {
 395          unset($this->definitions[strtolower($id)]);
 396      }
 397  
 398      /**
 399       * Returns true if the given service is defined.
 400       *
 401       * @param string $id The service identifier
 402       *
 403       * @return bool true if the service is defined, false otherwise
 404       */
 405      public function has($id)
 406      {
 407          $id = strtolower($id);
 408  
 409          return isset($this->definitions[$id]) || isset($this->aliasDefinitions[$id]) || parent::has($id);
 410      }
 411  
 412      /**
 413       * Gets a service.
 414       *
 415       * @param string $id              The service identifier
 416       * @param int    $invalidBehavior The behavior when the service does not exist
 417       *
 418       * @return object The associated service
 419       *
 420       * @throws InvalidArgumentException          when no definitions are available
 421       * @throws ServiceCircularReferenceException When a circular reference is detected
 422       * @throws ServiceNotFoundException          When the service is not defined
 423       * @throws \Exception
 424       *
 425       * @see Reference
 426       */
 427      public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
 428      {
 429          $id = strtolower($id);
 430  
 431          if ($service = parent::get($id, ContainerInterface::NULL_ON_INVALID_REFERENCE)) {
 432              return $service;
 433          }
 434  
 435          if (isset($this->loading[$id])) {
 436              throw new LogicException(sprintf('The service "%s" has a circular reference to itself.', $id));
 437          }
 438  
 439          if (!array_key_exists($id, $this->definitions) && isset($this->aliasDefinitions[$id])) {
 440              return $this->get($this->aliasDefinitions[$id]);
 441          }
 442  
 443          try {
 444              $definition = $this->getDefinition($id);
 445          } catch (ServiceNotFoundException $e) {
 446              if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
 447                  return;
 448              }
 449  
 450              throw $e;
 451          }
 452  
 453          $this->loading[$id] = true;
 454  
 455          try {
 456              $service = $this->createService($definition, $id);
 457          } catch (\Exception $e) {
 458              unset($this->loading[$id]);
 459  
 460              if ($e instanceof InactiveScopeException && self::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
 461                  return;
 462              }
 463  
 464              throw $e;
 465          } catch (\Throwable $e) {
 466              unset($this->loading[$id]);
 467  
 468              throw $e;
 469          }
 470  
 471          unset($this->loading[$id]);
 472  
 473          return $service;
 474      }
 475  
 476      /**
 477       * Merges a ContainerBuilder with the current ContainerBuilder configuration.
 478       *
 479       * Service definitions overrides the current defined ones.
 480       *
 481       * But for parameters, they are overridden by the current ones. It allows
 482       * the parameters passed to the container constructor to have precedence
 483       * over the loaded ones.
 484       *
 485       * $container = new ContainerBuilder(array('foo' => 'bar'));
 486       * $loader = new LoaderXXX($container);
 487       * $loader->load('resource_name');
 488       * $container->register('foo', new stdClass());
 489       *
 490       * In the above example, even if the loaded resource defines a foo
 491       * parameter, the value will still be 'bar' as defined in the ContainerBuilder
 492       * constructor.
 493       *
 494       * @param ContainerBuilder $container The ContainerBuilder instance to merge.
 495       *
 496       * @throws BadMethodCallException When this ContainerBuilder is frozen
 497       */
 498      public function merge(ContainerBuilder $container)
 499      {
 500          if ($this->isFrozen()) {
 501              throw new BadMethodCallException('Cannot merge on a frozen container.');
 502          }
 503  
 504          $this->addDefinitions($container->getDefinitions());
 505          $this->addAliases($container->getAliases());
 506          $this->getParameterBag()->add($container->getParameterBag()->all());
 507  
 508          if ($this->trackResources) {
 509              foreach ($container->getResources() as $resource) {
 510                  $this->addResource($resource);
 511              }
 512          }
 513  
 514          foreach ($this->extensions as $name => $extension) {
 515              if (!isset($this->extensionConfigs[$name])) {
 516                  $this->extensionConfigs[$name] = array();
 517              }
 518  
 519              $this->extensionConfigs[$name] = array_merge($this->extensionConfigs[$name], $container->getExtensionConfig($name));
 520          }
 521      }
 522  
 523      /**
 524       * Returns the configuration array for the given extension.
 525       *
 526       * @param string $name The name of the extension
 527       *
 528       * @return array An array of configuration
 529       */
 530      public function getExtensionConfig($name)
 531      {
 532          if (!isset($this->extensionConfigs[$name])) {
 533              $this->extensionConfigs[$name] = array();
 534          }
 535  
 536          return $this->extensionConfigs[$name];
 537      }
 538  
 539      /**
 540       * Prepends a config array to the configs of the given extension.
 541       *
 542       * @param string $name   The name of the extension
 543       * @param array  $config The config to set
 544       */
 545      public function prependExtensionConfig($name, array $config)
 546      {
 547          if (!isset($this->extensionConfigs[$name])) {
 548              $this->extensionConfigs[$name] = array();
 549          }
 550  
 551          array_unshift($this->extensionConfigs[$name], $config);
 552      }
 553  
 554      /**
 555       * Compiles the container.
 556       *
 557       * This method passes the container to compiler
 558       * passes whose job is to manipulate and optimize
 559       * the container.
 560       *
 561       * The main compiler passes roughly do four things:
 562       *
 563       *  * The extension configurations are merged;
 564       *  * Parameter values are resolved;
 565       *  * The parameter bag is frozen;
 566       *  * Extension loading is disabled.
 567       */
 568      public function compile()
 569      {
 570          if (null === $this->compiler) {
 571              $this->compiler = new Compiler();
 572          }
 573  
 574          if ($this->trackResources) {
 575              foreach ($this->compiler->getPassConfig()->getPasses() as $pass) {
 576                  $this->addObjectResource($pass);
 577              }
 578          }
 579  
 580          $this->compiler->compile($this);
 581  
 582          if ($this->trackResources) {
 583              foreach ($this->definitions as $definition) {
 584                  if ($definition->isLazy() && ($class = $definition->getClass()) && class_exists($class)) {
 585                      $this->addClassResource(new \ReflectionClass($class));
 586                  }
 587              }
 588          }
 589  
 590          $this->extensionConfigs = array();
 591  
 592          parent::compile();
 593      }
 594  
 595      /**
 596       * Gets all service ids.
 597       *
 598       * @return array An array of all defined service ids
 599       */
 600      public function getServiceIds()
 601      {
 602          return array_unique(array_merge(array_keys($this->getDefinitions()), array_keys($this->aliasDefinitions), parent::getServiceIds()));
 603      }
 604  
 605      /**
 606       * Adds the service aliases.
 607       *
 608       * @param array $aliases An array of aliases
 609       */
 610      public function addAliases(array $aliases)
 611      {
 612          foreach ($aliases as $alias => $id) {
 613              $this->setAlias($alias, $id);
 614          }
 615      }
 616  
 617      /**
 618       * Sets the service aliases.
 619       *
 620       * @param array $aliases An array of aliases
 621       */
 622      public function setAliases(array $aliases)
 623      {
 624          $this->aliasDefinitions = array();
 625          $this->addAliases($aliases);
 626      }
 627  
 628      /**
 629       * Sets an alias for an existing service.
 630       *
 631       * @param string       $alias The alias to create
 632       * @param string|Alias $id    The service to alias
 633       *
 634       * @throws InvalidArgumentException if the id is not a string or an Alias
 635       * @throws InvalidArgumentException if the alias is for itself
 636       */
 637      public function setAlias($alias, $id)
 638      {
 639          $alias = strtolower($alias);
 640  
 641          if (is_string($id)) {
 642              $id = new Alias($id);
 643          } elseif (!$id instanceof Alias) {
 644              throw new InvalidArgumentException('$id must be a string, or an Alias object.');
 645          }
 646  
 647          if ($alias === (string) $id) {
 648              throw new InvalidArgumentException(sprintf('An alias can not reference itself, got a circular reference on "%s".', $alias));
 649          }
 650  
 651          unset($this->definitions[$alias]);
 652  
 653          $this->aliasDefinitions[$alias] = $id;
 654      }
 655  
 656      /**
 657       * Removes an alias.
 658       *
 659       * @param string $alias The alias to remove
 660       */
 661      public function removeAlias($alias)
 662      {
 663          unset($this->aliasDefinitions[strtolower($alias)]);
 664      }
 665  
 666      /**
 667       * Returns true if an alias exists under the given identifier.
 668       *
 669       * @param string $id The service identifier
 670       *
 671       * @return bool true if the alias exists, false otherwise
 672       */
 673      public function hasAlias($id)
 674      {
 675          return isset($this->aliasDefinitions[strtolower($id)]);
 676      }
 677  
 678      /**
 679       * Gets all defined aliases.
 680       *
 681       * @return Alias[] An array of aliases
 682       */
 683      public function getAliases()
 684      {
 685          return $this->aliasDefinitions;
 686      }
 687  
 688      /**
 689       * Gets an alias.
 690       *
 691       * @param string $id The service identifier
 692       *
 693       * @return Alias An Alias instance
 694       *
 695       * @throws InvalidArgumentException if the alias does not exist
 696       */
 697      public function getAlias($id)
 698      {
 699          $id = strtolower($id);
 700  
 701          if (!isset($this->aliasDefinitions[$id])) {
 702              throw new InvalidArgumentException(sprintf('The service alias "%s" does not exist.', $id));
 703          }
 704  
 705          return $this->aliasDefinitions[$id];
 706      }
 707  
 708      /**
 709       * Registers a service definition.
 710       *
 711       * This methods allows for simple registration of service definition
 712       * with a fluid interface.
 713       *
 714       * @param string $id    The service identifier
 715       * @param string $class The service class
 716       *
 717       * @return Definition A Definition instance
 718       */
 719      public function register($id, $class = null)
 720      {
 721          return $this->setDefinition($id, new Definition($class));
 722      }
 723  
 724      /**
 725       * Adds the service definitions.
 726       *
 727       * @param Definition[] $definitions An array of service definitions
 728       */
 729      public function addDefinitions(array $definitions)
 730      {
 731          foreach ($definitions as $id => $definition) {
 732              $this->setDefinition($id, $definition);
 733          }
 734      }
 735  
 736      /**
 737       * Sets the service definitions.
 738       *
 739       * @param Definition[] $definitions An array of service definitions
 740       */
 741      public function setDefinitions(array $definitions)
 742      {
 743          $this->definitions = array();
 744          $this->addDefinitions($definitions);
 745      }
 746  
 747      /**
 748       * Gets all service definitions.
 749       *
 750       * @return Definition[] An array of Definition instances
 751       */
 752      public function getDefinitions()
 753      {
 754          return $this->definitions;
 755      }
 756  
 757      /**
 758       * Sets a service definition.
 759       *
 760       * @param string     $id         The service identifier
 761       * @param Definition $definition A Definition instance
 762       *
 763       * @return Definition the service definition
 764       *
 765       * @throws BadMethodCallException When this ContainerBuilder is frozen
 766       */
 767      public function setDefinition($id, Definition $definition)
 768      {
 769          if ($this->isFrozen()) {
 770              throw new BadMethodCallException('Adding definition to a frozen container is not allowed');
 771          }
 772  
 773          $id = strtolower($id);
 774  
 775          unset($this->aliasDefinitions[$id]);
 776  
 777          return $this->definitions[$id] = $definition;
 778      }
 779  
 780      /**
 781       * Returns true if a service definition exists under the given identifier.
 782       *
 783       * @param string $id The service identifier
 784       *
 785       * @return bool true if the service definition exists, false otherwise
 786       */
 787      public function hasDefinition($id)
 788      {
 789          return array_key_exists(strtolower($id), $this->definitions);
 790      }
 791  
 792      /**
 793       * Gets a service definition.
 794       *
 795       * @param string $id The service identifier
 796       *
 797       * @return Definition A Definition instance
 798       *
 799       * @throws ServiceNotFoundException if the service definition does not exist
 800       */
 801      public function getDefinition($id)
 802      {
 803          $id = strtolower($id);
 804  
 805          if (!array_key_exists($id, $this->definitions)) {
 806              throw new ServiceNotFoundException($id);
 807          }
 808  
 809          return $this->definitions[$id];
 810      }
 811  
 812      /**
 813       * Gets a service definition by id or alias.
 814       *
 815       * The method "unaliases" recursively to return a Definition instance.
 816       *
 817       * @param string $id The service identifier or alias
 818       *
 819       * @return Definition A Definition instance
 820       *
 821       * @throws ServiceNotFoundException if the service definition does not exist
 822       */
 823      public function findDefinition($id)
 824      {
 825          $id = strtolower($id);
 826  
 827          while (isset($this->aliasDefinitions[$id])) {
 828              $id = (string) $this->aliasDefinitions[$id];
 829          }
 830  
 831          return $this->getDefinition($id);
 832      }
 833  
 834      /**
 835       * Creates a service for a service definition.
 836       *
 837       * @param Definition $definition A service definition instance
 838       * @param string     $id         The service identifier
 839       * @param bool       $tryProxy   Whether to try proxying the service with a lazy proxy
 840       *
 841       * @return object The service described by the service definition
 842       *
 843       * @throws RuntimeException         When the scope is inactive
 844       * @throws RuntimeException         When the factory definition is incomplete
 845       * @throws RuntimeException         When the service is a synthetic service
 846       * @throws InvalidArgumentException When configure callable is not callable
 847       *
 848       * @internal this method is public because of PHP 5.3 limitations, do not use it explicitly in your code
 849       */
 850      public function createService(Definition $definition, $id, $tryProxy = true)
 851      {
 852          if ($definition->isSynthetic()) {
 853              throw new RuntimeException(sprintf('You have requested a synthetic service ("%s"). The DIC does not know how to construct this service.', $id));
 854          }
 855  
 856          if ($tryProxy && $definition->isLazy()) {
 857              $container = $this;
 858  
 859              $proxy = $this
 860                  ->getProxyInstantiator()
 861                  ->instantiateProxy(
 862                      $container,
 863                      $definition,
 864                      $id, function () use ($definition, $id, $container) {
 865                          return $container->createService($definition, $id, false);
 866                      }
 867                  );
 868              $this->shareService($definition, $proxy, $id);
 869  
 870              return $proxy;
 871          }
 872  
 873          $parameterBag = $this->getParameterBag();
 874  
 875          if (null !== $definition->getFile()) {
 876              require_once $parameterBag->resolveValue($definition->getFile());
 877          }
 878  
 879          $arguments = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())));
 880  
 881          if (null !== $definition->getFactoryMethod()) {
 882              if (null !== $definition->getFactoryClass()) {
 883                  $factory = $parameterBag->resolveValue($definition->getFactoryClass());
 884              } elseif (null !== $definition->getFactoryService()) {
 885                  $factory = $this->get($parameterBag->resolveValue($definition->getFactoryService()));
 886              } else {
 887                  throw new RuntimeException(sprintf('Cannot create service "%s" from factory method without a factory service or factory class.', $id));
 888              }
 889  
 890              $service = call_user_func_array(array($factory, $definition->getFactoryMethod()), $arguments);
 891          } else {
 892              $r = new \ReflectionClass($parameterBag->resolveValue($definition->getClass()));
 893  
 894              $service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs($arguments);
 895          }
 896  
 897          if ($tryProxy || !$definition->isLazy()) {
 898              // share only if proxying failed, or if not a proxy
 899              $this->shareService($definition, $service, $id);
 900          }
 901  
 902          foreach ($definition->getMethodCalls() as $call) {
 903              $this->callMethod($service, $call);
 904          }
 905  
 906          $properties = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties())));
 907          foreach ($properties as $name => $value) {
 908              $service->$name = $value;
 909          }
 910  
 911          if ($callable = $definition->getConfigurator()) {
 912              if (is_array($callable)) {
 913                  $callable[0] = $callable[0] instanceof Reference ? $this->get((string) $callable[0]) : $parameterBag->resolveValue($callable[0]);
 914              }
 915  
 916              if (!is_callable($callable)) {
 917                  throw new InvalidArgumentException(sprintf('The configure callable for class "%s" is not a callable.', get_class($service)));
 918              }
 919  
 920              call_user_func($callable, $service);
 921          }
 922  
 923          return $service;
 924      }
 925  
 926      /**
 927       * Replaces service references by the real service instance.
 928       *
 929       * @param mixed $value A value
 930       *
 931       * @return mixed The same value with all service references replaced by the real service instances
 932       */
 933      public function resolveServices($value)
 934      {
 935          if (is_array($value)) {
 936              foreach ($value as $k => $v) {
 937                  $value[$k] = $this->resolveServices($v);
 938              }
 939          } elseif ($value instanceof Reference) {
 940              $value = $this->get((string) $value, $value->getInvalidBehavior());
 941          } elseif ($value instanceof Definition) {
 942              $value = $this->createService($value, null);
 943          }
 944  
 945          return $value;
 946      }
 947  
 948      /**
 949       * Returns service ids for a given tag.
 950       *
 951       * Example:
 952       *
 953       * $container->register('foo')->addTag('my.tag', array('hello' => 'world'));
 954       *
 955       * $serviceIds = $container->findTaggedServiceIds('my.tag');
 956       * foreach ($serviceIds as $serviceId => $tags) {
 957       *     foreach ($tags as $tag) {
 958       *         echo $tag['hello'];
 959       *     }
 960       * }
 961       *
 962       * @param string $name The tag name
 963       *
 964       * @return array An array of tags with the tagged service as key, holding a list of attribute arrays.
 965       */
 966      public function findTaggedServiceIds($name)
 967      {
 968          $tags = array();
 969          foreach ($this->getDefinitions() as $id => $definition) {
 970              if ($definition->hasTag($name)) {
 971                  $tags[$id] = $definition->getTag($name);
 972              }
 973          }
 974  
 975          return $tags;
 976      }
 977  
 978      /**
 979       * Returns all tags the defined services use.
 980       *
 981       * @return array An array of tags
 982       */
 983      public function findTags()
 984      {
 985          $tags = array();
 986          foreach ($this->getDefinitions() as $id => $definition) {
 987              $tags = array_merge(array_keys($definition->getTags()), $tags);
 988          }
 989  
 990          return array_unique($tags);
 991      }
 992  
 993      /**
 994       * Returns the Service Conditionals.
 995       *
 996       * @param mixed $value An array of conditionals to return.
 997       *
 998       * @return array An array of Service conditionals
 999       */
1000      public static function getServiceConditionals($value)
1001      {
1002          $services = array();
1003  
1004          if (is_array($value)) {
1005              foreach ($value as $v) {
1006                  $services = array_unique(array_merge($services, self::getServiceConditionals($v)));
1007              }
1008          } elseif ($value instanceof Reference && $value->getInvalidBehavior() === ContainerInterface::IGNORE_ON_INVALID_REFERENCE) {
1009              $services[] = (string) $value;
1010          }
1011  
1012          return $services;
1013      }
1014  
1015      /**
1016       * Retrieves the currently set proxy instantiator or instantiates one.
1017       *
1018       * @return InstantiatorInterface
1019       */
1020      private function getProxyInstantiator()
1021      {
1022          if (!$this->proxyInstantiator) {
1023              $this->proxyInstantiator = new RealServiceInstantiator();
1024          }
1025  
1026          return $this->proxyInstantiator;
1027      }
1028  
1029      /**
1030       * Synchronizes a service change.
1031       *
1032       * This method updates all services that depend on the given
1033       * service by calling all methods referencing it.
1034       *
1035       * @param string $id A service id
1036       */
1037      private function synchronize($id)
1038      {
1039          foreach ($this->definitions as $definitionId => $definition) {
1040              // only check initialized services
1041              if (!$this->initialized($definitionId)) {
1042                  continue;
1043              }
1044  
1045              foreach ($definition->getMethodCalls() as $call) {
1046                  foreach ($call[1] as $argument) {
1047                      if ($argument instanceof Reference && $id == (string) $argument) {
1048                          $this->callMethod($this->get($definitionId), $call);
1049                      }
1050                  }
1051              }
1052          }
1053      }
1054  
1055      private function callMethod($service, $call)
1056      {
1057          $services = self::getServiceConditionals($call[1]);
1058  
1059          foreach ($services as $s) {
1060              if (!$this->has($s)) {
1061                  return;
1062              }
1063          }
1064  
1065          call_user_func_array(array($service, $call[0]), $this->resolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1]))));
1066      }
1067  
1068      /**
1069       * Shares a given service in the container.
1070       *
1071       * @param Definition $definition
1072       * @param mixed      $service
1073       * @param string     $id
1074       *
1075       * @throws InactiveScopeException
1076       */
1077      private function shareService(Definition $definition, $service, $id)
1078      {
1079          if (self::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) {
1080              if (self::SCOPE_CONTAINER !== $scope && !isset($this->scopedServices[$scope])) {
1081                  throw new InactiveScopeException($id, $scope);
1082              }
1083  
1084              $this->services[$lowerId = strtolower($id)] = $service;
1085  
1086              if (self::SCOPE_CONTAINER !== $scope) {
1087                  $this->scopedServices[$scope][$lowerId] = $service;
1088              }
1089          }
1090      }
1091  }


Generated: Thu Jan 11 00:25:41 2018 Cross-referenced by PHPXref 0.7.1