Passed
Push — master ( a4ddd3...82bd79 )
by Alex
06:44
created

UrlParser   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 148
Duplicated Lines 0 %

Importance

Changes 6
Bugs 1 Features 1
Metric Value
wmc 16
eloc 44
c 6
b 1
f 1
dl 0
loc 148
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A _getRouteMatcherRegExPattern() 0 19 3
A getDynamicRouteProcessor() 0 28 5
A _getParameterNames() 0 26 4
A warmCache() 0 15 4
1
<?php
2
declare(strict_types = 1);
3
namespace Mezon\Router;
4
5
use Mezon\Router\Types\BaseType;
6
7
/**
8
 * Trait UrlParser
9
 *
10
 * @package Router
11
 * @author Dodonov A.A.
12
 * @version v.1.0 (2021/09/27)
13
 * @copyright Copyright (c) 2021, aeon.org
14
 */
15
trait UrlParser
16
{
17
18
    use UrlParserBase;
19
20
    /**
21
     * Called route
22
     *
23
     * @var string
24
     */
25
    protected $calledRoute = '';
26
27
    /**
28
     * Cache for regular expressions
29
     *
30
     * @var string[]
31
     */
32
    private $cachedRegExps = [];
33
34
    /**
35
     * Cached parameters for route
36
     *
37
     * @var array<string, string[]>
38
     */
39
    private $cachedParameters = [];
40
41
    /**
42
     * Method compiles route pattern string in regex string.
43
     * For example [i:id]/some-str in ([\[0-9\]])/some-str
44
     *
45
     * @param string $routerPattern
46
     *            router pattern
47
     * @return string regexp pattern
48
     * @psalm-suppress MixedMethodCall
49
     */
50
    private function _getRouteMatcherRegExPattern(string $routerPattern): string
51
    {
52
        $key = $routerPattern;
53
54
        // try read from cache
55
        if (isset($this->cachedRegExps[$key])) {
56
            return $this->cachedRegExps[$key];
57
        }
58
59
        // parsing routes
60
        $compiledRouterPattern = $routerPattern;
61
        foreach ($this->types as $typeClass) {
62
            $compiledRouterPattern = preg_replace('/' . $typeClass::searchRegExp() . '/', '(' . $typeClass::parserRegExp() . ')', $compiledRouterPattern);
63
        }
64
65
        // final setup + save in cache
66
        $this->cachedRegExps[$key] = $compiledRouterPattern;
67
68
        return $compiledRouterPattern;
69
    }
70
71
    /**
72
     * Method returns all parameter names in the route
73
     *
74
     * @param string $routerPattern
75
     *            route
76
     * @return string[] names
77
     */
78
    private function _getParameterNames(string $routerPattern): array
79
    {
80
        if (isset($this->cachedParameters[$routerPattern])) {
81
            return $this->cachedParameters[$routerPattern];
82
        }
83
84
        $regExPattern = [];
85
86
        foreach (array_keys($this->types) as $typeName) {
87
            $regExPattern[] = $typeName;
88
        }
89
90
        $regExPattern = '\[(' . implode('|', $regExPattern) . '):(' . BaseType::PARAMETER_NAME_REGEXP . ')\]';
91
92
        $names = [];
93
        preg_match_all('/' . str_replace('/', '\\/', $regExPattern) . '/', $routerPattern, $names);
94
95
        $return = [];
96
97
        foreach ($names[2] as $name) {
98
            $return[] = $name;
99
        }
100
101
        $this->cachedParameters[$routerPattern] = $return;
102
103
        return $return;
104
    }
105
106
    /**
107
     * Method warms cache
108
     */
109
    public function warmCache(): void
110
    {
111
        foreach (SuppportedRequestMethods::getListOfSupportedRequestMethods() as $requestMethod) {
112
            /** @var array{bunch: array} $bunch */
113
            foreach ($this->paramRoutes[$requestMethod] as $bunch) {
114
                /** @var array{pattern: string} $route */
115
                foreach ($bunch['bunch'] as $route) {
116
                    $this->_getRouteMatcherRegExPattern($route['pattern']);
117
118
                    $this->_getParameterNames($route['pattern']);
119
                }
120
            }
121
        }
122
123
        $this->compileRegexpForBunches();
0 ignored issues
show
Bug introduced by
It seems like compileRegexpForBunches() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

123
        $this->/** @scrutinizer ignore-call */ 
124
               compileRegexpForBunches();
Loading history...
124
    }
125
126
    /**
127
     * Method searches dynamic route processor
128
     *
129
     * @param string $route
130
     *            route
131
     * @param string $requestMethod
132
     *            request method
133
     * @return array{0: string, 1:string}|callable|false route's handler or false in case the handler was not found
134
     */
135
    protected function getDynamicRouteProcessor(string $route, string $requestMethod = '')
136
    {
137
        $bunches = $this->paramRoutes[$requestMethod == '' ? $this->getRequestMethod() : $requestMethod];
138
139
        /** @var array{bunch: string[], regexp: string} $bunch */
140
        foreach ($bunches as $bunch) {
141
            $matches = [];
142
143
            if (preg_match($bunch['regexp'], $route, $matches)) {
144
                /** @var array{pattern: string, callback: callable} $routeData */
145
                $routeData = $bunch['bunch'][count($matches)];
146
147
                $names = $this->_getParameterNames($routeData['pattern']);
148
149
                $this->parameters = [];
150
                foreach ($names as $i => $name) {
151
                    /** @var string[] $matches */
152
                    $this->parameters[$name] = $matches[(int) $i + 1];
153
                }
154
155
                $this->calledRoute = $routeData['pattern'];
156
157
                return $routeData['callback'];
158
            }
159
        }
160
161
        // match was not found
162
        return false;
163
    }
164
}
165