Code Coverage  | 
     ||||||||||
Classes and Traits  | 
      Functions and Methods  | 
      Lines  | 
     ||||||||
| Total |         | 
      0.00%  | 
      0 / 1  | 
              | 
      80.00%  | 
      8 / 10  | 
      CRAP |         | 
      91.58%  | 
      87 / 95  | 
     
| ProxyBuilder |         | 
      0.00%  | 
      0 / 1  | 
              | 
      80.00%  | 
      8 / 10  | 
      33.65 |         | 
      91.58%  | 
      87 / 95  | 
     
| buildProxyClassName |         | 
      100.00%  | 
      1 / 1  | 
      1 |         | 
      100.00%  | 
      6 / 6  | 
     |||
| buildProxyNamespace |         | 
      100.00%  | 
      1 / 1  | 
      1 |         | 
      100.00%  | 
      4 / 4  | 
     |||
| build |         | 
      0.00%  | 
      0 / 1  | 
      14.23 |         | 
      80.65%  | 
      25 / 31  | 
     |||
| anonymous function |         | 
      100.00%  | 
      1 / 1  | 
      2 |         | 
      100.00%  | 
      4 / 4  | 
     |||
| buildLazyLoadItselfMethod |         | 
      100.00%  | 
      1 / 1  | 
      1 |         | 
      100.00%  | 
      1 / 1  | 
     |||
| buildMethod |         | 
      100.00%  | 
      1 / 1  | 
      4 |         | 
      100.00%  | 
      16 / 16  | 
     |||
| buildParameter |         | 
      100.00%  | 
      1 / 1  | 
      6 |         | 
      100.00%  | 
      14 / 14  | 
     |||
| buildMethodBody |         | 
      100.00%  | 
      1 / 1  | 
      3 |         | 
      100.00%  | 
      11 / 11  | 
     |||
| buildConstructorMethod |         | 
      100.00%  | 
      1 / 1  | 
      1 |         | 
      100.00%  | 
      1 / 1  | 
     |||
| buildUseStatements |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 2  | 
     |||
