Completed
Push — master ( 369b2c...ffb215 )
by Anton
8s
created

Reflection::prepareCache()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 16
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 6.2163
Metric Value
dl 0
loc 16
ccs 9
cts 11
cp 0.8182
rs 8.8571
cc 6
eloc 13
nc 6
nop 1
crap 6.2163
1
<?php
2
/**
3
 * Bluz Framework Component
4
 *
5
 * @copyright Bluz PHP Team
6
 * @link https://github.com/bluzphp/framework
7
 */
8
9
/**
10
 * @namespace
11
 */
12
namespace Bluz\Controller;
13
14
use Bluz\Common\Exception\ComponentException;
15
use Bluz\Common\Options;
16
17
/**
18
 * Reflection
19
 *
20
 * @package  Bluz\Controller
21
 * @author   Anton Shevchuk
22
 */
23
class Reflection
24
{
25
    use Options;
26
27
    /**
28
     * @var string full path to file
29
     */
30
    protected $file;
31
32
    /**
33
     * @var integer cache TTL
34
     */
35
    protected $cache = 0;
36
37
    /**
38
     * @var integer cache TTL for HTML content
39
     */
40
    protected $cacheHtml = 0;
41
42
    /**
43
     * @var array list of Accept
44
     */
45
    protected $accept = array();
46
47
    /**
48
     * @var array list of HTTP methods
49
     */
50
    protected $method = array();
51
52
    /**
53
     * @var array described params
54
     */
55
    protected $params = array();
56
57
    /**
58
     * @var string privilege
59
     */
60
    protected $privilege;
61
62
    /**
63
     * @var array routers
64
     */
65
    protected $route = array();
66
67
    /**
68
     * @var array default values of params
69
     */
70
    protected $values = array();
71
72
    /**
73
     * Constructor of Reflection
74
     *
75
     * @param string $file
76
     */
77 669
    public function __construct($file)
78
    {
79 669
        $this->file = $file;
80 669
    }
81
82
    /**
83
     * Set state required for working with var_export (used inside PHP File cache)
84
     *
85
     * @param  $array
86
     * @return Reflection
87
     */
88
    public static function __set_state($array)
89
    {
90
        $instance = new Reflection($array['file']);
91
        foreach ($array as $key => $value) {
92
            $instance->{$key} = $value;
93
        }
94
        return $instance;
95
    }
96
97
    /**
98
     * Process to get reflection from file
99
     *
100
     * @return void
101
     * @throws ComponentException
102
     */
103 669
    public function process()
104
    {
105
        // workaround for get reflection of closure function
106 669
        $bootstrap = $view = $module = $controller = null;
107
        /** @var \Closure|object $closure */
108 669
        $closure = include $this->file;
109
110 669
        if (!is_callable($closure)) {
111 1
            throw new ComponentException("There is no callable structure in file `{$this->file}`");
112
        }
113
114 669
        if ($closure instanceof \Closure) {
115 669
            $reflection = new \ReflectionFunction($closure);
116
        } else {
117 1
            $reflection = new \ReflectionObject($closure);
118
        }
119
120
        // check and normalize params by doc comment
121 669
        $docComment = $reflection->getDocComment();
122
123
        // get all options by one regular expression
124 669
        if (preg_match_all('/\s*\*\s*\@([a-z0-9-_]+)\s+(.*).*\s+/i', $docComment, $matches)) {
125 669
            foreach ($matches[1] as $i => $key) {
126 669
                $this->setOption($key, $matches[2][$i]);
127
            }
128
        }
129
130
        // init routes
131 669
        $this->initRoute();
132
133
        // parameters available for Closure only
134 669
        if ($reflection instanceof \ReflectionFunction) {
135
            // get params and convert it to simple array
136 669
            $reflectionParams = $reflection->getParameters();
137
            // setup params and optional params
138 669
            foreach ($reflectionParams as $param) {
139 669
                $name = $param->getName();
140
                // if some function params is missed in description
141 669
                if (!isset($this->params[$name])) {
142 669
                    $this->params[$name] = null;
143
                }
144 669
                if ($param->isOptional()) {
145 669
                    $this->values[$name] = $param->getDefaultValue();
146
                }
147
            }
148
        }
149 669
    }
150
151
    /**
152
     * Process request params
153
     *
154
     *  - type conversion
155
     *  - set default value
156
     *
157
     * @param  array $requestParams
158
     * @return array
159
     */
160 2
    public function params($requestParams)
161
    {
162
        // apply type and default value for request params
163 2
        $params = array();
164 2
        foreach ($this->params as $param => $type) {
165 1
            if (isset($requestParams[$param])) {
166
                switch ($type) {
167 1
                    case 'bool':
168 1
                    case 'boolean':
169
                        $params[] = (bool)$requestParams[$param];
170
                        break;
171 1
                    case 'int':
172 1
                    case 'integer':
173 1
                        $params[] = (int)$requestParams[$param];
174 1
                        break;
175 1
                    case 'float':
176
                        $params[] = (float)$requestParams[$param];
177
                        break;
178 1
                    case 'string':
179 1
                        $params[] = (string)$requestParams[$param];
180 1
                        break;
181
                    case 'array':
182
                        $params[] = (array)$requestParams[$param];
183
                        break;
184
                    default:
185
                        $params[] = $requestParams[$param];
186 1
                        break;
187
                }
188
            } elseif (isset($this->values[$param])) {
189
                $params[] = $this->values[$param];
190
            } else {
191 1
                $params[] = null;
192
            }
193
        }
194 2
        return $params;
195
    }
196
197
    /**
198
     * Get path to file
199
     *
200
     * @return string
201
     */
202
    public function getFile()
203
    {
204
        return $this->file;
205
    }
206
207
    /**
208
     * Get Cache TTL
209
     *
210
     * @return integer
211
     */
212 4
    public function getCache()
213
    {
214 4
        return $this->cache;
215
    }
216
217
    /**
218
     * Set Cache TTL
219
     *
220
     * @param  string $ttl
221
     * @return void
222
     */
223 3
    public function setCache($ttl)
224
    {
225 3
        $this->cache = $this->prepareCache($ttl);
226 3
    }
227
228
    /**
229
     * Get HTML Cache TTL
230
     *
231
     * @return integer
232
     */
233 3
    public function getCacheHtml()
234
    {
235 3
        return $this->cacheHtml;
236
    }
237
238
    /**
239
     * Set HTML Cache TTL
240
     *
241
     * @param  string $ttl
242
     * @return void
243
     */
244 3
    public function setCacheHtml($ttl)
245
    {
246 3
        $this->cacheHtml = $this->prepareCache($ttl);
247 3
    }
248
249
    /**
250
     * Prepare Cache
251
     *
252
     * @param  string $cache
253
     * @return integer
254
     */
255 3
    protected function prepareCache($cache)
256
    {
257 3
        $num = (int)$cache;
258 3
        $time = substr($cache, strpos($cache, ' '));
259
        switch ($time) {
260 3
            case 'day':
261 3
            case 'days':
262
                return (int)$num * 60 * 60 *24;
263 3
            case 'hour':
264 3
            case 'hours':
265
                return (int)$num * 60 * 60;
266 3
            case 'min':
267
            default:
268 3
                return (int)$num * 60;
269
        }
270
    }
271
272
    /**
273
     * Get accepted type
274
     *
275
     * @todo move here "accept map" from Application
276
     * @return array|null
277
     */
278 1
    public function getAccept()
279
    {
280 1
        return sizeof($this->accept)?$this->accept:null;
281
    }
282
283
    /**
284
     * Set accepted types
285
     *
286
     * @param  string $accept
287
     * @return void
288
     */
289
    public function setAccept($accept)
290
    {
291
        $this->accept[] = strtoupper($accept);
292
    }
293
294
    /**
295
     * Get HTTP Method
296
     *
297
     * @return array|null
298
     */
299 3
    public function getMethod()
300
    {
301 3
        return sizeof($this->method)?$this->method:null;
302
    }
303
304
    /**
305
     * Set HTTP Method
306
     *
307
     * @param  string $method
308
     * @return void
309
     */
310 3
    public function setMethod($method)
311
    {
312 3
        $this->method[] = strtoupper($method);
313 3
    }
314
315
    /**
316
     * Get all params
317
     *
318
     * @return array
319
     */
320 669
    public function getParams()
321
    {
322 669
        return $this->params;
323
    }
324
325
    /**
326
     * Set param types
327
     *
328
     * @param  string $param
329
     * @return void
330
     */
331 669
    public function setParam($param)
332
    {
333
        // prepare params data
334
        // setup param types
335 669
        if (strpos($param, '$') === false) {
336
            return;
337
        }
338
339 669
        list($type, $key) = preg_split('/[ $]+/', $param);
340
341 669
        $this->params[$key] = trim($type);
342 669
    }
343
344
    /**
345
     * Get Privilege fo ACL
346
     *
347
     * @return string
348
     */
349 4
    public function getPrivilege()
350
    {
351 4
        return $this->privilege;
352
    }
353
354
    /**
355
     * Set Privilege fo ACL allow only one privilege
356
     *
357
     * @param  string $privilege
358
     * @return void
359
     */
360 3
    public function setPrivilege($privilege)
361
    {
362 3
        $this->privilege = $privilege;
363 3
    }
364
365
    /**
366
     * Get Route
367
     *
368
     * @return array|null
369
     */
370 669
    public function getRoute()
371
    {
372 669
        return sizeof($this->route)?$this->route:null;
373
    }
374
375
    /**
376
     * Set Route
377
     *
378
     * @param  string $route
379
     * @return void
380
     */
381 669
    public function setRoute($route)
382
    {
383 669
        $this->route[$route] = null;
384 669
    }
385
386
    /**
387
     * Init Route
388
     *
389
     * @return void
390
     */
391 669
    protected function initRoute()
392
    {
393 669
        foreach ($this->route as $route => &$pattern) {
394 669
            $pattern = $this->prepareRoutePattern($route);
395
        }
396 669
    }
397
398
    /**
399
     * Prepare Route pattern
400
     *
401
     * @param  string $route
402
     * @return string
403
     */
404 669
    protected function prepareRoutePattern($route)
405
    {
406 669
        $pattern = str_replace('/', '\/', $route);
407
408 669
        foreach ($this->getParams() as $param => $type) {
409
            switch ($type) {
410 669
                case 'int':
411 669
                case 'integer':
412 669
                    $pattern = str_replace("{\$" . $param . "}", "(?P<$param>[0-9]+)", $pattern);
413 669
                    break;
414 669
                case 'float':
415 669
                    $pattern = str_replace("{\$" . $param . "}", "(?P<$param>[0-9.,]+)", $pattern);
416 669
                    break;
417 669
                case 'string':
418
                case 'module':
419
                case 'controller':
420 669
                    $pattern = str_replace(
421 669
                        "{\$" . $param . "}",
422 669
                        "(?P<$param>[a-zA-Z0-9-_.]+)",
423
                        $pattern
424
                    );
425 669
                    break;
426
            }
427
        }
428 669
        return '/^' . $pattern . '/i';
429
    }
430
}
431