Passed
Push — master ( 641400...00c924 )
by Akmal
02:10
created

Route::getSecondary()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace OpenEngine\Mika\Core\Components\Route;
4
5
use OpenEngine\Mika\Core\Components\Di\Di;
6
use OpenEngine\Mika\Core\Components\Di\Exceptions\ClassNotFoundException;
7
use OpenEngine\Mika\Core\Components\Di\Exceptions\MethodNotFoundException;
8
use OpenEngine\Mika\Core\Components\Di\Exceptions\MissingMethodArgumentException;
9
use OpenEngine\Mika\Core\Components\Http\Exceptions\NotFoundHttpException;
10
use OpenEngine\Mika\Core\Components\Route\Interfaces\RouteConfigInterface;
11
use OpenEngine\Mika\Core\Components\Route\Interfaces\RouteInterface;
12
use OpenEngine\Mika\Core\Helpers\Path;
13
use Psr\Container\ContainerInterface;
14
use Psr\Http\Message\RequestInterface;
15
use Psr\Http\Message\ResponseInterface;
16
17
/**
18
 * Class Route
19
 * @package OpenEngine\Mika\Core\Components\Route
20
 */
21
class Route implements RouteInterface
22
{
23
    /**
24
     * Default route name
25
     */
26
    public const DEFAULT_ROUTE = 'default';
27
28
    /**
29
     * @var RequestInterface
30
     */
31
    private $request;
32
33
    /**
34
     * @var string
35
     */
36
    private $main;
37
38
    /**
39
     * @var string
40
     */
41
    private $secondary;
42
43
    /**
44
     * @var string
45
     */
46
    private $action;
47
48
    /**
49
     * @var string
50
     */
51
    private $current;
52
53
    /**
54
     * @var array
55
     */
56
    private $routes;
57
58
    /**
59
     * @var ContainerInterface|Di
60
     */
61
    private $container;
62
63
    /**
64
     * @inheritdoc
65
     */
66
    public function __construct
67
    (
68
        RouteConfigInterface $routeConfig,
69
        RequestInterface $request,
70
        ContainerInterface $container
71
    ) {
72
        $this->routes = $routeConfig->getRoutes();
73
        $this->request = $request;
74
75
        $this->parseUri();
76
        $this->container = $container;
77
    }
78
79
    /**
80
     * @inheritdoc
81
     */
82
    public function getCurrent(): string
83
    {
84
        return $this->current;
85
    }
86
87
    /**
88
     * @inheritdoc
89
     */
90
    public function getMain(): string
91
    {
92
        return $this->main;
93
    }
94
95
    /**
96
     * @inheritdoc
97
     */
98
    public function getSecondary(): string
99
    {
100
        return $this->secondary;
101
    }
102
103
    /**
104
     * @inheritdoc
105
     */
106
    public function getAction(): string
107
    {
108
        return $this->action;
109
    }
110
111
    /**
112
     * {@inheritdoc}
113
     * @throws ClassNotFoundException
114
     * @throws NotFoundHttpException
115
     * @throws MethodNotFoundException
116
     * @throws MissingMethodArgumentException
117
     */
118
    public function callControllerAction(): ResponseInterface
119
    {
120
        $controller = $this->getController();
121
        return $this->callAction($controller);
122
    }
123
124
    /**
125
     * @inheritdoc
126
     */
127
    public function getRoutes(): array
128
    {
129
        return $this->routes;
130
    }
131
132
    /**
133
     * @return object
134
     * @throws ClassNotFoundException
135
     * @throws MethodNotFoundException
136
     * @throws MissingMethodArgumentException
137
     * @throws NotFoundHttpException
138
     */
139
    public function getController(): object
140
    {
141
        foreach ($this->getRoute($this->getMain()) as $className) {
142
            $controller = basename(Path::getPathByNamespace($className), 'Controller');
143
144
            if ($controller === ucfirst($this->getSecondary())) {
145
                return $this->container->createObject($className);
146
            }
147
        }
148
149
        throw new NotFoundHttpException('Controller for ' . $this->getCurrent() . ' is not found');
150
    }
151
152
    /**
153
     * @inheritdoc
154
     */
155
    private function hasRoute(string $name): bool
156
    {
157
        return isset($this->routes[$name]);
158
    }
159
160
    /**
161
     * Get registered as $name route
162
     *
163
     * @param string $name
164
     * @return array
165
     * @throws NotFoundHttpException Throws this exception when $name route is not registered
166
     */
167
    private function getRoute(string $name): array
168
    {
169
        if (!$this->hasRoute($name)) {
170
            throw new NotFoundHttpException('Route ' . $name . ' is not registered');
171
        }
172
173
        return $this->routes[$name];
174
175
    }
176
177
    private function parseUri(): void
178
    {
179
        $parts = explode('/', $this->request->getUri()->getPath());
180
181
        $this->main = $this->getPart($parts, 1);
182
        $this->secondary = $this->getPart($parts, 2);
183
        $this->action = $this->getPart($parts, 3);
184
185
        $this->current =
186
            '/' . $this->main .
187
            '/' . $this->secondary .
188
            '/' . $this->action;
189
    }
190
191
    private function getPart(array $parts, $key): string
192
    {
193
        return !empty($parts[$key]) && $parts[$key] !== '/' ? $parts[$key] :  self::DEFAULT_ROUTE;
194
195
    }
196
197
    /**
198
     * @param object $controller
199
     * @return ResponseInterface
200
     * @throws MethodNotFoundException
201
     * @throws MissingMethodArgumentException
202
     */
203
    private function callAction(object $controller): ResponseInterface
204
    {
205
        $methodName = $this->getAction() . 'Action';
206
        // todo user Request method instead of $_GET
207
208
        $depends = $this->container->createMethodDepends(\get_class($controller), $methodName, $_GET);
209
        return \call_user_func_array([$controller, $methodName], $depends);
210
    }
211
}
212