| <?php | |
| /** | |
| * @file | |
| * Contains \Drupal\Component\ProxyBuilder\ProxyBuilder. | |
| */ | |
| namespace Drupal\Component\ProxyBuilder; | |
| /** | |
| * Generates the string representation of the proxy service. | |
| */ | |
| class ProxyBuilder { | |
| /** | |
| * Generates the used proxy class name from a given class name. | |
| * | |
| * @param string $class_name | |
| * The class name of the actual service. | |
| * | |
| * @return string | |
| * The class name of the proxy. | |
| */ | |
| public static function buildProxyClassName($class_name) { | |
| $match = []; | |
| preg_match('/([a-zA-Z0-9_]+\\\\[a-zA-Z0-9_]+)\\\\(.+)/', $class_name, $match); | |
| $root_namespace = $match[1]; | |
| $rest_fqcn = $match[2]; | |
| $proxy_class_name = $root_namespace . '\\ProxyClass\\' . $rest_fqcn; | |
| return $proxy_class_name; | |
| } | |
| /** | |
| * Generates the used proxy namespace from a given class name. | |
| * | |
| * @param string $class_name | |
| * The class name of the actual service. | |
| * | |
| * @return string | |
| * The namespace name of the proxy. | |
| */ | |
| public static function buildProxyNamespace($class_name) { | |
| $proxy_classname = static::buildProxyClassName($class_name); | |
| preg_match('/(.+)\\\\[a-zA-Z0-9]+/', $proxy_classname, $match); | |
| $proxy_namespace = $match[1]; | |
| return $proxy_namespace; | |
| } | |
| /** | |
| * Builds a proxy class string. | |
| * | |
| * @param string $class_name | |
| * The class name of the actual service. | |
| * @param string $proxy_class_name | |
| * (optional) The class name of the proxy service. | |
| * | |
| * @return string | |
| * The full string with namespace class and methods. | |
| */ | |
| public function build($class_name, $proxy_class_name = '') { | |
| $reflection = new \ReflectionClass($class_name); | |
| if ($proxy_class_name) { | |
| $proxy_class_reflection = new \ReflectionClass($proxy_class_name); | |
| $proxy_namespace = $proxy_class_reflection->getNamespaceName(); | |
| } | |
| else { | |
| $proxy_class_name = $this->buildProxyClassName($class_name); | |
| $proxy_namespace = $this->buildProxyNamespace($class_name); | |
| $proxy_class_shortname = str_replace($proxy_namespace . '\\', '', $proxy_class_name); | |
| } | |
| $output = ''; | |
| $class_documentation = <<<'EOS' | |
| namespace {{ namespace }}{ | |
| /** | |
| * Provides a proxy class for \{{ class_name }}. | |
| * | |
| * @see \Drupal\Component\ProxyBuilder | |
| */ | |
| EOS; | |
| $class_start = ' class {{ proxy_class_shortname }}'; | |
| // For cases in which the implemented interface is a child of another | |
| // interface, getInterfaceNames() also returns the parent. This causes a | |
| // PHP error. | |
| // In order to avoid that, check for each interface, whether one of its | |
| // parents is also in the list and exclude it. | |
| if ($interfaces = $reflection->getInterfaces()) { | |
| foreach ($interfaces as $interface_name => $interface) { | |
| // Exclude all parents from the list of implemented interfaces of the | |
| // class. | |
| if ($parent_interfaces = $interface->getInterfaceNames()) { | |
| foreach ($parent_interfaces as $parent_interface) { | |
| if (isset($interfaces[$parent_interface])) {} | |
| unset($interfaces[$parent_interface]); | |
| } | |
| } | |
| } | |
| $interface_names = []; | |
| foreach ($interfaces as $interface) { | |
| $interface_names[] = '\\' . $interface->getName(); | |
| } | |
| $class_start .= ' implements ' . implode(', ', $interface_names); | |
| } | |
| $output .= $this->buildUseStatements(); | |
| // The actual class; | |
| $properties = <<<'EOS' | |
| /** | |
| * The id of the original proxied service. | |
| * | |
| * @var string | |
| */ | |
| protected $drupalProxyOriginalServiceId; | |
| /** | |
| * The real proxied service, after it was lazy loaded. | |
| * | |
| * @var \{{ class_name }} | |
| */ | |
| protected $service; | |
| /** | |
| * The service container. | |
| * | |
| * @var \Symfony\Component\DependencyInjection\ContainerInterface | |
| */ | |
| protected $container; | |
| EOS; | |
| $output .= $properties; | |
| // Add all the methods. | |
| $methods = []; | |
| $methods[] = $this->buildConstructorMethod(); | |
| $methods[] = $this->buildLazyLoadItselfMethod(); | |
| // Add all the methods of the proxied service. | |
| $reflection_methods = $reflection->getMethods(); | |
| foreach ($reflection_methods as $method) { | |
| if ($method->getName() === '__construct') { | |
| continue; | |
| } | |
| if ($method->isPublic()) { | |
| $methods[] = $this->buildMethod($method) . "\n"; | |
| } | |
| } | |
| $output .= implode("\n", $methods); | |
| // Indent the output. | |
| $output = implode("\n", array_map(function ($value) { | |
| if ($value === '') { | |
| return $value; | |
| } | |
| return " $value"; | |
| }, explode("\n", $output))); | |
| $final_output = $class_documentation . $class_start . "\n {\n\n" . $output . "\n }\n\n}\n"; | |
| $final_output = str_replace('{{ class_name }}', $class_name, $final_output); | |
| $final_output = str_replace('{{ namespace }}', $proxy_namespace ? $proxy_namespace . ' ' : '', $final_output); | |
| $final_output = str_replace('{{ proxy_class_shortname }}', $proxy_class_shortname, $final_output); | |
| return $final_output; | |
| } | |
| /** | |
| * Generates the string for the method which loads the actual service. | |
| * | |
| * @return string | |
| */ | |
| protected function buildLazyLoadItselfMethod() { | |
| $output = <<<'EOS' | |
| /** | |
| * Lazy loads the real service from the container. | |
| * | |
| * @return object | |
| * Returns the constructed real service. | |
| */ | |
| protected function lazyLoadItself() | |
| { | |
| if (!isset($this->service)) { | |
| $this->service = $this->container->get($this->drupalProxyOriginalServiceId); | |
| } | |
| return $this->service; | |
| } | |
| EOS; | |
| return $output; | |
| } | |
| /** | |
| * Generates the string representation of a single method: signature, body. | |
| * | |
| * @param \ReflectionMethod $reflection_method | |
| * A reflection method for the method. | |
| * | |
| * @return string | |
| */ | |
| protected function buildMethod(\ReflectionMethod $reflection_method) { | |
| $parameters = []; | |
| foreach ($reflection_method->getParameters() as $parameter) { | |
| $parameters[] = $this->buildParameter($parameter); | |
| } | |
| $function_name = $reflection_method->getName(); | |
| $reference = ''; | |
| if ($reflection_method->returnsReference()) { | |
| $reference = '&'; | |
| } | |
| $signature_line = <<<'EOS' | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| EOS; | |
| if ($reflection_method->isStatic()) { | |
| $signature_line .= 'public static function ' . $reference . $function_name . '('; | |
| } | |
| else { | |
| $signature_line .= 'public function ' . $reference . $function_name . '('; | |
| } | |
| $signature_line .= implode(', ', $parameters); | |
| $signature_line .= ')'; | |
| $output = $signature_line . "\n{\n"; | |
| $output .= $this->buildMethodBody($reflection_method); | |
| $output .= "\n" . '}'; | |
| return $output; | |
| } | |
| /** | |
| * Builds a string for a single parameter of a method. | |
| * | |
| * @param \ReflectionParameter $parameter | |
| * A reflection object of the parameter. | |
| * | |
| * @return string | |
| */ | |
| protected function buildParameter(\ReflectionParameter $parameter) { | |
| $parameter_string = ''; | |
| if ($parameter->isArray()) { | |
| $parameter_string .= 'array '; | |
| } | |
| elseif ($parameter->isCallable()) { | |
| $parameter_string .= 'callable '; | |
| } | |
| elseif ($class = $parameter->getClass()) { | |
| $parameter_string .= '\\' . $class->getName() . ' '; | |
| } | |
| if ($parameter->isPassedByReference()) { | |
| $parameter_string .= '&'; | |
| } | |
| $parameter_string .= '$' . $parameter->getName(); | |
| if ($parameter->isDefaultValueAvailable()) { | |
| $parameter_string .= ' = '; | |
| $parameter_string .= var_export($parameter->getDefaultValue(), TRUE); | |
| } | |
| return $parameter_string; | |
| } | |
| /** | |
| * Builds the body of a wrapped method. | |
| * | |
| * @param \ReflectionMethod $reflection_method | |
| * A reflection method for the method. | |
| * | |
| * @return string | |
| */ | |
| protected function buildMethodBody(\ReflectionMethod $reflection_method) { | |
| $output = ''; | |
| $function_name = $reflection_method->getName(); | |
| if (!$reflection_method->isStatic()) { | |
| $output .= ' return $this->lazyLoadItself()->' . $function_name . '('; | |
| } | |
| else { | |
| $class_name = $reflection_method->getDeclaringClass()->getName(); | |
| $output .= " \\$class_name::$function_name("; | |
| } | |
| // Add parameters; | |
| $parameters = []; | |
| foreach ($reflection_method->getParameters() as $parameter) { | |
| $parameters[] = '$' . $parameter->getName(); | |
| } | |
| $output .= implode(', ', $parameters) . ');'; | |
| return $output; | |
| } | |
| /** | |
| * Builds the constructor used to inject the actual service ID. | |
| * | |
| * @return string | |
| */ | |
| protected function buildConstructorMethod() { | |
| $output = <<<'EOS' | |
| /** | |
| * Constructs a ProxyClass Drupal proxy object. | |
| * | |
| * @param \Symfony\Component\DependencyInjection\ContainerInterface $container | |
| * The container. | |
| * @param string $drupal_proxy_original_service_id | |
| * The service ID of the original service. | |
| */ | |
| public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $drupal_proxy_original_service_id) | |
| { | |
| $this->container = $container; | |
| $this->drupalProxyOriginalServiceId = $drupal_proxy_original_service_id; | |
| } | |
| EOS; | |
| return $output; | |
| } | |
| /** | |
| * Build the required use statements of the proxy class. | |
| * | |
| * @return string | |
| */ | |
| protected function buildUseStatements() { | |
| $output = ''; | |
| return $output; | |
| } | |
| } |