Completed
Branch develop (9f43d2)
by Filipe
05:14
created

Resolver::resolve()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 1
1
<?php
2
3
/**
4
 * This file is part of slick/di
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\Definition\Object;
11
12
use Slick\Di\ContainerAwareMethods;
13
14
/**
15
 * Object definition Resolver
16
 *
17
 * @package Slick\Di\Definition\Object
18
 * @author  Filipe Silva <[email protected]>
19
 */
20
class Resolver implements ResolverInterface
21
{
22
23
    /**
24
     * @var DefinitionData
25
     */
26
    protected $data;
27
28
    /**
29
     * @var object
30
     */
31
    protected $object;
32
33
    /**
34
     * @var \ReflectionClass
35
     */
36
    protected $reflection;
37
38
    /**
39
     * Used to implement the ContainerAwareInterface
40
     */
41
    use ContainerAwareMethods;
42
43
    /**
44
     * Resolves the provided data into and object
45
     *
46
     * @param DefinitionData $data
47
     *
48
     * @return object
49
     */
50
    public function resolve(DefinitionData $data)
51
    {
52
        $this->data = $data;
53
54
        $this->object = $this->createObject();
55
56
        foreach ($data->calls as $call) {
57
            $this->apply($call);
58
        }
59
60
        return $this->object;
61
    }
62
63
    /**
64
     * Creates the object
65
     *
66
     * @return object
67
     */
68
    public function createObject()
69
    {
70
        $reflection = new \ReflectionClass($this->data->className);
71
        return $reflection->hasMethod('__construct')
72
            ? $reflection->newInstanceArgs(
73
                $this->filterArguments($this->data->arguments)
74
            )
75
            : $reflection->newInstance();
76
    }
77
78
    /**
79
     * Invoke a method with optional arguments on current object
80
     *
81
     * @param array $call
82
     *
83
     * @return Resolver
84
     */
85
    protected function apply($call)
86
    {
87
        if ($call['type'] !== DefinitionData::METHOD) {
88
            return $this->setProperty($call);
89
        }
90
91
        $this->getReflection()
92
            ->getMethod($call['name'])
93
            ->invokeArgs(
94
                $this->object,
95
                $this->filterArguments($call['arguments'])
96
            )
97
        ;
98
        return $this;
99
    }
100
101
    /**
102
     * Assign the call value to a property
103
     *
104
     * @param array $data
105
     *
106
     * @return Resolver
107
     */
108
    protected function setProperty($data)
109
    {
110
        $this->getReflection()
111
            ->getProperty($data['name'])
112
            ->setValue(
113
                $this->object,
114
                $this->filterValue($data['arguments'])
115
            )
116
        ;
117
        return $this;
118
    }
119
120
    /**
121
     * Filters all the arguments for aliases
122
     *
123
     * If an argument is prefixed with an '@' its value will be retrieved
124
     * from the container.
125
     *
126
     * @param array $data
127
     *
128
     * @return array
129
     */
130
    protected function filterArguments(array $data)
131
    {
132
        $values = [];
133
        foreach ($data as $argument) {
134
            array_push($values, $this->filterValue($argument));
135
        }
136
        return $values;
137
    }
138
139
    /**
140
     * Filters the value for aliases cases
141
     *
142
     * If the value is a string with an '@' prefix the it should try to get
143
     * value from the container
144
     *
145
     * @param string $value
146
     *
147
     * @return mixed
148
     */
149
    protected function filterValue($value)
150
    {
151
        if (is_string($value) && strpos($value, '@') !== false) {
152
            $key = substr($value, 1);
153
            return $this->getContainer()->get($key);
154
        }
155
        return $value;
156
    }
157
158
    /**
159
     * Get object reflection class
160
     *
161
     * @return \ReflectionClass
162
     */
163
    protected function getReflection()
164
    {
165
        if (!$this->reflection) {
166
            $this->reflection = new \ReflectionClass($this->object);
167
        }
168
        return $this->reflection;
169
    }
170
}
171