src/Discovery/AnnotatedPluginDiscovery.php
<?php namespace EclipseGc\PluginAnnotation\Discovery; use Doctrine\Common\Annotations\AnnotationReader;use Doctrine\Common\Annotations\AnnotationRegistry;use Doctrine\Common\Annotations\DocParser;use Doctrine\Common\Reflection\ClassFinderInterface;use Doctrine\Common\Reflection\StaticReflectionParser;use EclipseGc\Plugin\Discovery\PluginDefinitionSet;use EclipseGc\Plugin\Discovery\PluginDiscoveryInterface;use EclipseGc\Plugin\PluginDefinitionInterface;use EclipseGc\PluginAnnotation\Exception\NonexistentAnnotationException;use EclipseGc\PluginAnnotation\Exception\NonexistentInterfaceException; class AnnotatedPluginDiscovery implements PluginDiscoveryInterface { /** * @var \Traversable */ protected $namespaces; /** * @var string */ protected $directory; /** * @var string */ protected $interface; /** * @var string */ protected $annotationClass; /** * @var \Doctrine\Common\Annotations\Reader */ protected $reader; /** * AnnotatedPluginDiscovery constructor. * * @param \Traversable $namespaces * A traversable list of namespaces. * @param string $directory * The sub-directory structure plugins will appear in within namespaces. * @param string $interface * The interface plugins must implement. * @param string $annotationClass * The annotation class plugins must use. * * @throws \EclipseGc\PluginAnnotation\Exception\NonexistentAnnotationException * @throws \EclipseGc\PluginAnnotation\Exception\NonexistentInterfaceException * */ public function __construct(\Traversable $namespaces, string $directory, string $interface, string $annotationClass) { if (!interface_exists($interface)) { throw new NonexistentInterfaceException(sprintf("The specified interface %s does not exist.", $interface)); } if (!class_exists($annotationClass)) { throw new NonexistentAnnotationException(sprintf("The specified annotation class %s does not exist.", $annotationClass)); } $this->namespaces = $namespaces; $this->directory = $directory; $this->interface = $interface; $this->annotationClass = $annotationClass; } /** * {@inheritdoc} */Function `findPluginImplementations` has a Cognitive Complexity of 22 (exceeds 5 allowed). Consider refactoring.
Method `findPluginImplementations` has 26 lines of code (exceeds 25 allowed). Consider refactoring.
The variable $plugin_directory is not named in camelCase.
The variable $file_contents is not named in camelCase. public function findPluginImplementations(PluginDefinitionInterface ...$definitions) : PluginDefinitionSet { // Clear the annotation loaders of any previous annotation classes.Avoid using static access to class '\Doctrine\Common\Annotations\AnnotationRegistry' in method 'findPluginImplementations'. AnnotationRegistry::reset(); // Register the namespaces of classes that can be used for annotations.Avoid using static access to class '\Doctrine\Common\Annotations\AnnotationRegistry' in method 'findPluginImplementations'. AnnotationRegistry::registerLoader('class_exists'); $reader = $this->getReader();Avoid unused local variables such as '$namespace'. foreach ($this->namespaces as $namespace => $directory) { $plugin_directory = "$directory/{$this->directory}"; if (file_exists($plugin_directory)) { foreach (glob("$plugin_directory/*.php") as $file) { $file_contents = file_get_contents($file); $tokens = token_get_all($file_contents); $classes = $this->extractClassNames($tokens); foreach ($classes as $class) { if (class_exists($class) && !empty(class_implements($class)[$this->interface])) { $definition = $reader->getClassAnnotation((new StaticReflectionParser($class, $this->getFileFinder($file)))->getReflectionClass(), $this->annotationClass); if ($definition) {Missing class import via use statement (line '93', column '34'). $reflector = new \ReflectionClass($definition); $property = $reflector->getProperty('class'); $property->setAccessible(TRUE); $property->setValue($definition, $class); $definitions[] = $definition; } } } } } } return new PluginDefinitionSet(...$definitions); } /** * Extracts an array of class names from tokenized output of token_get_all(). * * @param array $tokens * * @return string[] */ protected function extractClassNames(array $tokens) : array { $classes = []; $namespace = $this->extractNamespace($tokens); foreach ($tokens as $id => $token) { if ($token[0] == T_CLASS) { $classes[] = $namespace ? $namespace . '\\' . $tokens[$id+2][1] : $tokens[$id+2][1]; } } return $classes; } /** * Extracts a namespace from tokenized output of token_get_all(). * * @param array $tokens * * @return string */Function `extractNamespace` has a Cognitive Complexity of 9 (exceeds 5 allowed). Consider refactoring. protected function extractNamespace(array $tokens) : string { $namespace = ''; $found = FALSE; foreach ($tokens as $token) { if (is_array($token) && $token[0] == T_NAMESPACE) { $found = TRUE; } if (is_array($token) && ($token[0] == T_NS_SEPARATOR || $token[0] == T_STRING)) { $namespace .= $token[1]; } elseif ($found && $token == ';') { return $namespace; } } return $namespace; } /** * @param $file * * @return \Doctrine\Common\Reflection\ClassFinderInterface */ protected function getFileFinder($file) { return new class($file) implements ClassFinderInterface { protected $file; public function __construct($file) { $this->file = $file; } Avoid unused parameters such as '$class'. public function findFile($class) { return $this->file; } }; } /** * @return \Doctrine\Common\Annotations\Reader */ protected function getReader() { if (empty($this->reader)) { $docParser = new DocParser(); $docParser->setIgnoreNotImportedAnnotations(TRUE); $this->reader = new AnnotationReader($docParser); } return $this->reader; } }