Completed
Push — master ( 95a6e8...b8af6d )
by Filipe
07:12
created

PropertiesInspector::setDefinition()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 1
crap 1
1
<?php
2
3
/**
4
 * This file is part of slick/di package
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace Slick\Di\DependencyInspector;
11
12
use Slick\Common\Annotation\Basic;
13
use Slick\Common\Base;
14
use Slick\Common\Inspector;
15
use Slick\Di\Definition\ObjectDefinitionInterface;
16
use Slick\Di\Exception\NotFoundException;
17
18
/**
19
 * Properties Inspector for dependency definition
20
 *
21
 * @package Slick\Di\DependencyInspector
22
 * @author  Filipe Silva <[email protected]>
23
 *
24
 * @property ObjectDefinitionInterface $definition
25
 */
26
class PropertiesInspector extends Base
27
{
28
    /**
29
     * @readwrite
30
     * @var ObjectDefinitionInterface
31
     */
32
    protected $definition;
33
34
    /** @var string[] */
35
    private $properties;
36
37
    /** @var Inspector */
38
    private $classInspector;
39
40
    /**
41
     * Set the definition that will be updated
42
     *
43
     * @param ObjectDefinitionInterface $definition
44
     * @return $this|self|PropertiesInspector
45
     */
46 46
    public function setDefinition(ObjectDefinitionInterface $definition)
47
    {
48 46
        $this->definition = $definition;
49 46
        $this->properties = $this->classInspector = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->classInspector = null of type null is incompatible with the declared type array<integer,string> of property $properties.

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...
50 46
        $this->updateDefinition();
51 46
        return $this;
52
    }
53
54
    /**
55
     * Updated property list on definition based on class inspection
56
     */
57 46
    private function updateDefinition()
58
    {
59 46
        foreach ($this->getProperties() as $property) {
60 36
            if ($this->hasInjectAnnotation($property)) {
61 14
                $this->addProperty($property);
62 14
            }
63 46
        }
64 46
    }
65
66
    /**
67
     * Gets class property list
68
     *
69
     * @return string[]
70
     */
71 46
    private function getProperties()
72
    {
73 46
        if (is_null($this->properties)) {
74 46
            $this->properties = $this->getClassInspector()
75 46
                ->getClassProperties();
76 46
        }
77 46
        return $this->properties;
78
    }
79
80
    /**
81
     * Gets class inspector
82
     *
83
     * @return Inspector
84
     */
85 46
    private function getClassInspector()
86
    {
87 46
        if (is_null($this->classInspector)) {
88 46
            $this->classInspector = Inspector::forClass(
89 46
                $this->definition->getClassName()
90 46
            );
91 46
        }
92 46
        return $this->classInspector;
93
    }
94
95
    /**
96
     * Check if the property has defined the @inject annotation
97
     *
98
     * @param string $property
99
     *
100
     * @return bool
101
     */
102 36
    private function hasInjectAnnotation($property)
103
    {
104 36
        $annotations = $this->getClassInspector()
105 36
            ->getPropertyAnnotations($property);
106 36
        return $annotations->hasAnnotation('@inject');
107
    }
108
109
    /**
110
     * Get inject annotation for provided property
111
     *
112
     * @param string $property
113
     * @return Basic|\Slick\Common\AnnotationInterface
114
     */
115 14
    private function getInjectAnnotation($property)
116
    {
117 14
        $annotations = $this->getClassInspector()
118 14
            ->getPropertyAnnotations($property);
119 14
        return $annotations->getAnnotation('@inject');
120
    }
121
122
    /**
123
     * Get var annotation for provided property
124
     *
125
     * @param string $property
126
     *
127
     * @return null|string
128
     */
129 14
    private function getVarAnnotationValue($property)
130
    {
131 14
        $value = null;
132 14
        $annotations = $this->getClassInspector()
133 14
            ->getPropertyAnnotations($property);
134 14
        if ($annotations->hasAnnotation('@var')) {
135 14
            $value = trim(
136 14
                $annotations->getAnnotation('@var')->getValue(),
137
                '\\'
138 14
            );
139 14
        }
140 14
        return $value;
141
    }
142
143
    /**
144
     * Adds property to the definition property list
145
     *
146
     * @param string $property
147
     */
148 14
    private function addProperty($property)
149
    {
150 14
        $id = $this->getVarAnnotationValue($property);
151 14
        $value = $this->getInjectAnnotation($property)->getValue();
152 14
        if (is_string($value)) {
153 14
            $id = trim($value, '\\');
154 14
        }
155 14
        $container = $this->definition->getContainer();
156
157 14
        if (!$container->has($id)) {
158 2
            throw new NotFoundException(
159 2
                "The property {$property} has annotation '@inject' but ".
160 2
                "current container has no correspondent entry for ".
161
                "the type or key entered."
162 2
            );
163
        }
164
165 14
        $this->definition->setProperty($property, $container->get($id));
166 14
    }
167
}
168