Completed
Push — master ( 51d2f6...9c4758 )
by John
02:14
created

Router::validateExtension()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 0 Features 2
Metric Value
c 5
b 0
f 2
dl 0
loc 7
rs 9.4286
cc 3
eloc 4
nc 2
nop 1
1
<?php
2
namespace LunixREST\Router;
3
4
use LunixREST\AccessControl\AccessControl;
5
use LunixREST\Configuration\Configuration;
6
use LunixREST\Exceptions\AccessDeniedException;
7
use LunixREST\Exceptions\InvalidAPIKeyException;
8
use LunixREST\Exceptions\InvalidResponseFormatException;
9
use LunixREST\Exceptions\ThrottleLimitExceededException;
10
use LunixREST\Exceptions\UnknownEndpointException;
11
use LunixREST\Exceptions\UnknownResponseFormatException;
12
use LunixREST\Request\Request;
13
use LunixREST\Throttle\Throttle;
14
use ReflectionClass;
15
16
/**
17
 * Class Router
18
 * @package LunixREST\Router
19
 */
20
class Router {
21
    /**
22
     * @var AccessControl
23
     */
24
    protected $accessControl;
25
    /**
26
     * @var Throttle
27
     */
28
    protected $throttle;
29
    /**
30
     * @var Configuration
31
     */
32
    protected $outputConfig;
33
    /**
34
     * @var Configuration
35
     */
36
    protected $formatsConfig;
37
    /**
38
     * @var string
39
     */
40
    protected $endpointNamespace;
41
42
    /**
43
     * @param AccessControl $accessControl
44
     * @param Throttle $throttle
45
     * @param Configuration $formatsConfig
46
     * @param string $endpointNamespace
47
     */
48
    public function __construct(AccessControl $accessControl, Throttle $throttle, Configuration $formatsConfig, $endpointNamespace = ''){
49
        $this->accessControl = $accessControl;
50
        $this->throttle = $throttle;
51
        $this->formatsConfig = $formatsConfig;
52
        $this->endpointNamespace = $endpointNamespace;
53
    }
54
55
    /**
56
     * @param Request $request
57
     * @return string
58
     * @throws AccessDeniedException
59
     * @throws InvalidAPIKeyException
60
     * @throws InvalidResponseFormatException
61
     * @throws ThrottleLimitExceededException
62
     * @throws UnknownEndpointException
63
     * @throws UnknownResponseFormatException
64
     */
65
    public function handle(Request $request){
66
        $this->validateKey($request);
67
68
        $this->validateExtension($request);
69
70
        $fullEndpoint = $this->endpointClass($request);
71
72
        $this->validateEndpoint($fullEndpoint);
73
74
        $this->throttle($request);
75
76
        $this->validateAccess($request);
77
78
        $responseData = $this->executeEndpoint($fullEndpoint, $request);
79
80
        $this->validateResponse($responseData);
81
82
        $responseClass = $this->responseClass($request);
83
        $format = new $responseClass($responseData);
84
85
        return $format->output();
86
    }
87
88
    /**
89
     * @param Request $request
90
     * @return string
91
     */
92
    private function endpointClass(Request $request){
93
        return '\\' . $this->endpointNamespace . '\Endpoints\v' . str_replace('.', '_', $request->getVersion()) . '\\' . $request->getEndpoint();
94
    }
95
96
    /**
97
     * @param Request $request
98
     * @return string
99
     */
100
    private function responseClass(Request $request){
101
        return '\\LunixREST\\Response\\' . strtoupper($request->getExtension()) . "Response";
102
    }
103
104
    /**
105
     * @param Request $request
106
     * @throws InvalidAPIKeyException
107
     */
108
    private function validateKey(Request $request){
109
        if(!$this->accessControl->validateKey($request->getApiKey())){
110
            throw new InvalidAPIKeyException('Invalid API key');
111
        }
112
    }
113
114
    /**
115
     * @param Request $request
116
     * @return bool
117
     * @throws UnknownResponseFormatException
118
     */
119
    private function validateExtension(Request $request)
120
    {
121
        $formats = $this->formatsConfig->get('formats');
122
        if(!($formats && in_array($request->getExtension(), $formats))){
123
            throw new UnknownResponseFormatException('Unknown response format: ' .$request->getExtension());
124
        }
125
    }
126
127
    /**
128
     * @param $fullEndpoint
129
     * @throws UnknownEndpointException
130
     */
131
    private function validateEndpoint($fullEndpoint){
132
        $endpointReflection = new \ReflectionClass($fullEndpoint);
133
        if(!class_exists($fullEndpoint) || !$endpointReflection->isSubclassOf('\LunixREST\Endpoints\Endpoint')){
134
            throw new UnknownEndpointException("unknown endpoint: " . $fullEndpoint);
135
        }
136
    }
137
138
    /**
139
     * @param Request $request
140
     * @throws ThrottleLimitExceededException
141
     */
142
    private function throttle(Request $request){
143
        if($this->throttle->throttle($request)){
144
            throw new ThrottleLimitExceededException('Request limit exceeded');
145
        }
146
    }
147
148
    /**
149
     * @param Request $request
150
     * @throws AccessDeniedException
151
     */
152
    private function validateAccess(Request $request){
153
        if(!$this->accessControl->validateAccess($request)){
154
            throw new AccessDeniedException("API key does not have the required permissions to access requested resource");
155
        }
156
    }
157
158
    /**
159
     * @param $responseData
160
     * @throws InvalidResponseFormatException
161
     */
162
    private function validateResponse($responseData){
163
        if(!is_array($responseData)){
164
            throw new InvalidResponseFormatException('Method output MUST be an array');
165
        }
166
    }
167
168
    private function executeEndpoint($fullEndpoint, Request $request){
169
        $endPoint = new $fullEndpoint($request);
170
        return call_user_func([$endPoint, $request->getMethod()]);
171
    }
172
173
    /**
174
     * @param AccessControl $accessControl
175
     */
176
    public function setAccessControl(AccessControl $accessControl)
177
    {
178
        $this->accessControl = $accessControl;
179
    }
180
181
    /**
182
     * @param Throttle $throttle
183
     */
184
    public function setThrottle(Throttle $throttle)
185
    {
186
        $this->throttle = $throttle;
187
    }
188
189
    /**
190
     * @param Configuration $formatsConfig
191
     */
192
    public function setFormatsConfig(Configuration $formatsConfig)
193
    {
194
        $this->formatsConfig = $formatsConfig;
195
    }
196
197
    /**
198
     * @param string $endpointNamespace
199
     */
200
    public function setEndpointNamespace($endpointNamespace)
201
    {
202
        $this->endpointNamespace = $endpointNamespace;
203
    }
204
}
205