Passed
Push — master ( ab3064...f18de6 )
by Mauro
02:00
created

DIC::saveCacheFile()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

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