Completed
Push — 1.x ( c183a4...05b51a )
by Alexander
8s
created

AspectLoader::getUnloadedAspects()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 12
ccs 0
cts 6
cp 0
rs 9.4285
c 1
b 0
f 0
cc 3
eloc 6
nc 3
nop 0
crap 12
1
<?php
2
/*
3
 * Go! AOP framework
4
 *
5
 * @copyright Copyright 2012, Lisachenko Alexander <[email protected]>
6
 *
7
 * This source file is subject to the license that is bundled
8
 * with this source code in the file LICENSE.
9
 */
10
11
namespace Go\Core;
12
13
use Doctrine\Common\Annotations\Reader;
14
use Go\Aop\Advisor;
15
use Go\Aop\Aspect;
16
use Go\Aop\Pointcut;
17
use ReflectionClass;
18
19
/**
20
 * Loader of aspects into the container
21
 */
22
class AspectLoader
23
{
24
25
    /**
26
     * Aspect container instance
27
     *
28
     * @var null|AspectContainer
29
     */
30
    protected $container = null;
31
32
    /**
33
     * List of aspect loaders
34
     *
35
     * @var array
36
     */
37
    protected $loaders = [];
38
39
    /**
40
     * Annotation reader for aspects
41
     *
42
     * @var Reader|null
43
     */
44
    protected $annotationReader = null;
45
46
    /**
47
     * List of aspects that was loaded
48
     *
49
     * @var array
50
     */
51
    protected $loadedAspects = [];
52
53
    /**
54
     * Loader constructor
55
     *
56
     * @param AspectContainer $container Instance of container to store pointcuts and advisors
57
     * @param Reader $reader Reader for annotations that is used for aspects
58
     */
59 13
    public function __construct(AspectContainer $container, Reader $reader)
60
    {
61 13
        $this->container        = $container;
62 13
        $this->annotationReader = $reader;
63 13
    }
64
65
    /**
66
     * Register an aspect loader extension
67
     *
68
     * This method allows to extend the logic of aspect loading by registering an extension for loader.
69
     *
70
     * @param AspectLoaderExtension $loader Loader to register
71
     */
72 2
    public function registerLoaderExtension(AspectLoaderExtension $loader)
73
    {
74 2
        $targets = (array) $loader->getTarget();
75 2
        foreach ($targets as $target) {
76 2
            $this->loaders[$target][] = $loader;
77
        }
78 2
    }
79
80
    /**
81
     * Loads an aspect with the help of aspect loaders, but don't register it in the container
82
     *
83
     * @see loadAndRegister() method for registration
84
     *
85
     * @param \Go\Aop\Aspect $aspect Aspect to load
86
     *
87
     * @return array|Pointcut[]|Advisor[]
88
     */
89
    public function load(Aspect $aspect)
90
    {
91
        $loadedItems = [];
92
        $refAspect   = new \ReflectionClass($aspect);
93
94
        if (!empty($this->loaders[AspectLoaderExtension::TARGET_CLASS])) {
95
            $loadedItems += $this->loadFrom($aspect, $refAspect, $this->loaders[AspectLoaderExtension::TARGET_CLASS]);
96
        }
97
98
        if (!empty($this->loaders[AspectLoaderExtension::TARGET_METHOD])) {
99
            $refMethods = $refAspect->getMethods();
100
            foreach ($refMethods as $refMethod) {
101
                $loadedItems += $this->loadFrom($aspect, $refMethod, $this->loaders[AspectLoaderExtension::TARGET_METHOD]);
102
            }
103
        }
104
105
        if (!empty($this->loaders[AspectLoaderExtension::TARGET_PROPERTY])) {
106
            $refProperties = $refAspect->getProperties();
107
            foreach ($refProperties as $refProperty) {
108
                $loadedItems += $this->loadFrom($aspect, $refProperty, $this->loaders[AspectLoaderExtension::TARGET_PROPERTY]);
109
            }
110
        }
111
112
        return $loadedItems;
113
    }
114
115
    /**
116
     * Loads and register all items of aspect in the container
117
     *
118
     * @param Aspect $aspect
119
     */
120
    public function loadAndRegister(Aspect $aspect)
121
    {
122
        $loadedItems = $this->load($aspect);
123
        foreach ($loadedItems as $itemId => $item) {
124
            if ($item instanceof Pointcut) {
125
                $this->container->registerPointcut($item, $itemId);
126
            }
127
            if ($item instanceof Advisor) {
128
                $this->container->registerAdvisor($item, $itemId);
129
            }
130
        }
131
132
        $aspectClass = get_class($aspect);
133
        $this->loadedAspects[$aspectClass] = $aspectClass;
134
    }
135
136
    /**
137
     * Returns list of unloaded aspects in the container
138
     *
139
     * @return array|Aspect[]
140
     */
141
    public function getUnloadedAspects()
142
    {
143
        $unloadedAspects = [];
144
145
        foreach ($this->container->getByTag('aspect') as $aspect) {
146
            if (!isset($this->loadedAspects[get_class($aspect)])) {
147
                $unloadedAspects[] = $aspect;
148
            }
149
        }
150
151
        return $unloadedAspects;
152
    }
153
154
    /**
155
     * Load definitions from specific aspect part into the aspect container
156
     *
157
     * @param Aspect $aspect Aspect instance
158
     * @param \ReflectionClass|\ReflectionMethod|\ReflectionProperty $refPoint Reflection instance
159
     * @param array|AspectLoaderExtension[] $loaders List of loaders that can produce advisors from aspect class
160
     *
161
     * @throws \InvalidArgumentException If kind of loader isn't supported
162
     *
163
     * @return array|Pointcut[]|Advisor[]
164
     */
165
    protected function loadFrom(Aspect $aspect, $refPoint, array $loaders)
166
    {
167
        $loadedItems = [];
168
169
        foreach ($loaders as $loader) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
170
171
            $loaderKind = $loader->getKind();
172
            switch ($loaderKind) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
173
174
                case AspectLoaderExtension::KIND_REFLECTION:
175
                    if ($loader->supports($aspect, $refPoint)) {
176
                        $loadedItems += $loader->load($aspect, $refPoint);
177
                    }
178
                    break;
179
180
                case AspectLoaderExtension::KIND_ANNOTATION:
181
                    $annotations = $this->getAnnotations($refPoint);
182
                    foreach ($annotations as $annotation) {
183
                        if ($loader->supports($aspect, $refPoint, $annotation)) {
184
                            $loadedItems += $loader->load($aspect, $refPoint, $annotation);
185
                        }
186
                    }
187
                    break;
188
189
                default:
190
                    throw new \InvalidArgumentException("Unsupported loader kind {$loaderKind}");
191
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
192
            }
193
        }
194
195
        return $loadedItems;
196
    }
197
198
    /**
199
     * Return list of annotations for reflection point
200
     *
201
     * @param \ReflectionClass|\ReflectionMethod|\ReflectionProperty $refPoint Reflection instance
202
     *
203
     * @return array list of annotations
204
     * @throws \InvalidArgumentException if $refPoint is unsupported
205
     */
206
    protected function getAnnotations($refPoint)
207
    {
208
        switch (true) {
209
            case ($refPoint instanceof \ReflectionClass):
210
                return $this->annotationReader->getClassAnnotations($refPoint);
211
212
            case ($refPoint instanceof \ReflectionMethod):
213
                return $this->annotationReader->getMethodAnnotations($refPoint);
214
215
            case ($refPoint instanceof \ReflectionProperty):
216
                return $this->annotationReader->getPropertyAnnotations($refPoint);
217
218
            default:
219
                throw new \InvalidArgumentException("Unsupported reflection point " . get_class($refPoint));
220
        }
221
    }
222
}
223