Passed
Push — master ( 086350...14a425 )
by Mauro
02:26
created

DIC::setValue()   B

Complexity

Conditions 8
Paths 9

Size

Total Lines 30
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 17
c 0
b 0
f 0
nc 9
nop 1
dl 0
loc 30
rs 8.4444
1
<?php
2
3
namespace SimpleDIC;
4
5
use SimpleDIC\Parser\Parser;
6
7
class DIC
8
{
9
    /**
10
     * @var array
11
     */
12
    private static $values;
13
14
    /**
15
     * @var array
16
     */
17
    private static $cache;
18
19
    /**
20
     * @var string
21
     */
22
    private static $cacheDir;
23
24
    /**
25
     * @var string
26
     */
27
    private static $sha;
28
29
    /**
30
     * @param string $filename
31
     *
32
     * @throws Exceptions\ParserException
33
     */
34
    public static function initFromFile($filename)
35
    {
36
        self::$values = [];
37
        self::$sha = sha1($filename);
38
39
        $mapFile = self::getCacheDir(). DIRECTORY_SEPARATOR .self::$sha.'.php';
40
41
        if (false === file_exists($mapFile)) {
42
            if (false === is_dir(self::getCacheDir())) {
43
                if (false === mkdir(self::getCacheDir(), 0755, true)) {
44
                    throw new \Exception(self::getCacheDir() . ' is not a writable directory.');
45
                }
46
            }
47
48
            if (false === file_put_contents($mapFile, '<?php return unserialize(\'' . serialize(Parser::parse($filename)) . '\');' . PHP_EOL)) {
49
                throw new \Exception(' Can\'t write cache file.');
50
            }
51
        }
52
53
        self::$cache = include($mapFile);
54
    }
55
56
    /**
57
     * @param $dir
58
     *
59
     * @return mixed
60
     */
61
    public static function setCacheDir($dir)
62
    {
63
        return self::$cacheDir = $dir;
64
    }
65
66
    /**
67
     * @return string
68
     */
69
    private static function getCacheDir()
70
    {
71
        return (!empty(self::$cacheDir)) ? self::$cacheDir : __DIR__.'/../_cache';
72
    }
73
74
    /**
75
     * @return int
76
     */
77
    public static function count()
78
    {
79
        return count(self::$values);
80
    }
81
82
    /**
83
     * @param string $id
84
     *
85
     * @return mixed|null
86
     */
87
    public static function get($id)
88
    {
89
        // if apcu is enabled return from cache
90
        if (self::isApcuEnabled() and apcu_exists(self::getApcuKey($id))) {
91
            return apcu_fetch(self::getApcuKey($id));
92
        }
93
94
        // otherwise set the value in memory if it is not present
95
        if (false === isset(self::$values[$id])) {
96
            self::setValue($id);
97
        }
98
99
        // return from memory
100
        return self::$values[$id];
101
    }
102
103
    /**
104
     * Set an entry in the container.
105
     *
106
     * @param array $cachedMap
107
     * @param mixed $content
108
     *
109
     * @return bool
110
     */
111
    private static function setValue($id)
112
    {
113
        $content = self::$cache[$id];
114
115
        // if is not a class set the entry value in DIC
116
        if (false === isset($content['class'])) {
117
            self::$values[$id] = self::getFromEnvOrDICParams($content);
118
            $_SESSION[self::$sha][$id] = self::$values[$id];
119
120
            return true;
121
        }
122
123
        // otherwise it's a class, so extract variables
124
        extract($content);
125
126
        $methodArgsToInject = self::getArgumentsToInject(isset($method_arguments) ? $method_arguments : null);
127
        $classArgsToInject = self::getArgumentsToInject(isset($arguments) ? $arguments : null);
128
129
        try {
130
            self::$values[$id] = self::instantiateTheClass($class, $classArgsToInject, isset($method) ? $method : null, $methodArgsToInject);
131
132
            if (self::isApcuEnabled()) {
133
                apcu_store(self::getApcuKey($id), self::$values[$id]);
134
            }
135
136
            return true;
137
        } catch (\Error $error) {
138
            return false;
139
        } catch (\Exception $exception) {
140
            return false;
141
        }
142
    }
143
144
    /**
145
     * @return bool
146
     */
147
    private static function isApcuEnabled()
148
    {
149
        return (extension_loaded('apc') && ini_get('apc.enabled'));
150
    }
151
152
    /**
153
     * @param string $id
154
     *
155
     * @return string
156
     */
157
    private static function getApcuKey($id)
158
    {
159
        return md5(self::$sha.'/'.$id);
160
    }
161
162
    /**
163
     * @param string $id
164
     *
165
     * @return bool
166
     */
167
    public static function has($id)
168
    {
169
        if (false === isset(self::$values[$id])) {
170
            self::setValue($id);
171
        }
172
173
        return isset(self::$values[$id]);
174
    }
175
176
    /**
177
     * @return array
178
     */
179
    public static function keys()
180
    {
181
        return array_keys(self::$values);
182
    }
183
184
    /**
185
     * @param string $class
186
     * @param array $classArguments
187
     * @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...
188
     * @param array $methodArguments
189
     *
190
     * @return mixed|bool
191
     *
192
     * @throws \ReflectionException
193
     */
194
    private static function instantiateTheClass($class, array $classArguments = [], $method = null, array $methodArguments = [])
195
    {
196
        if (false === class_exists($class)) {
197
            return false;
198
        }
199
200
        $reflected = new \ReflectionClass($class);
201
202
        // 1. the class has no method to call
203
        if (null == $method) {
0 ignored issues
show
introduced by
The condition null == $method is always true.
Loading history...
204
            return new $class(...$classArguments);
205
        }
206
207
        if (false === $reflected->hasMethod($method)) {
208
            return false;
209
        }
210
211
        // 2. the method to call is static
212
        if ($reflected->getMethod($method)->isStatic()) {
213
            return $class::$method(...$methodArguments);
214
        }
215
216
        // 3. the class has a private constructor
217
        if ($reflected->hasMethod('__construct') and $reflected->getConstructor()->isPrivate()) {
218
            return call_user_func_array([$class, $method], $methodArguments);
219
        }
220
221
        // 4. the class has a public constructor
222
        return (new $class(...$classArguments))->$method(...$methodArguments);
223
    }
224
225
    /**
226
     * Get the arguments to inject into the class to instantiate within DIC.
227
     *
228
     * @param array $cachedMap
229
     * @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...
230
     *
231
     * @return array
232
     */
233
    private static function getArgumentsToInject($providedArguments = null)
234
    {
235
        $returnArguments = [];
236
237
        if (null != $providedArguments) {
0 ignored issues
show
introduced by
The condition null != $providedArguments is always false.
Loading history...
238
            foreach ($providedArguments as $argument) {
239
                $returnArguments[] = self::getArgumentToInject($argument);
240
            }
241
        }
242
243
        return $returnArguments;
244
    }
245
246
    /**
247
     * @param array $cachedMap
248
     * @param string $argument
249
     *
250
     * @return mixed|string|null
251
     */
252
    private static function getArgumentToInject($argument)
253
    {
254
        $id = ltrim($argument, '@');
255
256
        return (isset(self::$cache[$id])) ? self::get($id) : self::getFromEnvOrDICParams($argument);
257
    }
258
259
    /**
260
     * @param string $parameter
261
     *
262
     * @return mixed|string|null
263
     */
264
    private static function getFromEnvOrDICParams($parameter)
265
    {
266
        if (is_string($parameter)) {
0 ignored issues
show
introduced by
The condition is_string($parameter) is always true.
Loading history...
267
            if (null !== self::getEnvKey($parameter)) {
268
                return (getenv(self::getEnvKey($parameter))) ? getenv(self::getEnvKey($parameter)) : $parameter;
269
            }
270
271
            return (DICParams::has(self::getParamKey($parameter))) ? DICParams::get(self::getParamKey($parameter)) : $parameter;
272
        }
273
274
        return $parameter;
275
    }
276
277
    /**
278
     * Extract from a string like %env(FOO)%
279
     *
280
     * @param string $string
281
     *
282
     * @return mixed|null
283
     */
284
    private static function getEnvKey($string)
285
    {
286
        preg_match('~%env\((.*?)\)%~', $string, $matches);
287
288
        return (count($matches) > 0) ? $matches[1] : null;
289
    }
290
291
    /**
292
     * @param string $string
293
     *
294
     * @return string
295
     */
296
    private static function getParamKey($string)
297
    {
298
        return trim($string, '%');
299
    }
300
}
301