Completed
Pull Request — master (#422)
by Anton
05:12
created

Meta::setAcl()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
426
            switch ($type) {
427 712
                case 'int':
428 712
                case 'integer':
429 712
                    $pattern = str_replace("{\$$param}", "(?P<$param>[0-9]+)", $pattern);
430 712
                    break;
431 712
                case 'float':
432 712
                    $pattern = str_replace("{\$$param}", "(?P<$param>[0-9.,]+)", $pattern);
433 712
                    break;
434 712
                case 'string':
435 712
                case 'module':
436 712
                case 'controller':
437 712
                    $pattern = str_replace(
438 712
                        "{\$$param}",
439 712
                        "(?P<$param>[a-zA-Z0-9-_.]+)",
440 712
                        $pattern
441
                    );
442 712
                    break;
443
            }
444
        }
445 712
        return '/^' . $pattern . '/i';
446
    }
447
}
448