Passed
Push — master ( 9c412f...50f52a )
by Mauro
02:02
created

DIC::instantiateTheClass()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 29
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 12
c 0
b 0
f 0
dl 0
loc 29
rs 8.8333
cc 7
nc 6
nop 4
1
<?php
2
3
namespace SimpleDIC;
4
5
use Pimple\Container;
6
use SimpleDIC\Parser\Parser;
7
8
class DIC
9
{
10
    /**
11
     * @var Container
12
     */
13
    private static $container;
14
15
    /**
16
     * DIC constructor.
17
     *
18
     * @param array $config
19
     */
20
    private function __construct(array $config = [])
21
    {
22
        self::$container = new Container();
23
24
        $this->resolveDependencies($config);
25
    }
26
27
    /**
28
     * @return int
29
     */
30
    public static function count()
31
    {
32
        return count(self::keys());
33
    }
34
35
    /**
36
     * Initialise the DIC
37
     *
38
     * @param array $config
39
     *
40
     * @return DIC
41
     */
42
    public static function init(array $config = [])
43
    {
44
        return new self($config);
45
    }
46
47
    /**
48
     * @param string $filename
49
     *
50
     * @return DIC
51
     * @throws \Exception
52
     */
53
    public static function initFromFile($filename)
54
    {
55
        return new self(Parser::parse($filename));
56
    }
57
58
    /**
59
     * @return array
60
     */
61
    public static function keys()
62
    {
63
        return self::$container->keys();
64
    }
65
66
    /**
67
     * Resolve the dependencies and register into the DIC
68
     *
69
     * @param array $config
70
     */
71
    private function resolveDependencies(array $config = [])
72
    {
73
        foreach ($config as $key => $content) {
74
            self::set($key, $content);
75
        }
76
    }
77
78
    /**
79
     *
80
     * Check for an entry existence within the container
81
     *
82
     * @param string $dependency
83
     *
84
     * @return bool
85
     */
86
    public static function has($dependency)
87
    {
88
        return isset(self::$container[$dependency]);
89
    }
90
91
    /**
92
     * Get an entry from the container.
93
     *
94
     * The method returns:
95
     * - false if the entry has a wrong configuration
96
     * - NULL if the entry does not exists
97
     *
98
     * @param string $dependency
99
     *
100
     * @return mixed
101
     */
102
    public static function get($dependency)
103
    {
104
        if (self::has($dependency)) {
105
            return self::$container[$dependency];
106
        }
107
    }
108
109
    /**
110
     * Set an entry in the container.
111
     *
112
     * @param string $key
113
     * @param array|mixed $content
114
     *
115
     * @return mixed|bool|null
116
     */
117
    private static function set($key, $content)
118
    {
119
        if (false === self::has($key)) {
120
            self::$container[$key] = function ($c) use ($content) {
121
122
                // if is not a class set the entry value in DIC
123
                if (false === isset($content['class'])) {
124
                    return self::getFromEnvOrDICParams($content);
125
                }
126
127
                // otherwise it's a class, so extract variables
128
                $class           = $content['class'];
129
                $classArguments  = isset($content['arguments']) ? $content['arguments'] : null;
130
                $method          = isset($content['method']) ? $content['method'] : null;
131
                $methodArguments = isset($content['method_arguments']) ? $content['method_arguments'] : null;
132
133
                $methodArgsToInject = self::getArgumentsToInject($c, $methodArguments);
134
                $classArgsToInject = self::getArgumentsToInject($c, $classArguments);
135
136
                try {
137
                    return self::instantiateTheClass($class, $classArgsToInject, $method, $methodArgsToInject);
138
                } catch (\Error $error) {
139
                    return false;
140
                } catch (\Exception $exception) {
141
                    return false;
142
                }
143
            };
144
145
            return null;
146
        }
147
    }
148
149
    /**
150
     * @param string $class
151
     * @param array $classArguments
152
     * @param null $method
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $method is correct as it would always require null to be passed?
Loading history...
153
     * @param array $methodArguments
154
     *
155
     * @return mixed|bool
156
     *
157
     * @throws \ReflectionException
158
     */
159
    private static function instantiateTheClass($class, array $classArguments = [], $method = null, array $methodArguments = [])
160
    {
161
        if (false === class_exists($class)) {
162
            return false;
163
        }
164
165
        $reflected = new \ReflectionClass($class);
166
167
        // 1. the class has no method to call
168
        if (null == $method) {
0 ignored issues
show
introduced by
The condition null == $method is always true.
Loading history...
169
            return new $class(...$classArguments);
170
        }
171
172
        if (false === $reflected->hasMethod($method)) {
173
            return false;
174
        }
175
176
        // 2. the method to call is static
177
        if ($reflected->getMethod($method)->isStatic()) {
178
            return $class::$method(...$methodArguments);
179
        }
180
181
        // 3. the class has a private constructor
182
        if ($reflected->hasMethod('__construct') and $reflected->getConstructor()->isPrivate()) {
183
            return call_user_func_array([$class, $method], $methodArguments);
184
        }
185
186
        // 4. the class has a public constructor
187
        return (new $class(...$classArguments))->$method(...$methodArguments);
188
    }
189
190
    /**
191
     * Get the arguments to inject into the class to instantiate within DIC.
192
     *
193
     * @param Container $c
194
     * @param null      $providedArguments
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $providedArguments is correct as it would always require null to be passed?
Loading history...
195
     *
196
     * @return array
197
     */
198
    private static function getArgumentsToInject(Container $c, $providedArguments = null)
199
    {
200
        $returnArguments = [];
201
202
        if (null != $providedArguments) {
0 ignored issues
show
introduced by
The condition null != $providedArguments is always false.
Loading history...
203
            foreach ($providedArguments as $argument) {
204
                $returnArguments[] = self::getArgumentToInject($argument, $c);
205
            }
206
        }
207
208
        return $returnArguments;
209
    }
210
211
    /**
212
     * @param   string        $argument
213
     * @param Container $c
214
     *
215
     * @return mixed|string|null
216
     */
217
    private static function getArgumentToInject($argument, Container $c)
218
    {
219
        if (isset($c[ltrim($argument, '@')])) {
220
            return $c[ltrim($argument, '@')];
221
        }
222
223
        return self::getFromEnvOrDICParams($argument);
224
    }
225
226
    /**
227
     * @param string $parameter
228
     *
229
     * @return mixed|string|null
230
     */
231
    private static function getFromEnvOrDICParams($parameter)
232
    {
233
        if (is_string($parameter)) {
0 ignored issues
show
introduced by
The condition is_string($parameter) is always true.
Loading history...
234
            if (null !== self::getEnvKey($parameter)) {
235
                return (getenv(self::getEnvKey($parameter))) ? getenv(self::getEnvKey($parameter)) : $parameter;
236
            }
237
238
            return (DICParams::has(self::getParamKey($parameter))) ? DICParams::get(self::getParamKey($parameter)) : $parameter;
239
        }
240
241
        return $parameter;
242
    }
243
244
    /**
245
     * Extract from a string like %env(FOO)%
246
     *
247
     * @param string $string
248
     *
249
     * @return mixed|null
250
     */
251
    private static function getEnvKey($string)
252
    {
253
        preg_match('~%env\((.*?)\)%~', $string, $matches);
254
255
        return (count($matches) > 0) ? $matches[1] : null;
256
    }
257
258
    /**
259
     * @param string $string
260
     *
261
     * @return string
262
     */
263
    private static function getParamKey($string)
264
    {
265
        return trim($string, '%');
266
    }
267
}
268