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 12namespace Symfony\Component\DependencyInjection\Loader\Configurator; 13 14use Symfony\Component\DependencyInjection\Alias; 15use Symfony\Component\DependencyInjection\ChildDefinition; 16use Symfony\Component\DependencyInjection\ContainerBuilder; 17use Symfony\Component\DependencyInjection\Definition; 18use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; 19use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; 20 21/** 22 * @author Nicolas Grekas <p@tchwork.com> 23 */ 24class ServicesConfigurator extends AbstractConfigurator 25{ 26 const FACTORY = 'services'; 27 28 private $defaults; 29 private $container; 30 private $loader; 31 private $instanceof; 32 private $path; 33 private $anonymousHash; 34 private $anonymousCount; 35 36 public function __construct(ContainerBuilder $container, PhpFileLoader $loader, array &$instanceof, string $path = null, int &$anonymousCount = 0) 37 { 38 $this->defaults = new Definition(); 39 $this->container = $container; 40 $this->loader = $loader; 41 $this->instanceof = &$instanceof; 42 $this->path = $path; 43 $this->anonymousHash = ContainerBuilder::hash($path ?: mt_rand()); 44 $this->anonymousCount = &$anonymousCount; 45 $instanceof = []; 46 } 47 48 /** 49 * Defines a set of defaults for following service definitions. 50 */ 51 final public function defaults(): DefaultsConfigurator 52 { 53 return new DefaultsConfigurator($this, $this->defaults = new Definition(), $this->path); 54 } 55 56 /** 57 * Defines an instanceof-conditional to be applied to following service definitions. 58 */ 59 final public function instanceof(string $fqcn): InstanceofConfigurator 60 { 61 $this->instanceof[$fqcn] = $definition = new ChildDefinition(''); 62 63 return new InstanceofConfigurator($this, $definition, $fqcn, $this->path); 64 } 65 66 /** 67 * Registers a service. 68 * 69 * @param string|null $id The service id, or null to create an anonymous service 70 * @param string|null $class The class of the service, or null when $id is also the class name 71 */ 72 final public function set(?string $id, string $class = null): ServiceConfigurator 73 { 74 $defaults = $this->defaults; 75 $allowParent = !$defaults->getChanges() && empty($this->instanceof); 76 77 $definition = new Definition(); 78 79 if (null === $id) { 80 if (!$class) { 81 throw new \LogicException('Anonymous services must have a class name.'); 82 } 83 84 $id = sprintf('.%d_%s', ++$this->anonymousCount, preg_replace('/^.*\\\\/', '', $class).'~'.$this->anonymousHash); 85 $definition->setPublic(false); 86 } else { 87 $definition->setPublic($defaults->isPublic()); 88 } 89 90 $definition->setAutowired($defaults->isAutowired()); 91 $definition->setAutoconfigured($defaults->isAutoconfigured()); 92 $definition->setBindings($defaults->getBindings()); 93 $definition->setChanges([]); 94 95 $configurator = new ServiceConfigurator($this->container, $this->instanceof, $allowParent, $this, $definition, $id, $defaults->getTags(), $this->path); 96 97 return null !== $class ? $configurator->class($class) : $configurator; 98 } 99 100 /** 101 * Creates an alias. 102 */ 103 final public function alias(string $id, string $referencedId): AliasConfigurator 104 { 105 $ref = static::processValue($referencedId, true); 106 $alias = new Alias((string) $ref, $this->defaults->isPublic()); 107 $this->container->setAlias($id, $alias); 108 109 return new AliasConfigurator($this, $alias); 110 } 111 112 /** 113 * Registers a PSR-4 namespace using a glob pattern. 114 */ 115 final public function load(string $namespace, string $resource): PrototypeConfigurator 116 { 117 $allowParent = !$this->defaults->getChanges() && empty($this->instanceof); 118 119 return new PrototypeConfigurator($this, $this->loader, $this->defaults, $namespace, $resource, $allowParent); 120 } 121 122 /** 123 * Gets an already defined service definition. 124 * 125 * @throws ServiceNotFoundException if the service definition does not exist 126 */ 127 final public function get(string $id): ServiceConfigurator 128 { 129 $allowParent = !$this->defaults->getChanges() && empty($this->instanceof); 130 $definition = $this->container->getDefinition($id); 131 132 return new ServiceConfigurator($this->container, $definition->getInstanceofConditionals(), $allowParent, $this, $definition, $id, []); 133 } 134 135 /** 136 * Registers a service. 137 */ 138 final public function __invoke(string $id, string $class = null): ServiceConfigurator 139 { 140 return $this->set($id, $class); 141 } 142 143 public function __destruct() 144 { 145 $this->loader->registerAliasesForSinglyImplementedInterfaces(); 146 } 147} 148