Completed
Pull Request — master (#30)
by Eric
08:14 queued 18s
created

Router::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 18 and the first side effect is on line 3.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
declare(strict_types = 1);
4
5
namespace Jarvis\Skill\Routing;
6
7
use FastRoute\{
8
    DataGenerator\GroupCountBased as DataGenerator,
9
    Dispatcher\GroupCountBased as Dispatcher,
10
    RouteParser\Std as Parser,
11
    RouteCollector
12
};
13
use Jarvis\{Jarvis, Skill\Core\ScopeManager};
14
15
/**
16
 * @author Eric Chau <[email protected]>
17
 */
18
class Router extends Dispatcher
19
{
20
    private $rawRoutes = [];
21
    private $routesNames = [];
22
    private $routeCollector;
23
    private $compilationKey;
24
    private $scopeManager;
25
    private $host = '';
26
    private $scheme = 'http';
27
28
    public function __construct(ScopeManager $scopeManager)
29
    {
30
        $this->scopeManager = $scopeManager;
31
    }
32
33
    public function host() : string
34
    {
35
        return $this->host;
36
    }
37
38
    public function setHost(string $host = null) : Router
39
    {
40
        $this->host = (string) $host;
41
42
        return $this;
43
    }
44
45
    public function scheme() : string
46
    {
47
        return $this->scheme;
48
    }
49
50
    public function setScheme(string $scheme = null) : Router
51
    {
52
        $this->scheme = (string) $scheme ?: 'http';
53
54
        return $this;
55
    }
56
57
    /**
58
     * Alias to Router's route collector ::addRoute method.
59
     * @see RouteCollector::addRoute
60
     */
61
    public function addRoute(Route $route) : Router
62
    {
63
        $this->rawRoutes[$route->scope()] = $this->rawRoutes[$route->scope()] ?? [];
64
        $this->rawRoutes[$route->scope()][] = [$route->method(), $route->pattern(), $route->handler()];
65
        $this->compilationKey = null;
66
67
        if (null !== $name = $route->name()) {
68
            $this->routesNames[$name] = $route->pattern();
69
        }
70
71
        return $this;
72
    }
73
74
    public function beginRoute(string $name = null) : Route
75
    {
76
        return new Route($name, $this);
77
    }
78
79
    public function url(string $uri) : string
80
    {
81
        $scheme = '';
82
        if ($this->host) {
83
            $uri = preg_replace('~/+~', '/', "{$this->host}$uri");
84
            $scheme = "{$this->scheme}://";
85
        }
86
87
        return "$scheme$uri";
88
    }
89
90
    /**
91
     * Generates URI associated to provided route name.
92
     *
93
     * @param  string $name   The URI route name we want to generate
94
     * @param  array  $params Parameters to replace in pattern
95
     * @return string
96
     * @throws \InvalidArgumentException if provided route name is unknown
97
     */
98
    public function uri(string $name, array $params = []) : string
99
    {
100
        if (!isset($this->routesNames[$name])) {
101
            throw new \InvalidArgumentException(
102
                "Cannot generate URI for '$name' cause it does not exist."
103
            );
104
        }
105
106
        $uri = $this->routesNames[$name];
107
        foreach ($params as $key => $value) {
108
            if (1 !== preg_match("~\{($key:?[^}]*)\}~", $uri, $matches)) {
109
                continue;
110
            }
111
112
            $value = (string) $value;
113
            $pieces = explode(':', $matches[1]);
114
            if (1 < count($pieces) && 1 !== preg_match('~' . $pieces[1] . '~', $value)) {
115
                continue;
116
            }
117
118
            $uri = str_replace($matches[0], $value, $uri);
119
        }
120
121
        return $uri;
122
    }
123
124
    /**
125
     * Alias of GroupCountBased::dispatch.
126
     * {@inheritdoc}
127
     */
128
    public function match(string $method, string $uri)
129
    {
130
        return $this->dispatch($method, $uri);
131
    }
132
133
    public function dispatch($method, $uri)
134
    {
135
        list($this->staticRouteMap, $this->variableRouteData) = $this->routeCollector()->getData();
136
137
        return parent::dispatch(strtolower($method), $uri);
138
    }
139
140
    private function routeCollector() : RouteCollector
141
    {
142
        $key = $this->generateCompilationKey();
143
        if (null === $this->compilationKey || $this->compilationKey !== $key) {
144
            $this->compilationKey = $key;
145
            $this->routeCollector = new RouteCollector(new Parser(), new DataGenerator());
146
147
            $enabledRoutes = [];
148
            foreach ($this->rawRoutes as $scope => $rawRoutes) {
149
                if ($this->scopeManager->isEnabled($scope)) {
150
                    $enabledRoutes = array_merge($enabledRoutes, $rawRoutes);
151
                }
152
            }
153
154
            foreach ($enabledRoutes as $rawRoute) {
155
                list($method, $route, $handler) = $rawRoute;
156
                $this->routeCollector->addRoute($method, $route, $handler);
157
            }
158
        }
159
160
        return $this->routeCollector;
161
    }
162
163
    private function generateCompilationKey() : string
164
    {
165
        return md5(implode(',', $this->scopeManager->all()));
166
    }
167
}
168