Completed
Push — master ( 3f1d1d...0341ae )
by Matze
05:15
created

AnnotationLoader   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 133
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 96%

Importance

Changes 0
Metric Value
wmc 15
lcom 1
cbo 5
dl 0
loc 133
ccs 48
cts 50
cp 0.96
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
A load() 0 5 1
A supports() 0 4 1
B loadDefinition() 0 30 5
A includeFiles() 0 15 3
A processFiles() 0 12 3
A includeFile() 0 8 1
1
<?php
2
3
namespace BrainExe\Core;
4
5
use BrainExe\Core\Annotations\Service;
6
use BrainExe\Core\Annotations\Builder\ServiceDefinition;
7
use Doctrine\Common\Annotations\AnnotationReader;
8
use Doctrine\Common\Annotations\AnnotationRegistry;
9
use Doctrine\Common\Annotations\IndexedReader;
10
use RecursiveDirectoryIterator;
11
use RecursiveIteratorIterator;
12
use ReflectionClass;
13
use SplFileInfo;
14
use Symfony\Component\Config\Loader\Loader as ConfigLoader;
15
use Symfony\Component\DependencyInjection\ContainerBuilder;
16
use Symfony\Component\DependencyInjection\Definition;
17
18
class AnnotationLoader extends ConfigLoader
19
{
20
    /**
21
     * @var ContainerBuilder
22
     */
23
    private $container;
24
25
    /**
26
     * @var AnnotationReader
27
     */
28
    private $reader;
29
30
    /**
31
     * @var ServiceDefinition[]
32
     */
33
    private $builders = [];
34
35
    /**
36
     * @param ContainerBuilder $container
37
     * @param ServiceDefinition[] $builders
38
     */
39 1
    public function __construct(ContainerBuilder $container, array $builders = [])
40
    {
41 1
        $this->container = $container;
42 1
        $this->builders  = $builders;
43 1
        $this->reader    = new IndexedReader(new AnnotationReader());
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Doctrine\Common\Ann...ons\AnnotationReader()) of type object<Doctrine\Common\Annotations\IndexedReader> is incompatible with the declared type object<Doctrine\Common\A...tions\AnnotationReader> of property $reader.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
44
45 1
        AnnotationRegistry::registerLoader(function ($class) {
46 1
            return class_exists($class);
47 1
        });
48 1
    }
49
50
    /**
51
     * {@inheritdoc}
52
     */
53 1
    public function load($path, $type = null)
54
    {
55 1
        $includedFiles = $this->includeFiles($path);
56 1
        $this->processFiles($includedFiles);
57 1
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62
    public function supports($resource, $type = null)
63
    {
64
        return is_dir($resource);
65
    }
66
67
    /**
68
     * @param ReflectionClass $reflection
69
     * @return array
70
     */
71 1
    private function loadDefinition(ReflectionClass $reflection)
72
    {
73 1
        $annotation = $this->reader->getClassAnnotation($reflection, Service::class);
74 1
        $definitions = [];
75
76
        /** @var ServiceDefinition $builder */
77 1
        if ($annotation) {
78 1
            $annotationClass = get_class($annotation);
79
80 1
            $class = $reflection->getName();
81 1
            $definition = $this->container->register($class, $class);
82
83 1
            if (isset($this->builders[$annotationClass])) {
84 1
                $builder = $this->builders[$annotationClass];
85
            } else {
86
                /** @var string|Service $annotationClass */
87 1
                $this->builders[$annotationClass] = $builder = $annotationClass::getBuilder(
88 1
                    $this->container,
89 1
                    $this->reader
90
                );
91
            }
92
93 1
            list($alias) = $builder->build($reflection, $annotation, $definition);
94 1
            if ($alias && $alias !== $class) {
95 1
                $this->container->setAlias($alias, $class);
96
            }
97
        }
98
99 1
        return $definitions;
100
    }
101
102
    /**
103
     * @param string $path
104
     * @return string[]
105
     */
106 1
    private function includeFiles(string $path) : array
107
    {
108 1
        $includedFiles = [];
109
110
        /** @var SplFileInfo[] $directoryIterator */
111 1
        $directoryIterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path));
112 1
        foreach ($directoryIterator as $fileInfo) {
113 1
            if ($fileInfo->getExtension() === 'php') {
114 1
                $included = $this->includeFile($fileInfo);
115 1
                $includedFiles[$included] = true;
116
            }
117
        }
118
119 1
        return $includedFiles;
120
    }
121
122
    /**
123
     * @param string[] $includedFiles
124
     */
125 1
    private function processFiles(array $includedFiles)
126
    {
127 1
        $declaredClasses = get_declared_classes();
128 1
        foreach ($declaredClasses as $className) {
129 1
            $reflection = new ReflectionClass($className);
130 1
            $filename   = $reflection->getFileName();
131
132 1
            if (isset($includedFiles[$filename])) {
133 1
                $this->loadDefinition($reflection);
134
            }
135
        }
136 1
    }
137
138
    /**
139
     * @param SplFileInfo $fileInfo
140
     * @return string
141
     */
142 1
    private function includeFile(SplFileInfo $fileInfo)
143
    {
144 1
        $sourceFile = $fileInfo->getRealPath();
145
146 1
        require_once $sourceFile;
147
148 1
        return $sourceFile;
149
    }
150
}
151