Passed
Push — master ( 35a242...04c846 )
by Mauro
02:00
created

DIC::callClassMethod()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
c 0
b 0
f 0
dl 0
loc 13
rs 10
cc 3
nc 3
nop 2
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           = isset($content['class']) ? $content['class'] : null;
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
                if (false === class_exists($class)) {
134
                    return false;
135
                }
136
137
                // if specified, call a method
138
                if ($method) {
139
140
                    // if specified, call the method with provided arguments
141
                    if ($methodArguments) {
142
                        try {
143
                            return call_user_func_array([$class, $method], self::getArgumentsToInject($c, $methodArguments));
144
                        } catch (\Error $error) {
145
                            return false;
146
                        } catch (\Exception $exception) {
147
                            return false;
148
                        }
149
                    }
150
151
                    // if not, call the method with no arguments
152
                    try {
153
                        return self::callClassMethod($class, $method);
154
                    } catch (\Error $error) {
155
                        return false;
156
                    } catch (\Exception $exception) {
157
                        return false;
158
                    }
159
                }
160
161
                // if the method is not specified, call the constructor
162
                try {
163
                    return new $class(...self::getArgumentsToInject($c, $classArguments));
164
                } catch (\Error $error) {
165
                    return false;
166
                } catch (\Exception $exception) {
167
                    return false;
168
                }
169
            };
170
171
            return null;
172
        }
173
    }
174
175
    /**
176
     * @param string $class
177
     * @param string $method
178
     *
179
     * @return bool|mixed
180
     * @throws \ReflectionException
181
     */
182
    private static function callClassMethod($class, $method)
183
    {
184
        $reflected = new \ReflectionClass($class);
185
186
        if (false === $reflected->hasMethod($method)) {
187
            return false;
188
        }
189
190
        if ($reflected->getMethod($method)->isStatic()) {
191
            return call_user_func([$class, $method]);
192
        }
193
194
        return (new $class)->$method();
195
    }
196
197
    /**
198
     * Get the arguments to inject into the class to instantiate within DIC.
199
     *
200
     * @param Container $c
201
     * @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...
202
     *
203
     * @return array
204
     */
205
    private static function getArgumentsToInject(Container $c, $providedArguments = null)
206
    {
207
        $returnArguments = [];
208
209
        if (null != $providedArguments) {
0 ignored issues
show
introduced by
The condition null != $providedArguments is always false.
Loading history...
210
            foreach ($providedArguments as $argument) {
211
                $returnArguments[] = self::getArgumentToInject($argument, $c);
212
            }
213
        }
214
215
        return $returnArguments;
216
    }
217
218
    /**
219
     * @param   string        $argument
220
     * @param Container $c
221
     *
222
     * @return mixed|string|null
223
     */
224
    private static function getArgumentToInject($argument, Container $c)
225
    {
226
        if (isset($c[ltrim($argument, '@')])) {
227
            return $c[ltrim($argument, '@')];
228
        }
229
230
        return self::getFromEnvOrDICParams($argument);
231
    }
232
233
    /**
234
     * @param string $parameter
235
     *
236
     * @return mixed|string|null
237
     */
238
    private static function getFromEnvOrDICParams($parameter)
239
    {
240
        if (is_string($parameter)) {
0 ignored issues
show
introduced by
The condition is_string($parameter) is always true.
Loading history...
241
            if (null !== self::getEnvKey($parameter)) {
242
                return (getenv(self::getEnvKey($parameter))) ? getenv(self::getEnvKey($parameter)) : $parameter;
243
            }
244
245
            return (DICParams::has(self::getParamKey($parameter))) ? DICParams::get(self::getParamKey($parameter)) : $parameter;
246
        }
247
248
        return $parameter;
249
    }
250
251
    /**
252
     * Extract from a string like %env(FOO)%
253
     *
254
     * @param string $string
255
     *
256
     * @return mixed|null
257
     */
258
    private static function getEnvKey($string)
259
    {
260
        preg_match('~%env\((.*?)\)%~', $string, $matches);
261
262
        return (count($matches) > 0) ? $matches[1] : null;
263
    }
264
265
    /**
266
     * @param string $string
267
     *
268
     * @return string
269
     */
270
    private static function getParamKey($string)
271
    {
272
        return trim($string, '%');
273
    }
274
}
275