Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
88.24% |
15 / 17 |
CRAP | |
96.53% |
139 / 144 |
| OptimizedPhpArrayDumper | |
0.00% |
0 / 1 |
|
88.24% |
15 / 17 |
64 | |
96.53% |
139 / 144 |
| dump | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| getArray | |
100.00% |
1 / 1 |
1 | |
100.00% |
7 / 7 |
|||
| getAliases | |
100.00% |
1 / 1 |
3 | |
100.00% |
8 / 8 |
|||
| getParameters | |
100.00% |
1 / 1 |
2 | |
100.00% |
5 / 5 |
|||
| getServiceDefinitions | |
100.00% |
1 / 1 |
5 | |
100.00% |
8 / 8 |
|||
| prepareParameters | |
0.00% |
0 / 1 |
5.05 | |
87.50% |
7 / 8 |
|||
| escape | |
100.00% |
1 / 1 |
4 | |
100.00% |
8 / 8 |
|||
| getServiceDefinition | |
100.00% |
1 / 1 |
14 | |
100.00% |
31 / 31 |
|||
| dumpMethodCalls | |
100.00% |
1 / 1 |
3 | |
100.00% |
8 / 8 |
|||
| dumpCollection | |
100.00% |
1 / 1 |
6 | |
100.00% |
15 / 15 |
|||
| dumpCallable | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
|||
| getPrivateServiceCall | |
100.00% |
1 / 1 |
2 | |
100.00% |
8 / 8 |
|||
| dumpValue | |
0.00% |
0 / 1 |
10.80 | |
80.00% |
16 / 20 |
|||
| getReferenceCall | |
100.00% |
1 / 1 |
3 | |
100.00% |
7 / 7 |
|||
| getServiceCall | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
| getParameterCall | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| supportsMachineFormat | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| <?php | |
| /** | |
| * @file | |
| * Contains \Drupal\Component\DependencyInjection\Dumper\OptimizedPhpArrayDumper. | |
| */ | |
| namespace Drupal\Component\DependencyInjection\Dumper; | |
| use Symfony\Component\DependencyInjection\ContainerInterface; | |
| use Symfony\Component\DependencyInjection\Definition; | |
| use Symfony\Component\DependencyInjection\Parameter; | |
| use Symfony\Component\DependencyInjection\Reference; | |
| use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; | |
| use Symfony\Component\DependencyInjection\Exception\RuntimeException; | |
| use Symfony\Component\DependencyInjection\Dumper\Dumper; | |
| use Symfony\Component\ExpressionLanguage\Expression; | |
| /** | |
| * OptimizedPhpArrayDumper dumps a service container as a serialized PHP array. | |
| * | |
| * The format of this dumper is very similar to the internal structure of the | |
| * ContainerBuilder, but based on PHP arrays and \stdClass objects instead of | |
| * rich value objects for performance reasons. | |
| * | |
| * By removing the abstraction and optimizing some cases like deep collections, | |
| * fewer classes need to be loaded, fewer function calls need to be executed and | |
| * fewer run time checks need to be made. | |
| * | |
| * In addition to that, this container dumper treats private services as | |
| * strictly private with their own private services storage, whereas in the | |
| * Symfony service container builder and PHP dumper, shared private services can | |
| * still be retrieved via get() from the container. | |
| * | |
| * It is machine-optimized, for a human-readable version based on this one see | |
| * \Drupal\Component\DependencyInjection\Dumper\PhpArrayDumper. | |
| * | |
| * @see \Drupal\Component\DependencyInjection\Container | |
| */ | |
| class OptimizedPhpArrayDumper extends Dumper { | |
| /** | |
| * Whether to serialize service definitions or not. | |
| * | |
| * Service definitions are serialized by default to avoid having to | |
| * unserialize the whole container on loading time, which improves early | |
| * bootstrap performance for e.g. the page cache. | |
| * | |
| * @var bool | |
| */ | |
| protected $serialize = TRUE; | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function dump(array $options = array()) { | |
| return serialize($this->getArray()); | |
| } | |
| /** | |
| * Gets the service container definition as a PHP array. | |
| * | |
| * @return array | |
| * A PHP array representation of the service container. | |
| */ | |
| public function getArray() { | |
| $definition = array(); | |
| $definition['aliases'] = $this->getAliases(); | |
| $definition['parameters'] = $this->getParameters(); | |
| $definition['services'] = $this->getServiceDefinitions(); | |
| $definition['frozen'] = $this->container->isFrozen(); | |
| $definition['machine_format'] = $this->supportsMachineFormat(); | |
| return $definition; | |
| } | |
| /** | |
| * Gets the aliases as a PHP array. | |
| * | |
| * @return array | |
| * The aliases. | |
| */ | |
| protected function getAliases() { | |
| $alias_definitions = array(); | |
| $aliases = $this->container->getAliases(); | |
| foreach ($aliases as $alias => $id) { | |
| $id = (string) $id; | |
| while (isset($aliases[$id])) { | |
| $id = (string) $aliases[$id]; | |
| } | |
| $alias_definitions[$alias] = $id; | |
| } | |
| return $alias_definitions; | |
| } | |
| /** | |
| * Gets parameters of the container as a PHP array. | |
| * | |
| * @return array | |
| * The escaped and prepared parameters of the container. | |
| */ | |
| protected function getParameters() { | |
| if (!$this->container->getParameterBag()->all()) { | |
| return array(); | |
| } | |
| $parameters = $this->container->getParameterBag()->all(); | |
| $is_frozen = $this->container->isFrozen(); | |
| return $this->prepareParameters($parameters, $is_frozen); | |
| } | |
| /** | |
| * Gets services of the container as a PHP array. | |
| * | |
| * @return array | |
| * The service definitions. | |
| */ | |
| protected function getServiceDefinitions() { | |
| if (!$this->container->getDefinitions()) { | |
| return array(); | |
| } | |
| $services = array(); | |
| foreach ($this->container->getDefinitions() as $id => $definition) { | |
| // Only store public service definitions, references to shared private | |
| // services are handled in ::getReferenceCall(). | |
| if ($definition->isPublic()) { | |
| $service_definition = $this->getServiceDefinition($definition); | |
| $services[$id] = $this->serialize ? serialize($service_definition) : $service_definition; | |
| } | |
| } | |
| return $services; | |
| } | |
| /** | |
| * Prepares parameters for the PHP array dumping. | |
| * | |
| * @param array $parameters | |
| * An array of parameters. | |
| * @param bool $escape | |
| * Whether keys with '%' should be escaped or not. | |
| * | |
| * @return array | |
| * An array of prepared parameters. | |
| */ | |
| protected function prepareParameters(array $parameters, $escape = TRUE) { | |
| $filtered = array(); | |
| foreach ($parameters as $key => $value) { | |
| if (is_array($value)) { | |
| $value = $this->prepareParameters($value, $escape); | |
| } | |
| elseif ($value instanceof Reference) { | |
| $value = $this->dumpValue($value); | |
| } | |
| $filtered[$key] = $value; | |
| } | |
| return $escape ? $this->escape($filtered) : $filtered; | |
| } | |
| /** | |
| * Escapes parameters. | |
| * | |
| * @param array $parameters | |
| * The parameters to escape for '%' characters. | |
| * | |
| * @return array | |
| * The escaped parameters. | |
| */ | |
| protected function escape(array $parameters) { | |
| $args = array(); | |
| foreach ($parameters as $key => $value) { | |
| if (is_array($value)) { | |
| $args[$key] = $this->escape($value); | |
| } | |
| elseif (is_string($value)) { | |
| $args[$key] = str_replace('%', '%%', $value); | |
| } | |
| else { | |
| $args[$key] = $value; | |
| } | |
| } | |
| return $args; | |
| } | |
| /** | |
| * Gets a service definition as PHP array. | |
| * | |
| * @param \Symfony\Component\DependencyInjection\Definition $definition | |
| * The definition to process. | |
| * | |
| * @return array | |
| * The service definition as PHP array. | |
| * | |
| * @throws \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException | |
| * Thrown when the definition is marked as decorated, or with an explicit | |
| * scope different from SCOPE_CONTAINER and SCOPE_PROTOTYPE. | |
| */ | |
| protected function getServiceDefinition(Definition $definition) { | |
| $service = array(); | |
| if ($definition->getClass()) { | |
| $service['class'] = $definition->getClass(); | |
| } | |
| if (!$definition->isPublic()) { | |
| $service['public'] = FALSE; | |
| } | |
| if ($definition->getFile()) { | |
| $service['file'] = $definition->getFile(); | |
| } | |
| if ($definition->isSynthetic()) { | |
| $service['synthetic'] = TRUE; | |
| } | |
| if ($definition->isLazy()) { | |
| $service['lazy'] = TRUE; | |
| } | |
| if ($definition->getArguments()) { | |
| $arguments = $definition->getArguments(); | |
| $service['arguments'] = $this->dumpCollection($arguments); | |
| $service['arguments_count'] = count($arguments); | |
| } | |
| else { | |
| $service['arguments_count'] = 0; | |
| } | |
| if ($definition->getProperties()) { | |
| $service['properties'] = $this->dumpCollection($definition->getProperties()); | |
| } | |
| if ($definition->getMethodCalls()) { | |
| $service['calls'] = $this->dumpMethodCalls($definition->getMethodCalls()); | |
| } | |
| if (($scope = $definition->getScope()) !== ContainerInterface::SCOPE_CONTAINER) { | |
| if ($scope === ContainerInterface::SCOPE_PROTOTYPE) { | |
| // Scope prototype has been replaced with 'shared' => FALSE. | |
| // This is a Symfony 2.8 forward compatibility fix. | |
| // Reference: https://github.com/symfony/symfony/blob/2.8/UPGRADE-2.8.md#dependencyinjection | |
| $service['shared'] = FALSE; | |
| } | |
| else { | |
| throw new InvalidArgumentException("The 'scope' definition is deprecated in Symfony 3.0 and not supported by Drupal 8."); | |
| } | |
| } | |
| if (($decorated = $definition->getDecoratedService()) !== NULL) { | |
| throw new InvalidArgumentException("The 'decorated' definition is not supported by the Drupal 8 run-time container. The Container Builder should have resolved that during the DecoratorServicePass compiler pass."); | |
| } | |
| if ($callable = $definition->getFactory()) { | |
| $service['factory'] = $this->dumpCallable($callable); | |
| } | |
| if ($callable = $definition->getConfigurator()) { | |
| $service['configurator'] = $this->dumpCallable($callable); | |
| } | |
| return $service; | |
| } | |
| /** | |
| * Dumps method calls to a PHP array. | |
| * | |
| * @param array $calls | |
| * An array of method calls. | |
| * | |
| * @return array | |
| * The PHP array representation of the method calls. | |
| */ | |
| protected function dumpMethodCalls(array $calls) { | |
| $code = array(); | |
| foreach ($calls as $key => $call) { | |
| $method = $call[0]; | |
| $arguments = array(); | |
| if (!empty($call[1])) { | |
| $arguments = $this->dumpCollection($call[1]); | |
| } | |
| $code[$key] = [$method, $arguments]; | |
| } | |
| return $code; | |
| } | |
| /** | |
| * Dumps a collection to a PHP array. | |
| * | |
| * @param mixed $collection | |
| * A collection to process. | |
| * @param bool &$resolve | |
| * Used for passing the information to the caller whether the given | |
| * collection needed to be resolved or not. This is used for optimizing | |
| * deep arrays that don't need to be traversed. | |
| * | |
| * @return \stdClass|array | |
| * The collection in a suitable format. | |
| */ | |
| protected function dumpCollection($collection, &$resolve = FALSE) { | |
| $code = array(); | |
| foreach ($collection as $key => $value) { | |
| if (is_array($value)) { | |
| $resolve_collection = FALSE; | |
| $code[$key] = $this->dumpCollection($value, $resolve_collection); | |
| if ($resolve_collection) { | |
| $resolve = TRUE; | |
| } | |
| } | |
| else { | |
| if (is_object($value)) { | |
| $resolve = TRUE; | |
| } | |
| $code[$key] = $this->dumpValue($value); | |
| } | |
| } | |
| if (!$resolve) { | |
| return $collection; | |
| } | |
| return (object) array( | |
| 'type' => 'collection', | |
| 'value' => $code, | |
| 'resolve' => $resolve, | |
| ); | |
| } | |
| /** | |
| * Dumps callable to a PHP array. | |
| * | |
| * @param array|callable $callable | |
| * The callable to process. | |
| * | |
| * @return callable | |
| * The processed callable. | |
| */ | |
| protected function dumpCallable($callable) { | |
| if (is_array($callable)) { | |
| $callable[0] = $this->dumpValue($callable[0]); | |
| $callable = array($callable[0], $callable[1]); | |
| } | |
| return $callable; | |
| } | |
| /** | |
| * Gets a private service definition in a suitable format. | |
| * | |
| * @param string $id | |
| * The ID of the service to get a private definition for. | |
| * @param \Symfony\Component\DependencyInjection\Definition $definition | |
| * The definition to process. | |
| * @param bool $shared | |
| * (optional) Whether the service will be shared with others. | |
| * By default this parameter is FALSE. | |
| * | |
| * @return \stdClass | |
| * A very lightweight private service value object. | |
| */ | |
| protected function getPrivateServiceCall($id, Definition $definition, $shared = FALSE) { | |
| $service_definition = $this->getServiceDefinition($definition); | |
| if (!$id) { | |
| $hash = hash('sha1', serialize($service_definition)); | |
| $id = 'private__' . $hash; | |
| } | |
| return (object) array( | |
| 'type' => 'private_service', | |
| 'id' => $id, | |
| 'value' => $service_definition, | |
| 'shared' => $shared, | |
| ); | |
| } | |
| /** | |
| * Dumps the value to PHP array format. | |
| * | |
| * @param mixed $value | |
| * The value to dump. | |
| * | |
| * @return mixed | |
| * The dumped value in a suitable format. | |
| * | |
| * @throws RuntimeException | |
| * When trying to dump object or resource. | |
| */ | |
| protected function dumpValue($value) { | |
| if (is_array($value)) { | |
| $code = array(); | |
| foreach ($value as $k => $v) { | |
| $code[$k] = $this->dumpValue($v); | |
| } | |
| return $code; | |
| } | |
| elseif ($value instanceof Reference) { | |
| return $this->getReferenceCall((string) $value, $value); | |
| } | |
| elseif ($value instanceof Definition) { | |
| return $this->getPrivateServiceCall(NULL, $value); | |
| } | |
| elseif ($value instanceof Parameter) { | |
| return $this->getParameterCall((string) $value); | |
| } | |
| elseif ($value instanceof Expression) { | |
| throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.'); | |
| } | |
| elseif (is_object($value)) { | |
| // Drupal specific: Instantiated objects have a _serviceId parameter. | |
| if (isset($value->_serviceId)) { | |
| return $this->getReferenceCall($value->_serviceId); | |
| } | |
| throw new RuntimeException('Unable to dump a service container if a parameter is an object without _serviceId.'); | |
| } | |
| elseif (is_resource($value)) { | |
| throw new RuntimeException('Unable to dump a service container if a parameter is a resource.'); | |
| } | |
| return $value; | |
| } | |
| /** | |
| * Gets a service reference for a reference in a suitable PHP array format. | |
| * | |
| * The main difference is that this function treats references to private | |
| * services differently and returns a private service reference instead of | |
| * a normal reference. | |
| * | |
| * @param string $id | |
| * The ID of the service to get a reference for. | |
| * @param \Symfony\Component\DependencyInjection\Reference|NULL $reference | |
| * (optional) The reference object to process; needed to get the invalid | |
| * behavior value. | |
| * | |
| * @return string|\stdClass | |
| * A suitable representation of the service reference. | |
| */ | |
| protected function getReferenceCall($id, Reference $reference = NULL) { | |
| $invalid_behavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; | |
| if ($reference !== NULL) { | |
| $invalid_behavior = $reference->getInvalidBehavior(); | |
| } | |
| // Private shared service. | |
| $definition = $this->container->getDefinition($id); | |
| if (!$definition->isPublic()) { | |
| // The ContainerBuilder does not share a private service, but this means a | |
| // new service is instantiated every time. Use a private shared service to | |
| // circumvent the problem. | |
| return $this->getPrivateServiceCall($id, $definition, TRUE); | |
| } | |
| return $this->getServiceCall($id, $invalid_behavior); | |
| } | |
| /** | |
| * Gets a service reference for an ID in a suitable PHP array format. | |
| * | |
| * @param string $id | |
| * The ID of the service to get a reference for. | |
| * @param int $invalid_behavior | |
| * (optional) The invalid behavior of the service. | |
| * | |
| * @return string|\stdClass | |
| * A suitable representation of the service reference. | |
| */ | |
| protected function getServiceCall($id, $invalid_behavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) { | |
| return (object) array( | |
| 'type' => 'service', | |
| 'id' => $id, | |
| 'invalidBehavior' => $invalid_behavior, | |
| ); | |
| } | |
| /** | |
| * Gets a parameter reference in a suitable PHP array format. | |
| * | |
| * @param string $name | |
| * The name of the parameter to get a reference for. | |
| * | |
| * @return string|\stdClass | |
| * A suitable representation of the parameter reference. | |
| */ | |
| protected function getParameterCall($name) { | |
| return (object) array( | |
| 'type' => 'parameter', | |
| 'name' => $name, | |
| ); | |
| } | |
| /** | |
| * Whether this supports the machine-optimized format or not. | |
| * | |
| * @return bool | |
| * TRUE if this supports machine-optimized format, FALSE otherwise. | |
| */ | |
| protected function supportsMachineFormat() { | |
| return TRUE; | |
| } | |
| } |