Completed
Push — master ( 15c856...4ce16e )
by Rafael
05:47
created

AnnotationLoader::extractNamespaceClasses()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 18
ccs 12
cts 12
cp 1
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 12
nc 5
nop 3
crap 5
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
        foreach ($this->annotationParsers as $parser) {
69 1
            if ($parser instanceof AnnotationParserInterface) {
70 1
                foreach ($classesToLoad as $class) {
71 1
                    $refClass = new \ReflectionClass($class);
72 1
                    $annotations = $this->reader->getClassAnnotations($refClass);
73 1
                    foreach ($annotations as $annotation) {
74 1
                        if ($parser->supports($annotation)) {
75 1
                            $parser->parse($annotation, $refClass, $endpoint);
76
                        }
77
                    }
78
                }
79
            }
80
        }
81 1
    }
82
83
    /**
84
     * @return array
85
     */
86 1
    protected function resolveClasses(): array
87
    {
88 1
        $bundles = $this->kernel->getBundles();
89 1
        $classes = [[]];
90 1
        foreach (self::DEFINITIONS_LOCATIONS as $definitionLocation) {
91 1
            foreach ($bundles as $bundle) {
92 1
                $path = $bundle->getPath().'/'.$definitionLocation;
93 1
                if (file_exists($path)) {
94 1
                    $classes[] = $this->extractNamespaceClasses($path, $bundle->getNamespace(), $definitionLocation);
95
                }
96
            }
97
98 1
            if (Kernel::VERSION_ID >= 40000) {
99
                $path = $this->kernel->getRootDir().'/'.$definitionLocation;
100
                if (file_exists($path)) {
101 1
                    $classes[] = $this->extractNamespaceClasses($path, 'App', $definitionLocation);
102
                }
103
            }
104
        }
105
106 1
        $classes = array_merge(...$classes);
107
108 1
        return array_unique($classes);
109
    }
110
111
    /**
112
     * @param string $path
113
     * @param string $baseNamespace
114
     * @param string $baseLocation
115
     *
116
     * @return array
117
     */
118 1
    protected function extractNamespaceClasses($path, $baseNamespace, $baseLocation)
119
    {
120 1
        $classes = [];
121 1
        $finder = new Finder();
122 1
        foreach ($finder->in($path)->name('/.php$/')->getIterator() as $file) {
123 1
            $className = preg_replace('/.php$/', null, $file->getFilename());
124 1
            if ($file->getRelativePath()) {
125 1
                $subNamespace = str_replace('/', '\\', $file->getRelativePath());
126 1
                $fullyClassName = $baseNamespace.'\\'.$baseLocation.'\\'.$subNamespace.'\\'.$className;
127
            } else {
128 1
                $fullyClassName = $baseNamespace.'\\'.$baseLocation.'\\'.$className;
129
            }
130 1
            if (class_exists($fullyClassName) || interface_exists($fullyClassName)) {
131 1
                $classes[] = $fullyClassName;
132
            }
133
        }
134
135 1
        return $classes;
136
    }
137
}
138