Completed
Pull Request — master (#4)
by Joao
01:18
created

DependencyInjection::bind()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
4
namespace ByJG\Config;
5
6
use ByJG\Config\Exception\DependencyInjectionException;
7
use Psr\Container\ContainerInterface;
8
use ReflectionClass;
9
use ReflectionException;
10
use ReflectionMethod;
11
12
class DependencyInjection
13
{
14
    /**
15
     * @var ContainerInterface
16
     */
17
    protected $containerInterface;
18
19
    protected $class;
20
21
    protected $args = [];
22
23
    protected $instance;
24
25
    protected $singleton = false;
26
27
    protected $methodCall = [];
28
29
    /**
30
     * @param $containerInterface ContainerInterface
31
     * @return DependencyInjection
32
     */
33
    public function injectContainer($containerInterface)
34
    {
35
        $this->containerInterface = $containerInterface;
36
        return $this;
37
    }
38
39
    /**
40
     * @return mixed
41
     */
42
    protected function getClass()
43
    {
44
        return $this->class;
45
    }
46
47
    /**
48
     * @param mixed $class
49
     * @throws DependencyInjectionException
50
     */
51
    protected function setClass($class)
52
    {
53
        if (!class_exists($class)) {
54
            throw new DependencyInjectionException("Class $class does not exists");
55
        }
56
        $this->class = $class;
57
    }
58
59
    /**
60
     * @return mixed
61
     */
62
    protected function getArgs()
63
    {
64
        return array_map(function ($value) {
65
            if ($value instanceof Param) {
66
                return $this->containerInterface->get($value->getParam());
67
            }
68
            return $value;
69
        }, $this->args);
70
    }
71
72
    /**
73
     * @param mixed $args
74
     * @return DependencyInjection
75
     * @throws DependencyInjectionException
76
     */
77
    public function withConstructorArgs($args)
78
    {
79
        if (!is_null($args) && !is_array($args)) {
80
            throw new DependencyInjectionException("Arguments should be an array");
81
        }
82
        $this->args = $args;
0 ignored issues
show
Documentation Bug introduced by
It seems like $args can be null. However, the property $args is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

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

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
83
84
        return $this;
85
    }
86
87
    /**
88
     * DependencyInjection constructor.
89
     * @param $class
90
     * @throws DependencyInjectionException
91
     */
92
    protected function __construct($class)
93
    {
94
        $this->setClass($class);
95
    }
96
97
    /**
98
     * @param $class
99
     * @return DependencyInjection
100
     * @throws DependencyInjectionException
101
     */
102
    public static function bind($class)
103
    {
104
        return new DependencyInjection($class);
105
    }
106
107
    /**
108
     * @return DependencyInjection
109
     * @throws DependencyInjectionException
110
     * @throws ReflectionException
111
     */
112
    public function withInjectedConstructor()
113
    {
114
        $reflection = new ReflectionMethod($this->getClass(), "__construct");
115
116
        $docComments = str_replace("\n", " ", $reflection->getDocComment());
117
118
        $params = [];
119
        $result = preg_match_all('/@param\s+\$[\w_\d]+\s+([\d\w_\\\\]+)/', $docComments, $params);
120
121
        if ($result) {
122
            $args = [];
123
            foreach ($params[1] as $param) {
124
                $args[] = Param::get(ltrim($param, "\\"));
125
            }
126
            return $this->withConstructorArgs($args);
127
        }
128
129
        return $this->withNoConstructor();
130
    }
131
132
    /**
133
     * @return DependencyInjection
134
     */
135
    public function withNoConstructor()
136
    {
137
        $this->args = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $args.

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...
138
        return $this;
139
    }
140
141
    public function withMethodCall($method, $args = [])
142
    {
143
        $this->methodCall[$method] = $args;
144
        return $this;
145
    }
146
147
    /**
148
     * @return DependencyInjection
149
     */
150
    public function toSingleton()
151
    {
152
        $this->singleton = true;
153
        return $this;
154
    }
155
156
    /**
157
     * @return DependencyInjection
158
     */
159
    public function toInstance()
160
    {
161
        $this->singleton = false;
162
        return $this;
163
    }
164
165
    /**
166
     * @return object
167
     * @throws ReflectionException
168
     */
169
    public function getInstance()
170
    {
171
        if ($this->singleton) {
172
            return $this->getSingletonInstace();
173
        }
174
175
        return $this->getNewInstance();
176
177
    }
178
179
    /**
180
     * @return object
181
     * @throws ReflectionException
182
     */
183
    protected function getNewInstance()
184
    {
185
        $reflectionClass = new ReflectionClass($this->getClass());
186
187
        if (is_null($this->args)) {
188
            return $this->callMethods($reflectionClass->newInstanceWithoutConstructor());
189
        }
190
191
        return $this->callMethods($reflectionClass->newInstanceArgs($this->getArgs()));
192
    }
193
194
    /**
195
     * @param $instance
196
     * @return mixed
197
     */
198
    protected function callMethods($instance)
199
    {
200
        foreach ($this->methodCall as $methodName => $args) {
201
            if (is_null($args)) {
202
                call_user_func([$instance, $methodName]);
203
            } else {
204
                call_user_func_array([$instance, $methodName], $args);
205
            }
206
        }
207
208
        return $instance;
209
    }
210
211
    /**
212
     * @return object
213
     * @throws ReflectionException
214
     */
215
    protected function getSingletonInstace()
216
    {
217
        if (empty($this->instance)) {
218
            $this->instance = $this->getNewInstance();
219
        }
220
        return $this->instance;
221
    }
222
}
223