Completed
Push — master ( 7e3d04...dc7866 )
by Changwan
06:39
created

Descriptor::getDecorators()   D

Complexity

Conditions 9
Paths 48

Size

Total Lines 30
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 9

Importance

Changes 0
Metric Value
cc 9
eloc 19
nc 48
nop 2
dl 0
loc 30
ccs 18
cts 18
cp 1
crap 9
rs 4.909
c 0
b 0
f 0
1
<?php
2
namespace Wandu\DI;
3
4
use Doctrine\Common\Annotations\Reader;
5
use ReflectionClass;
6
use Wandu\DI\Contracts\ClassDecoratorInterface;
7
use Wandu\DI\Contracts\MethodDecoratorInterface;
8
use Wandu\DI\Contracts\PropertyDecoratorInterface;
9
use Wandu\DI\Contracts\ResolverInterface;
10
11
class Descriptor
12
{
13
    /** @var string */
14
    protected $className;
15
    
16
    /** @var \Wandu\DI\Contracts\ResolverInterface */
17
    protected $resolver;
18
    
19
    /** @var mixed */
20
    public $cache;
21
    
22
    /** @var array */
23
    public $arguments = [];
24
    
25
    /** @var bool */
26
    public $factory = false;
27
    
28
    /** @var bool */
29
    public $annotated = false;
30
    
31
    /** @var callable[] */
32
    public $afters = [];
33
    
34
    /** @var bool */
35
    public $frozen = false;
36
    
37 55
    public function __construct($className = null, ResolverInterface $resolver = null)
38
    {
39 55
        $this->className = $className;
40 55
        $this->resolver = $resolver;
41 55
    }
42
43
    /**
44
     * @param \Wandu\DI\Contracts\ResolverInterface $resolver
45
     * @return \Wandu\DI\Descriptor
46
     */
47
    public function setResolver(ResolverInterface $resolver): Descriptor
48
    {
49
        $this->resolver = $resolver;
50
        return $this;
51
    }
52
    
53
    /**
54
     * @param array $arguments
55
     * @return \Wandu\DI\Descriptor
56
     */
57 17
    public function assign(array $arguments = []): Descriptor
58
    {
59 17
        $this->arguments = $arguments + $this->arguments;
60 17
        return $this;
61
    }
62
63
    /**
64
     * @return \Wandu\DI\Descriptor
65
     */
66 1
    public function freeze(): Descriptor
67
    {
68 1
        $this->frozen = true;
69 1
        return $this;
70
    }
71
72
    /**
73
     * @return \Wandu\DI\Descriptor
74
     */
75 2
    public function factory(): Descriptor
76
    {
77 2
        $this->factory = true;
78 2
        return $this;
79
    }
80
81
    /**
82
     * @return \Wandu\DI\Descriptor
83
     */
84 4
    public function annotated(): Descriptor
85
    {
86 4
        $this->annotated = true;
87 4
        return $this;
88
    }
89
    
90
    /**
91
     * @deprecated
92
     * 
93
     * @return \Wandu\DI\Descriptor
94
     */
95 2
    public function wire(): Descriptor
96
    {
97 2
        return $this->annotated();
98
    }
99
100
    /**
101
     * @param callable $after
102
     * @return \Wandu\DI\Descriptor
103
     */
104 7
    public function after(callable $after): Descriptor
105
    {
106 7
        $this->afters[] = $after;
107 7
        return $this;
108
    }
109
110
    /**
111
     * @internal
112
     * @param \Wandu\DI\ContainerInterface $container
113
     * @return mixed
114
     */
115 50
    public function createInstance(ContainerInterface $container)
116
    {
117 50
        if ($this->factory) {
118 2
            if ($this->annotated && $this->className) {
119
                $reflClass = new ReflectionClass($this->className);
120
                list($classDecorators, $propertyDecorators, $methodDecorators) = $this->getDecorators($container->get(Reader::class),
121
                    $reflClass);
122
                /** @var \Wandu\DI\Contracts\ClassDecoratorInterface $anno */
123
                foreach ($classDecorators as $anno) {
124
                    $anno->onBindClass($reflClass, $this, $container);
125
                }
126
                /** @var \Wandu\DI\Contracts\PropertyDecoratorInterface $anno */
127
                foreach ($propertyDecorators as list($anno, $refl)) {
128
                    $anno->onBindProperty($refl, $reflClass, $this, $container);
129
                }
130
                /** @var \Wandu\DI\Contracts\MethodDecoratorInterface $anno */
131
                foreach ($methodDecorators as list($anno, $refl)) {
132
                    $anno->onBindMethod($refl, $reflClass, $this, $container);
133
                }
134
            }
135 2
            $object = $this->resolver->resolve($container, $this->arguments);
136 2
            foreach ($this->afters as $after) {
137
                $result = call_user_func($after, $object);
138
                if ($result) {
139
                    $object = $result;
140
                }
141
            }
142 2
            $this->frozen = true;
143 2
            return $object;
144
        }
145 50
        if (!isset($this->cache)) {
146 50
            if ($this->annotated && $this->className) {
147 4
                $reflClass = new ReflectionClass($this->className);
148 4
                list($classDecorators, $propertyDecorators, $methodDecorators) = $this->getDecorators($container->get(Reader::class),
149
                    $reflClass);
150
                /** @var \Wandu\DI\Contracts\ClassDecoratorInterface $anno */
151 4
                foreach ($classDecorators as $anno) {
152 1
                    $anno->onBindClass($reflClass, $this, $container);
153
                }
154
                /** @var \Wandu\DI\Contracts\PropertyDecoratorInterface $anno */
155 4
                foreach ($propertyDecorators as list($anno, $refl)) {
156 3
                    $anno->onBindProperty($refl, $reflClass, $this, $container);
157
                }
158
                /** @var \Wandu\DI\Contracts\MethodDecoratorInterface $anno */
159 4
                foreach ($methodDecorators as list($anno, $refl)) {
160 2
                    $anno->onBindMethod($refl, $reflClass, $this, $container);
161
                }
162
            }
163 50
            $object = $this->resolver->resolve($container, $this->arguments);
164 46
            foreach ($this->afters as $after) {
165 7
                $result = call_user_func($after, $object);
166 7
                if ($result) {
167 7
                    $object = $result;
168
                }
169
            }
170 46
            $this->cache = $object; 
171
        }
172 46
        $this->frozen = true;
173 46
        return $this->cache;
174
    }
175
176 4
    protected function getDecorators(Reader $reader, ReflectionClass $reflClass)
177
    {
178 4
        $classDecorators = [];
179 4
        $propertyDecorators = [];
180 4
        $methodDecorators = [];
181 4
        foreach ($reader->getClassAnnotations($reflClass) as $classAnnotation) {
182 1
            if ($classAnnotation instanceof ClassDecoratorInterface) {
183 1
                $classDecorators[] = $classAnnotation;
184
            }
185
        }
186 4
        foreach ($reflClass->getProperties() as $reflProperty) {
187 3
            foreach ($reader->getPropertyAnnotations($reflProperty) as $propertyAnnotation) {
188 3
                if ($propertyAnnotation instanceof PropertyDecoratorInterface) {
189 3
                    $propertyDecorators[] = [$propertyAnnotation, $reflProperty];
190
                }
191
            }
192
        }
193 4
        foreach ($reflClass->getMethods() as $reflMethod) {
194 4
            foreach ($reader->getMethodAnnotations($reflMethod) as $methodAnnotation) {
195 2
                if ($methodAnnotation instanceof MethodDecoratorInterface) {
196 4
                    $methodDecorators[] = [$methodAnnotation, $reflMethod];
197
                }
198
            }
199
        }
200
        return [
201 4
            $classDecorators,
202 4
            $propertyDecorators,
203 4
            $methodDecorators,
204
        ];
205
    }
206
}
207