Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
66.67% |
2 / 3 |
CRAP | |
92.44% |
110 / 119 |
| PhpArrayContainer | |
0.00% |
0 / 1 |
|
66.67% |
2 / 3 |
57.36 | |
92.44% |
110 / 119 |
| __construct | |
100.00% |
1 / 1 |
7 | |
100.00% |
8 / 8 |
|||
| createService | |
0.00% |
0 / 1 |
35.92 | |
88.16% |
67 / 76 |
|||
| resolveServicesAndParameters | |
100.00% |
1 / 1 |
15 | |
100.00% |
35 / 35 |
|||
| <?php | |
| /** | |
| * @file | |
| * Contains \Drupal\Component\DependencyInjection\PhpArrayContainer. | |
| */ | |
| namespace Drupal\Component\DependencyInjection; | |
| use Symfony\Component\DependencyInjection\ContainerInterface; | |
| use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; | |
| use Symfony\Component\DependencyInjection\Exception\RuntimeException; | |
| /** | |
| * Provides a container optimized for Drupal's needs. | |
| * | |
| * This container implementation is compatible with the default Symfony | |
| * dependency injection container and similar to the Symfony ContainerBuilder | |
| * class, but optimized for speed. | |
| * | |
| * It is based on a human-readable PHP array container definition with a | |
| * structure very similar to the YAML container definition. | |
| * | |
| * @see \Drupal\Component\DependencyInjection\Container | |
| * @see \Drupal\Component\DependencyInjection\Dumper\PhpArrayDumper | |
| * @see \Drupal\Component\DependencyInjection\DependencySerializationTrait | |
| * | |
| * @ingroup container | |
| */ | |
| class PhpArrayContainer extends Container { | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function __construct(array $container_definition = array()) { | |
| if (isset($container_definition['machine_format']) && $container_definition['machine_format'] === TRUE) { | |
| throw new InvalidArgumentException('The machine-optimized format is not supported by this class. Use a human-readable format instead, e.g. as produced by \Drupal\Component\DependencyInjection\Dumper\PhpArrayDumper.'); | |
| } | |
| // Do not call the parent's constructor as it would bail on the | |
| // machine-optimized format. | |
| $this->aliases = isset($container_definition['aliases']) ? $container_definition['aliases'] : array(); | |
| $this->parameters = isset($container_definition['parameters']) ? $container_definition['parameters'] : array(); | |
| $this->serviceDefinitions = isset($container_definition['services']) ? $container_definition['services'] : array(); | |
| $this->frozen = isset($container_definition['frozen']) ? $container_definition['frozen'] : FALSE; | |
| // Register the service_container with itself. | |
| $this->services['service_container'] = $this; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| protected function createService(array $definition, $id) { | |
| // This method is a verbatim copy of | |
| // \Drupal\Component\DependencyInjection\Container::createService | |
| // except for the following difference: | |
| // - There are no instanceof checks on \stdClass, which are used in the | |
| // parent class to avoid resolving services and parameters when it is | |
| // known from dumping that there is nothing to resolve. | |
| if (isset($definition['synthetic']) && $definition['synthetic'] === TRUE) { | |
| 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)); | |
| } | |
| $arguments = array(); | |
| if (isset($definition['arguments'])) { | |
| $arguments = $this->resolveServicesAndParameters($definition['arguments']); | |
| } | |
| if (isset($definition['file'])) { | |
| $file = $this->frozen ? $definition['file'] : current($this->resolveServicesAndParameters(array($definition['file']))); | |
| require_once $file; | |
| } | |
| if (isset($definition['factory'])) { | |
| $factory = $definition['factory']; | |
| if (is_array($factory)) { | |
| $factory = $this->resolveServicesAndParameters(array($factory[0], $factory[1])); | |
| } | |
| elseif (!is_string($factory)) { | |
| throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id)); | |
| } | |
| $service = call_user_func_array($factory, $arguments); | |
| } | |
| else { | |
| $class = $this->frozen ? $definition['class'] : current($this->resolveServicesAndParameters(array($definition['class']))); | |
| $length = isset($definition['arguments_count']) ? $definition['arguments_count'] : count($arguments); | |
| // Optimize class instantiation for services with up to 10 parameters as | |
| // reflection is noticeably slow. | |
| switch ($length) { | |
| case 0: | |
| $service = new $class(); | |
| break; | |
| case 1: | |
| $service = new $class($arguments[0]); | |
| break; | |
| case 2: | |
| $service = new $class($arguments[0], $arguments[1]); | |
| break; | |
| case 3: | |
| $service = new $class($arguments[0], $arguments[1], $arguments[2]); | |
| break; | |
| case 4: | |
| $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3]); | |
| break; | |
| case 5: | |
| $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4]); | |
| break; | |
| case 6: | |
| $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5]); | |
| break; | |
| case 7: | |
| $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6]); | |
| break; | |
| case 8: | |
| $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6], $arguments[7]); | |
| break; | |
| case 9: | |
| $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6], $arguments[7], $arguments[8]); | |
| break; | |
| case 10: | |
| $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6], $arguments[7], $arguments[8], $arguments[9]); | |
| break; | |
| default: | |
| $r = new \ReflectionClass($class); | |
| $service = $r->newInstanceArgs($arguments); | |
| break; | |
| } | |
| } | |
| // Share the service if it is public. | |
| if (!isset($definition['public']) || $definition['public'] !== FALSE) { | |
| // Forward compatibility fix for Symfony 2.8 update. | |
| if (!isset($definition['shared']) || $definition['shared'] !== FALSE) { | |
| $this->services[$id] = $service; | |
| } | |
| } | |
| if (isset($definition['calls'])) { | |
| foreach ($definition['calls'] as $call) { | |
| $method = $call[0]; | |
| $arguments = array(); | |
| if (!empty($call[1])) { | |
| $arguments = $call[1]; | |
| $arguments = $this->resolveServicesAndParameters($arguments); | |
| } | |
| call_user_func_array(array($service, $method), $arguments); | |
| } | |
| } | |
| if (isset($definition['properties'])) { | |
| $definition['properties'] = $this->resolveServicesAndParameters($definition['properties']); | |
| foreach ($definition['properties'] as $key => $value) { | |
| $service->{$key} = $value; | |
| } | |
| } | |
| if (isset($definition['configurator'])) { | |
| $callable = $definition['configurator']; | |
| if (is_array($callable)) { | |
| $callable = $this->resolveServicesAndParameters($callable); | |
| } | |
| if (!is_callable($callable)) { | |
| throw new InvalidArgumentException(sprintf('The configurator for class "%s" is not a callable.', get_class($service))); | |
| } | |
| call_user_func($callable, $service); | |
| } | |
| return $service; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| protected function resolveServicesAndParameters($arguments) { | |
| // This method is different from the parent method only for the following | |
| // cases: | |
| // - A service is denoted by '@service' and not by a \stdClass object. | |
| // - A parameter is denoted by '%parameter%' and not by a \stdClass object. | |
| // - The depth of the tree representing the arguments is not known in | |
| // advance, so it needs to be fully traversed recursively. | |
| foreach ($arguments as $key => $argument) { | |
| if ($argument instanceof \stdClass) { | |
| $type = $argument->type; | |
| // Private services are a special flavor: In case a private service is | |
| // only used by one other service, the ContainerBuilder uses a | |
| // Definition object as an argument, which does not have an ID set. | |
| // Therefore the format uses a \stdClass object to store the definition | |
| // and to be able to create the service on the fly. | |
| // | |
| // Note: When constructing a private service by hand, 'id' must be set. | |
| // | |
| // The PhpArrayDumper just uses the hash of the private service | |
| // definition to generate a unique ID. | |
| // | |
| // @see \Drupal\Component\DependecyInjection\Dumper\OptimizedPhpArrayDumper::getPrivateServiceCall | |
| if ($type == 'private_service') { | |
| $id = $argument->id; | |
| // Check if the private service already exists - in case it is shared. | |
| if (!empty($argument->shared) && isset($this->privateServices[$id])) { | |
| $arguments[$key] = $this->privateServices[$id]; | |
| continue; | |
| } | |
| // Create a private service from a service definition. | |
| $arguments[$key] = $this->createService($argument->value, $id); | |
| if (!empty($argument->shared)) { | |
| $this->privateServices[$id] = $arguments[$key]; | |
| } | |
| continue; | |
| } | |
| if ($type !== NULL) { | |
| throw new InvalidArgumentException("Undefined type '$type' while resolving parameters and services."); | |
| } | |
| } | |
| if (is_array($argument)) { | |
| $arguments[$key] = $this->resolveServicesAndParameters($argument); | |
| continue; | |
| } | |
| if (!is_string($argument)) { | |
| continue; | |
| } | |
| // Resolve parameters. | |
| if ($argument[0] === '%') { | |
| $name = substr($argument, 1, -1); | |
| if (!isset($this->parameters[$name])) { | |
| $arguments[$key] = $this->getParameter($name); | |
| // This can never be reached as getParameter() throws an Exception, | |
| // because we already checked that the parameter is not set above. | |
| } | |
| $argument = $this->parameters[$name]; | |
| $arguments[$key] = $argument; | |
| } | |
| // Resolve services. | |
| if ($argument[0] === '@') { | |
| $id = substr($argument, 1); | |
| $invalid_behavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; | |
| if ($id[0] === '?') { | |
| $id = substr($id, 1); | |
| $invalid_behavior = ContainerInterface::NULL_ON_INVALID_REFERENCE; | |
| } | |
| if (isset($this->services[$id])) { | |
| $arguments[$key] = $this->services[$id]; | |
| } | |
| else { | |
| $arguments[$key] = $this->get($id, $invalid_behavior); | |
| } | |
| } | |
| } | |
| return $arguments; | |
| } | |
| } |