Passed
Push — master ( 0f979d...0862ec )
by Hong
02:33 queued 13s
created

Route::setPattern()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 6
c 1
b 0
f 0
nc 3
nop 2
dl 0
loc 10
rs 10
1
<?php
2
3
/**
4
 * Phoole (PHP7.2+)
5
 *
6
 * @category  Library
7
 * @package   Phoole\Route
8
 * @copyright Copyright (c) 2019 Hong Zhang
9
 */
10
declare(strict_types=1);
11
12
namespace Phoole\Route\Util;
13
14
/**
15
 * Route
16
 *
17
 * @package Phoole\Route
18
 */
19
class Route
20
{
21
    /**
22
     * @var string[]
23
     */
24
    protected $methods;
25
26
    /**
27
     * @var string
28
     */
29
    protected $pattern;
30
31
    /**
32
     * @param  string|string[] $method  HTTP method[s]
33
     * @param  string $pattern          URI pattern to match
34
     * @param  mixed $handler           request handler
35
     * @param  array $defaults          default parameters
36
     * @throws \LogicException          if pattern not right
37
     */
38
    public function __construct(
39
        $method,
40
        string $pattern,
41
        $handler,
42
        array $defaults = []
43
    ) {
44
        $this
45
            ->setPattern($pattern, $defaults)
46
            ->setMethods($method, $handler, $defaults);
47
    }
48
49
    /**
50
     * Set route pattern
51
     *
52
     * @param  string $pattern
53
     * @param  array  &$defaults
54
     * @return Route  $this
55
     * @throws \LogicException  if pattern not right
56
     */
57
    public function setPattern(string $pattern, &$defaults): Route
58
    {
59
        if ($this->validatePattern($pattern)) {
60
            list($pattern, $params) = $this->extractDefaults($pattern);
61
            $this->pattern = $pattern;
62
            if (!empty($params)) {
63
                $defaults = array_merge($params, $defaults);
64
            }
65
        }
66
        return $this;
67
    }
68
69
    /**
70
     * @return string
71
     */
72
    public function getPattern(): string
73
    {
74
        return $this->pattern;
75
    }
76
77
    /**
78
     * Set methods(with related handler/defaults)
79
     *
80
     * @param  string|string[] $method
81
     * @param  mixed $handler
82
     * @param  array $defaults
83
     * @return Route $this
84
     */
85
    public function setMethods($method, $handler, array $defaults): Route
86
    {
87
        $methods = is_string($method) ?
88
            preg_split('~[^A-Z]+~', strtoupper($method), -1, PREG_SPLIT_NO_EMPTY) :
89
            array_map('strtoupper', $method);
90
        
91
        foreach ($methods as $mth) {
92
            $this->methods[$mth] = [$handler, $defaults];
93
        }
94
        return $this;
95
    }
96
97
    /**
98
     * Add new methods from another route
99
     *
100
     * @param  Route $route  another route
101
     * @return Route $this
102
     */
103
    public function addMethods(Route $route): Route
104
    {
105
        $this->methods = array_merge($this->methods, $route->getMethods());
106
        return $this;
107
    }
108
109
    /**
110
     * @param  array
111
     */
112
    public function getMethods(): array
113
    {
114
        return $this->methods;
115
    }
116
    
117
    /**
118
     * Validate the pattern
119
     *
120
     * @param  string $pattern
121
     * @return bool
122
     * @throws \LogicException  if not valid pattern
123
     */
124
    protected function validatePattern(string $pattern): bool
125
    {
126
        if (
127
            !is_string($pattern) ||
0 ignored issues
show
introduced by
The condition is_string($pattern) is always true.
Loading history...
128
            substr_count($pattern, '[') !== substr_count($pattern, ']') ||
129
            substr_count($pattern, '{') !== substr_count($pattern, '}')
130
        ) {
131
            throw new \LogicException("Invalid route pattern '$pattern'");
132
        }
133
        return true;
134
    }
135
136
    /**
137
     * Extract default values from the pattern
138
     *
139
     * @param  string $pattern
140
     * @return array
141
     */
142
    protected function extractDefaults(string $pattern): array
143
    {
144
        $vals = [];
145
        $regex = '~\{([a-zA-Z][a-zA-Z0-9_]*+)[^\}]*(=[a-zA-Z0-9._]++)\}~';
146
        if (preg_match_all($regex, $pattern, $matches, \PREG_SET_ORDER)) {
147
            $srch = $repl = [];
148
            foreach ($matches as $m) {
149
                $srch[] = $m[0];
150
                $repl[] = str_replace($m[2], '', $m[0]);
151
                $vals[$m[1]] = substr($m[2], 1);
152
            }
153
            
154
            $pattern = str_replace($srch, $repl, $pattern);
155
        }
156
        return [$pattern, $vals];
157
    }
158
}
159