Passed
Push — master ( 7c2a71...ab3064 )
by Mauro
01:59
created

DIC::getCache()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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