Passed
Pull Request — master (#1)
by Vince
01:27
created

server::setOptions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 8
rs 10
1
<?php
2
/**
3
 * ==================================
4
 * Responsible PHP API
5
 * ==================================
6
 *
7
 * @link Git https://github.com/vince-scarpa/responsibleAPI.git
8
 *
9
 * @api Responible API
10
 * @package responsible\core
11
 *
12
 * @author Vince scarpa <[email protected]>
13
 *
14
 */
15
namespace responsible\core;
16
17
use responsible\core\auth;
18
use responsible\core\configuration;
19
use responsible\core\connect;
20
use responsible\core\endpoints;
21
use responsible\core\exception;
22
use responsible\core\headers;
23
use responsible\core\keys;
24
use responsible\core\request;
25
use responsible\core\route;
26
use responsible\core\throttle;
27
28
class server
29
{
30
    /**
31
     * [$config]
32
     * @var object
33
     */
34
    protected $config;
35
36
    /**
37
     * [$options Variable store for the Responsible API options set]
38
     * @var array
39
     */
40
    private $options;
41
42
    /**
43
     * [$DB Database PDO connector]
44
     * @var object
45
     */
46
    protected $DB = null;
47
48
    /**
49
     * [$router The responsible API router]
50
     * @var array
51
     */
52
    protected $router;
53
54
    /**
55
     * [$grant_access If grant type is set then allow system scope override]
56
     * @var boolean
57
     */
58
    protected $grantAccess = false;
59
60
    /**
61
     * [$ALLOWED_METHODS]
62
     * @var array
63
     */
64
    private $ALLOWED_METHODS = array(
0 ignored issues
show
introduced by
The private property $ALLOWED_METHODS is not used, and could be removed.
Loading history...
65
        'GET',
66
        'POST',
67
        'PUT',
68
        'PATCH',
69
        'DELETE',
70
    );
71
72
    /**
73
     * [$RESPONSE]
74
     * @var array
75
     */
76
    protected $RESPONSE = array();
77
78
    /**
79
     * [__construct]
80
     * @param array  $config 
81
     *        environment variables
82
     * @param boolean $db
83
     */
84
    public function __construct(array $config = [], array $options = [], $db = false)
85
    {
86
        $this->setOptions($options);
87
88
        if ($db && !$this->isMockTest()) {
89
            if (empty($config)) {
90
                $config = new configuration\config;
91
                $config->responsibleDefault();
92
                $config = $config->getConfig();
93
            }
94
            if (is_null($this->DB)) {
95
                $this->DB = new connect\DB($config['DB_HOST'], $config['DB_NAME'], $config['DB_USER'], $config['DB_PASSWORD']);
96
            }
97
        }
98
99
        $this->header = new headers\header;
0 ignored issues
show
Bug Best Practice introduced by
The property header does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
100
        $this->header->setOptions($options);
101
102
        $this->keys = new keys\key;
0 ignored issues
show
Bug Best Practice introduced by
The property keys does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
103
        $this->endpoints = new endpoints\map;
0 ignored issues
show
Bug Best Practice introduced by
The property endpoints does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
104
        $this->endpoints->setOptions($options);
105
106
        $this->auth = new auth\authorise($options);
0 ignored issues
show
Bug Best Practice introduced by
The property auth does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
107
        $this->auth->header = $this->header;
108
    }
109
110
    /**
111
     * [options Responsible API options]
112
     * @param array $options
113
     */
114
    public function setOptions($options)
115
    {
116
        if (!is_null($this->options)) {
0 ignored issues
show
introduced by
The condition is_null($this->options) is always false.
Loading history...
117
            array_merge($this->options, $options);
118
            return;
119
        }
120
121
        $this->options = $options;
122
    }
123
124
    /**
125
     * [getOptions Get the stored Responsible API options]
126
     * @return array
127
     */
128
    public function getOptions():array
129
    {
130
        return $this->options;
131
    }
132
133
    /**
134
     * [DB Get the database instance]
135
     * @return object
136
     */
137
    public function DB()
138
    {
139
        return $this->DB;
140
    }
141
142
    /**
143
     * [requestType]
144
     * @var string $type
145
     * @return self
146
     */
147
    public function requestType($type)
148
    {
149
        $this->header->requestType($type);
150
        $this->header->requestMethod();
151
        return $this;
152
    }
153
154
    /**
155
     * [getRequestType]
156
     * @return string
157
     */
158
    public function getRequestType()
159
    {
160
        return $this->header->getRequestType();
161
    }
162
163
    /**
164
     * [setResponse Append the Responsible API response]
165
     * @param [string/array] $key [Array key]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [string/array] at position 0 could not be parsed: Unknown type name '[' at position 0 in [string/array].
Loading history...
166
     * @param array|null $response [Array value]
167
     */
168
    public function setResponse($key, $response)
169
    {
170
        $this->RESPONSE = [
171
            'headerStatus' => $this->header->getHeaderStatus(),
172
            'expires_in' => $this->auth->getJWTObject('expiresIn'),
173
            'access_token' => $this->auth->getJWTObject('token'),
174
            'refresh_token' => $this->auth->getJWTObject('refresh'),
175
        ];
176
177
        if (isset($this->RESPONSE['response'][$key])) {
178
            $this->RESPONSE['response'][$key][] = $response;
179
            return;
180
        }
181
        if (is_null($key) || $key == '') {
182
            if( !is_null($response) ) {
183
                $this->RESPONSE['response'] = $response;
184
            }
185
            return;
186
        }
187
188
        $this->RESPONSE['response'][$key] = $response;
189
    }
190
191
    /**
192
     * [getResponse Get the Responsible API output response]
193
     * @return array
194
     */
195
    private function getResponse()
196
    {
197
        return $this->RESPONSE;
198
    }
199
200
    /**
201
     * [rate Set the API rate limit]
202
     * @param  integer $limit [The request limit]
203
     * @param  string|integer $rate  [The request window]
204
     * @return self
205
     */
206
    public function rateLimit($limit = null, $rate = null)
207
    {
208
        $this->limiter = new throttle\limiter($limit, $rate);
0 ignored issues
show
Bug Best Practice introduced by
The property limiter does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
Unused Code introduced by
The call to responsible\core\throttle\limiter::__construct() has too many arguments starting with $limit. ( Ignorable by Annotation )

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

208
        $this->limiter = /** @scrutinizer ignore-call */ new throttle\limiter($limit, $rate);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
209
        return $this;
210
    }
211
212
    /**
213
     * [authenticate Parse the requests to Responsible API]
214
     *
215
     * 1. Authorise the requests JWT
216
     * 2. Throttle the requests
217
     *
218
     * @return self
219
     */
220
    public function authenticate()
221
    {
222
        $options = $this->getOptions();
223
        $route = (isset($options['route']) && !empty($options['route']) ) ? $options['route'] : '';
224
225
        $this->endpoints->baseApiRoot(dirname(__DIR__));
226
        $this->endpoints->register();
227
        
228
        $router = new route\router();
229
        $router->baseApiRoot(dirname(__DIR__));
230
231
        $this->router = $router->route($route);
0 ignored issues
show
Documentation Bug introduced by
It seems like $router->route($route) of type object is incompatible with the declared type array of property $router.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
232
        $endpoint = $this->endpoints->isEndpoint($router->getApi(), $router->getPath());
233
234
        if(isset($endpoint->model['scope'])) {
235
            $_REQUEST['scope'] = $endpoint->model['scope'];
236
            $this->header->setData($_REQUEST);
237
        }
238
239
        /**
240
         * Authenticate the JWT
241
         */
242
        $this->auth->authorise();
243
244
        /**
245
         * Call the rate limiter then throttle
246
         */
247
        if (!isset($this->limiter)) {
248
            $this->rateLimit();
249
        }
250
        
251
        $this->limiter
252
            ->options($this->getOptions())
253
            ->setAccount($this->auth->user())
254
            ->setupOptions()
255
            ->throttleRequest()
256
        ;
257
258
        return $this;
259
    }
260
261
    /**
262
     * [route Build the Responsible router]
263
     *
264
     * 1. Endpoints registry
265
     * 2. Build router
266
     * 3. Try run middleware
267
     *
268
     * @return array
269
     */
270
    public function route($route)
271
    {
272
        /**
273
         * Register endpoints
274
         */
275
        $this->endpoints->baseApiRoot(dirname(__DIR__));
276
        $this->endpoints->register();
277
278
        /**
279
         * Initialise the router
280
         */
281
        $router = new route\router();
282
        $router->baseApiRoot(dirname(__DIR__));
283
        $this->router = $router->route($route);
0 ignored issues
show
Documentation Bug introduced by
It seems like $router->route($route) of type object is incompatible with the declared type array of property $router.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
284
        $this->router->options = $this->getOptions();
285
        $this->router->auth = $this->auth->user();
286
        $this->router->limiter = $this->limiter->getThrottle();
287
288
        /**
289
         * Endpoint tiers must be larger than 1
290
         */
291
        if ($router->getSize() < 2) {
292
            (new exception\errorException)->error('NOT_FOUND');
293
        }
294
295
        /**
296
         * Check if the requested endpoint is allowed
297
         */
298
        if (!$this->router->endpoint =
299
            $this->endpoints->isEndpoint($router->getApi(), $router->getPath())
300
        ) {
301
            (new exception\errorException)->error('BAD_REQUEST');
302
        }
303
304
        $this->router->endpoint->header = [
305
            'method' => $this->header->getServerMethod(),
306
            'status' => $this->header->getHeaderStatus(),
307
            'body' => $this->header->getMethod(),
308
        ];
309
310
        /**
311
         * Check if theres a payload sent
312
         */
313
        if(isset($_REQUEST['payload'])) {
314
            $router->setRequestBody($_REQUEST['payload']);
315
        }
316
        // print_r($_REQUEST);
317
        /*if(isset($_POST) && !empty($_POST)) {
318
            $router->setPostBody($_POST);
319
        }*/
320
        $this->router->payload = $router->getRequestBody();
321
322
        /**
323
         * Check the access scope
324
         */
325
        if( !isset($this->router->endpoint->model['scope']) ) {
326
            $this->router->endpoint->model['scope'] = 'private';
327
        }
328
329
        if( isset($this->header->getMethod()->data['scope']) && 
330
            ($this->header->getMethod()->data['scope'] == 'anonymous')
331
        ) {
332
            $this->router->endpoint->model['scope'] = 'anonymous';
333
        }
334
335
        $router->setScope($this->router->endpoint->model['scope']);
336
        
337
        if (!$this->auth->isGrantType()) {
338
            if (!$router->systemAccess($this->auth->user())) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $router->systemAccess($this->auth->user()) of type null|true is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
339
                $this->header->unauthorised();
340
            }
341
        }
342
343
        /**
344
         * Try run the requests
345
         */
346
        if ($router->getScope() !== 'system') {
347
            $response = $router->run();
348
349
        } else {
350
            $response = [
0 ignored issues
show
Unused Code introduced by
The assignment to $response is dead and can be removed.
Loading history...
351
                'system' => $router->getApi(),
352
            ];
353
354
            $response = $router->run();
355
        }
356
357
        $this->setResponse('', $response);
358
359
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type responsible\core\server which is incompatible with the documented return type array.
Loading history...
360
    }
361
362
    /**
363
     * [getRouter Get the details of the Responsible API router]
364
     * @return array
365
     */
366
    public function getRouter()
367
    {
368
        return $this->router;
369
    }
370
371
    /**
372
     * [coredata Get the core data response]
373
     * @return object
374
     */
375
    public function coredata()
376
    {
377
        /**
378
         * Set the core data response
379
         * Used for debugging
380
         */
381
        foreach ($this->router as $key => $value) {
382
            $this->setResponse($key, $value);
383
        }
384
        return $this;
385
    }
386
387
    /**
388
     * [response Finnal response output]
389
     * @return array|object
390
     */
391
    public function response($debug = '')
392
    {
393
        /**
394
         * Output bebug functions
395
         */
396
        if (!empty($debug)) {
397
            if (method_exists($this, $debug)) {
398
                call_user_func(array($this, $debug));
399
            }
400
        }
401
402
        /**
403
         * Set the Responsible headers
404
         */
405
        $this->header->requestType($this->getRequestType());
406
        $this->header->setHeaders();
407
408
        /**
409
         * Output the response if any
410
         */
411
        return (new request\application($this->getRequestType()))
412
            ->data($this->getResponse());
413
    }
414
415
    /**
416
     * isMockTest
417
     *     Check if there's a mook server request
418
     * @return boolean
419
     */
420
    public function isMockTest():bool
421
    {
422
        if (isset($this->options['mock']) && 
423
            $this->options['mock'] == 'mock:3$_\7ucJ#D4,Yy=qzwY{&E+Mk_h,7L8:key'
424
        ) {
425
            return true;
426
        }
427
428
        return false;
429
    }
430
}
431