Chris@0: aliases = isset($container_definition['aliases']) ? $container_definition['aliases'] : []; Chris@0: $this->parameters = isset($container_definition['parameters']) ? $container_definition['parameters'] : []; Chris@0: $this->serviceDefinitions = isset($container_definition['services']) ? $container_definition['services'] : []; Chris@0: $this->frozen = isset($container_definition['frozen']) ? $container_definition['frozen'] : FALSE; Chris@0: Chris@0: // Register the service_container with itself. Chris@0: $this->services['service_container'] = $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: protected function createService(array $definition, $id) { Chris@0: // This method is a verbatim copy of Chris@0: // \Drupal\Component\DependencyInjection\Container::createService Chris@0: // except for the following difference: Chris@0: // - There are no instanceof checks on \stdClass, which are used in the Chris@0: // parent class to avoid resolving services and parameters when it is Chris@0: // known from dumping that there is nothing to resolve. Chris@0: if (isset($definition['synthetic']) && $definition['synthetic'] === TRUE) { Chris@0: throw new RuntimeException(sprintf('You have requested a synthetic service ("%s"). The service container does not know how to construct this service. The service will need to be set before it is first used.', $id)); Chris@0: } Chris@0: Chris@0: $arguments = []; Chris@0: if (isset($definition['arguments'])) { Chris@0: $arguments = $this->resolveServicesAndParameters($definition['arguments']); Chris@0: } Chris@0: Chris@0: if (isset($definition['file'])) { Chris@0: $file = $this->frozen ? $definition['file'] : current($this->resolveServicesAndParameters([$definition['file']])); Chris@0: require_once $file; Chris@0: } Chris@0: Chris@0: if (isset($definition['factory'])) { Chris@0: $factory = $definition['factory']; Chris@0: if (is_array($factory)) { Chris@0: $factory = $this->resolveServicesAndParameters([$factory[0], $factory[1]]); Chris@0: } Chris@0: elseif (!is_string($factory)) { Chris@0: throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id)); Chris@0: } Chris@0: Chris@0: $service = call_user_func_array($factory, $arguments); Chris@0: } Chris@0: else { Chris@0: $class = $this->frozen ? $definition['class'] : current($this->resolveServicesAndParameters([$definition['class']])); Chris@0: $length = isset($definition['arguments_count']) ? $definition['arguments_count'] : count($arguments); Chris@0: Chris@0: // Optimize class instantiation for services with up to 10 parameters as Chris@0: // reflection is noticeably slow. Chris@0: switch ($length) { Chris@0: case 0: Chris@0: $service = new $class(); Chris@0: break; Chris@0: Chris@0: case 1: Chris@0: $service = new $class($arguments[0]); Chris@0: break; Chris@0: Chris@0: case 2: Chris@0: $service = new $class($arguments[0], $arguments[1]); Chris@0: break; Chris@0: Chris@0: case 3: Chris@0: $service = new $class($arguments[0], $arguments[1], $arguments[2]); Chris@0: break; Chris@0: Chris@0: case 4: Chris@0: $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3]); Chris@0: break; Chris@0: Chris@0: case 5: Chris@0: $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4]); Chris@0: break; Chris@0: Chris@0: case 6: Chris@0: $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5]); Chris@0: break; Chris@0: Chris@0: case 7: Chris@0: $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6]); Chris@0: break; Chris@0: Chris@0: case 8: Chris@0: $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6], $arguments[7]); Chris@0: break; Chris@0: Chris@0: case 9: Chris@0: $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6], $arguments[7], $arguments[8]); Chris@0: break; Chris@0: Chris@0: case 10: Chris@0: $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6], $arguments[7], $arguments[8], $arguments[9]); Chris@0: break; Chris@0: Chris@0: default: Chris@0: $r = new \ReflectionClass($class); Chris@0: $service = $r->newInstanceArgs($arguments); Chris@0: break; Chris@0: } Chris@0: } Chris@0: Chris@0: if (!isset($definition['shared']) || $definition['shared'] !== FALSE) { Chris@0: $this->services[$id] = $service; Chris@0: } Chris@0: Chris@0: if (isset($definition['calls'])) { Chris@0: foreach ($definition['calls'] as $call) { Chris@0: $method = $call[0]; Chris@0: $arguments = []; Chris@0: if (!empty($call[1])) { Chris@0: $arguments = $call[1]; Chris@0: $arguments = $this->resolveServicesAndParameters($arguments); Chris@0: } Chris@0: call_user_func_array([$service, $method], $arguments); Chris@0: } Chris@0: } Chris@0: Chris@0: if (isset($definition['properties'])) { Chris@0: $definition['properties'] = $this->resolveServicesAndParameters($definition['properties']); Chris@0: foreach ($definition['properties'] as $key => $value) { Chris@0: $service->{$key} = $value; Chris@0: } Chris@0: } Chris@0: Chris@0: if (isset($definition['configurator'])) { Chris@0: $callable = $definition['configurator']; Chris@0: if (is_array($callable)) { Chris@0: $callable = $this->resolveServicesAndParameters($callable); Chris@0: } Chris@0: Chris@0: if (!is_callable($callable)) { Chris@0: throw new InvalidArgumentException(sprintf('The configurator for class "%s" is not a callable.', get_class($service))); Chris@0: } Chris@0: Chris@0: call_user_func($callable, $service); Chris@0: } Chris@0: Chris@0: return $service; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: protected function resolveServicesAndParameters($arguments) { Chris@0: // This method is different from the parent method only for the following Chris@0: // cases: Chris@0: // - A service is denoted by '@service' and not by a \stdClass object. Chris@0: // - A parameter is denoted by '%parameter%' and not by a \stdClass object. Chris@0: // - The depth of the tree representing the arguments is not known in Chris@0: // advance, so it needs to be fully traversed recursively. Chris@0: foreach ($arguments as $key => $argument) { Chris@0: if ($argument instanceof \stdClass) { Chris@0: $type = $argument->type; Chris@0: Chris@0: // Private services are a special flavor: In case a private service is Chris@0: // only used by one other service, the ContainerBuilder uses a Chris@0: // Definition object as an argument, which does not have an ID set. Chris@0: // Therefore the format uses a \stdClass object to store the definition Chris@0: // and to be able to create the service on the fly. Chris@0: // Chris@0: // Note: When constructing a private service by hand, 'id' must be set. Chris@0: // Chris@0: // The PhpArrayDumper just uses the hash of the private service Chris@0: // definition to generate a unique ID. Chris@0: // Chris@17: // @see \Drupal\Component\DependencyInjection\Dumper\OptimizedPhpArrayDumper::getPrivateServiceCall Chris@0: if ($type == 'private_service') { Chris@0: $id = $argument->id; Chris@0: Chris@0: // Check if the private service already exists - in case it is shared. Chris@0: if (!empty($argument->shared) && isset($this->privateServices[$id])) { Chris@0: $arguments[$key] = $this->privateServices[$id]; Chris@0: continue; Chris@0: } Chris@0: Chris@0: // Create a private service from a service definition. Chris@0: $arguments[$key] = $this->createService($argument->value, $id); Chris@0: if (!empty($argument->shared)) { Chris@0: $this->privateServices[$id] = $arguments[$key]; Chris@0: } Chris@0: Chris@0: continue; Chris@0: } Chris@0: Chris@0: if ($type !== NULL) { Chris@0: throw new InvalidArgumentException("Undefined type '$type' while resolving parameters and services."); Chris@0: } Chris@0: } Chris@0: Chris@0: if (is_array($argument)) { Chris@0: $arguments[$key] = $this->resolveServicesAndParameters($argument); Chris@0: continue; Chris@0: } Chris@0: Chris@0: if (!is_string($argument)) { Chris@0: continue; Chris@0: } Chris@0: Chris@0: // Resolve parameters. Chris@0: if ($argument[0] === '%') { Chris@0: $name = substr($argument, 1, -1); Chris@0: if (!isset($this->parameters[$name])) { Chris@0: $arguments[$key] = $this->getParameter($name); Chris@0: // This can never be reached as getParameter() throws an Exception, Chris@0: // because we already checked that the parameter is not set above. Chris@0: } Chris@0: $argument = $this->parameters[$name]; Chris@0: $arguments[$key] = $argument; Chris@0: } Chris@0: Chris@0: // Resolve services. Chris@0: if ($argument[0] === '@') { Chris@0: $id = substr($argument, 1); Chris@0: $invalid_behavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; Chris@0: if ($id[0] === '?') { Chris@0: $id = substr($id, 1); Chris@0: $invalid_behavior = ContainerInterface::NULL_ON_INVALID_REFERENCE; Chris@0: } Chris@0: if (isset($this->services[$id])) { Chris@0: $arguments[$key] = $this->services[$id]; Chris@0: } Chris@0: else { Chris@0: $arguments[$key] = $this->get($id, $invalid_behavior); Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: return $arguments; Chris@0: } Chris@0: Chris@0: }