Passed
Push — master ( 9ee6f0...969439 )
by Rafael
05:54
created

AnnotationLoader::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 3
crap 1
1
<?php
2
/*******************************************************************************
3
 *  This file is part of the GraphQL Bundle package.
4
 *
5
 *  (c) YnloUltratech <[email protected]>
6
 *
7
 *  For the full copyright and license information, please view the LICENSE
8
 *  file that was distributed with this source code.
9
 ******************************************************************************/
10
11
namespace Ynlo\GraphQLBundle\Definition\Loader;
12
13
use Doctrine\Common\Annotations\Reader;
14
use Symfony\Component\Finder\Finder;
15
use Symfony\Component\HttpKernel\Kernel;
16
use Ynlo\GraphQLBundle\Definition\Loader\Annotation\AnnotationParserInterface;
17
use Ynlo\GraphQLBundle\Definition\Registry\Endpoint;
18
19
/**
20
 * Resolve and load definitions based on common annotations
21
 */
22
class AnnotationLoader implements DefinitionLoaderInterface
23
{
24
    /**
25
     * Folders inside bundles to locate definitions
26
     * TODO: allow add additional mapping on bundle config
27
     */
28
    private const DEFINITIONS_LOCATIONS = [
29
        'Model', //non persistent models like interfaces, or abstract classes
30
        'Entity', //doctrine entities
31
        'Mutation', //custom actions
32
        'Query', //custom actions
33
    ];
34
35
    /**
36
     * @var Kernel
37
     */
38
    protected $kernel;
39
40
    /**
41
     * @var Reader
42
     */
43
    protected $reader;
44
45
    /**
46
     * @var iterable|array|AnnotationParserInterface[]
47
     */
48
    protected $annotationParsers = [];
49
50
    /**
51
     * @param Kernel                               $kernel
52
     * @param Reader                               $reader
53
     * @param iterable|AnnotationParserInterface[] $annotationParsers
54
     */
55 1
    public function __construct(Kernel $kernel, Reader $reader, $annotationParsers = [])
56
    {
57 1
        $this->kernel = $kernel;
58 1
        $this->reader = $reader;
59 1
        $this->annotationParsers = $annotationParsers;
60 1
    }
61
62
    /**
63
     * {@inheritdoc}
64
     */
65 1
    public function loadDefinitions(Endpoint $endpoint): void
66
    {
67 1
        $classesToLoad = $this->resolveClasses();
68 1
        $annotationsMapping = [];
69 1
        foreach ($classesToLoad as $class) {
70 1
            $refClass = new \ReflectionClass($class);
71 1
            $annotations = $this->reader->getClassAnnotations($refClass);
72 1
            if ($annotations) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $annotations of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
73 1
                $annotationsMapping[$refClass->getName()] = [$refClass, $annotations];
74
            }
75
        }
76
77 1
        foreach ($this->annotationParsers as $parser) {
78 1
            if ($parser instanceof AnnotationParserInterface) {
79 1
                foreach ($annotationsMapping as $className => $map) {
80 1
                    list($refClass, $annotations) = $map;
81 1
                    foreach ($annotations as $annotation) {
82 1
                        if ($parser->supports($annotation)) {
83 1
                            $parser->parse($annotation, $refClass, $endpoint);
84
                        }
85
                    }
86
                }
87
            }
88
        }
89 1
    }
90
91
    /**
92
     * @return array
93
     */
94 1
    protected function resolveClasses(): array
95
    {
96 1
        $bundles = $this->kernel->getBundles();
97 1
        $classes = [[]];
98 1
        foreach (self::DEFINITIONS_LOCATIONS as $definitionLocation) {
99 1
            foreach ($bundles as $bundle) {
100 1
                $path = $bundle->getPath().'/'.$definitionLocation;
101 1
                if (file_exists($path)) {
102 1
                    $classes[] = $this->extractNamespaceClasses($path, $bundle->getNamespace(), $definitionLocation);
103
                }
104
            }
105
106 1
            if (Kernel::VERSION_ID >= 40000) {
107
                $path = $this->kernel->getRootDir().'/'.$definitionLocation;
108
                if (file_exists($path)) {
109 1
                    $classes[] = $this->extractNamespaceClasses($path, 'App', $definitionLocation);
110
                }
111
            }
112
        }
113
114 1
        $classes = array_merge(...$classes);
115
116 1
        return array_unique($classes);
117
    }
118
119
    /**
120
     * @param string $path
121
     * @param string $baseNamespace
122
     * @param string $baseLocation
123
     *
124
     * @return array
125
     */
126 1
    protected function extractNamespaceClasses($path, $baseNamespace, $baseLocation)
127
    {
128 1
        $classes = [];
129 1
        $finder = new Finder();
130 1
        foreach ($finder->in($path)->name('/.php$/')->getIterator() as $file) {
131 1
            $className = preg_replace('/.php$/', null, $file->getFilename());
132 1
            if ($file->getRelativePath()) {
133 1
                $subNamespace = str_replace('/', '\\', $file->getRelativePath());
134 1
                $fullyClassName = $baseNamespace.'\\'.$baseLocation.'\\'.$subNamespace.'\\'.$className;
135
            } else {
136 1
                $fullyClassName = $baseNamespace.'\\'.$baseLocation.'\\'.$className;
137
            }
138 1
            if (class_exists($fullyClassName) || interface_exists($fullyClassName)) {
139 1
                $classes[] = $fullyClassName;
140
            }
141
        }
142
143 1
        return $classes;
144
    }
145
}
146