Passed
Push — 5.x ( 01ab87...adf9b9 )
by Phil
01:40
created

Route::getPath()   B

Complexity

Conditions 11
Paths 27

Size

Total Lines 56
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 11.0492

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 28
c 1
b 0
f 0
dl 0
loc 56
ccs 25
cts 27
cp 0.9259
rs 7.3166
cc 11
nc 27
nop 1
crap 11.0492

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace League\Route;
6
7
use FastRoute\RouteParser\Std;
8
use League\Route\Middleware\{MiddlewareAwareInterface, MiddlewareAwareTrait};
9
use League\Route\Strategy\{StrategyAwareInterface, StrategyAwareTrait, StrategyInterface};
10
use Psr\Container\ContainerInterface;
11
use Psr\Http\Message\{ResponseInterface, ServerRequestInterface};
12
use Psr\Http\Server\{MiddlewareInterface, RequestHandlerInterface};
13
use RuntimeException;
14
15
class Route implements
16
    MiddlewareInterface,
17
    MiddlewareAwareInterface,
18
    RouteConditionHandlerInterface,
19
    StrategyAwareInterface
20
{
21
    use MiddlewareAwareTrait;
22
    use RouteConditionHandlerTrait;
23
    use StrategyAwareTrait;
24
25
    /**
26
     * @var callable|string
27
     */
28
    protected $handler;
29
30
    /**
31
     * @var RouteGroup
32
     */
33
    protected $group;
34
35
    /**
36
     * @var string
37
     */
38
    protected $method;
39
40
    /**
41
     * @var string
42
     */
43
    protected $path;
44
45
    /**
46
     * @var array
47
     */
48
    protected $vars = [];
49
50 126
    public function __construct(string $method, string $path, $handler)
51
    {
52 126
        $this->method  = $method;
53 126
        $this->path    = $path;
54 126
        $this->handler = $handler;
55 126
    }
56
57 60
    public function getCallable(?ContainerInterface $container = null): callable
58
    {
59 60
        $callable = $this->handler;
60
61 60
        if (is_string($callable) && strpos($callable, '::') !== false) {
62 6
            $callable = explode('::', $callable);
63
        }
64
65 60
        if (is_array($callable) && isset($callable[0]) && is_object($callable[0])) {
0 ignored issues
show
introduced by
The condition is_object($callable[0]) is always false.
Loading history...
66 3
            $callable = [$callable[0], $callable[1]];
67
        }
68
69 60
        if (is_array($callable) && isset($callable[0]) && is_string($callable[0])) {
70 6
            $callable = [$this->resolve($callable[0], $container), $callable[1]];
71
        }
72
73 60
        if (is_string($callable)) {
74 3
            $callable = $this->resolve($callable, $container);
75
        }
76
77 60
        if (!is_callable($callable)) {
78 3
            throw new RuntimeException('Could not resolve a callable for this route');
79
        }
80
81 57
        return $callable;
82
    }
83
84 54
    public function getMethod(): string
85
    {
86 54
        return $this->method;
87
    }
88
89 42
    public function getParentGroup(): ?RouteGroup
90
    {
91 42
        return $this->group;
92
    }
93
94 93
    public function getPath(?array $replacements = null): string
95
    {
96 93
        if (null === $replacements) {
97 57
            return $this->path;
98
        }
99
100 36
        $hasReplacementRegex = '/{(' . implode('|', array_keys($replacements)) . ')(:.*)?}/';
101
102 36
        preg_match_all('/\[(.*?)?{(?<keys>.*?)}/', $this->path, $matches);
103
104
        $isOptionalRegex = '/(.*)?{('
105 36
            . implode('|', $matches['keys'])
106 36
            . ')(:.*)?}(.*)?/'
107
        ;
108
109
        $isPartiallyOptionalRegex = '/^([^\[\]{}]+)?\[((?:.*)?{(?:'
110 36
            . implode('|', $matches['keys'])
111 36
            . ')(?::.*)?}(?:.*)?)\]?([^\[\]{}]+)?(?:[\[\]]+)?$/'
112
        ;
113
114 36
        $toReplace = [];
115
116 36
        foreach ($replacements as $wildcard => $actual) {
117 27
            $toReplace['/{' . preg_quote($wildcard, '/') . '(:.*)?}/'] = $actual;
118
        }
119
120 36
        $segments = [];
121
122 36
        foreach (array_filter(explode('/', $this->path)) as $segment) {
123
            // segment is partially optional with a wildcard, strip it if no match, tidy up if match
124 36
            if (preg_match($isPartiallyOptionalRegex, $segment)) {
125 6
                $segment = preg_match($hasReplacementRegex, $segment)
126 3
                    ? preg_replace($isPartiallyOptionalRegex, '$1$2$3', $segment)
127 6
                    : preg_replace($isPartiallyOptionalRegex, '$1', $segment)
128
                ;
129
            }
130
131
            // segment either isn't a wildcard or there is a replacement
132 36
            if (!preg_match('/{(.*?)}/', $segment) || preg_match($hasReplacementRegex, $segment)) {
133 36
                $segments[] = preg_replace(['/\[$/', '/\]+$/'], '', $segment);
134 36
                continue;
135
            }
136
137
            // segment is a required wildcard, no replacement, still gets added
138 18
            if (!preg_match($isOptionalRegex, $segment)) {
139
                $segments[] = preg_replace(['/\[$/', '/\]+$/'], '', $segment);
140
                continue;
141
            }
142
143
            // segment is completely optional with no replacement, strip it and break
144 18
            if (preg_match($isOptionalRegex, $segment) && !preg_match($hasReplacementRegex, $segment)) {
145 18
                break;
146
            }
147
        }
148
149 36
        return preg_replace(array_keys($toReplace), array_values($toReplace), '/' . implode('/', $segments));
150
    }
151
152 42
    public function getVars(): array
153
    {
154 42
        return $this->vars;
155
    }
156
157 42
    public function process(
158
        ServerRequestInterface $request,
159
        RequestHandlerInterface $handler
160
    ): ResponseInterface {
161 42
        $strategy = $this->getStrategy();
162
163 42
        if (!($strategy instanceof StrategyInterface)) {
164 3
            throw new RuntimeException('A strategy must be set to process a route');
165
        }
166
167 39
        return $strategy->invokeRouteCallable($this, $request);
168
    }
169
170 15
    public function setParentGroup(RouteGroup $group): self
171
    {
172 15
        $this->group = $group;
173 15
        $prefix      = $this->group->getPrefix();
174 15
        $path        = $this->getPath();
175
176 15
        if (strcmp($prefix, substr($path, 0, strlen($prefix))) !== 0) {
177 3
            $path = $prefix . $path;
178 3
            $this->path = $path;
179
        }
180
181 15
        return $this;
182
    }
183
184 42
    public function setVars(array $vars): self
185
    {
186 42
        $this->vars = $vars;
187 42
        return $this;
188
    }
189
190 9
    protected function resolve(string $class, ?ContainerInterface $container = null)
191
    {
192 9
        if ($container instanceof ContainerInterface && $container->has($class)) {
193 3
            return $container->get($class);
194
        }
195
196 6
        if (class_exists($class)) {
197 3
            return new $class();
198
        }
199
200 3
        return $class;
201
    }
202
}
203