Passed
Push — master ( 0c1115...dae56e )
by Vince
03:09 queued 14s
created

map   C

Complexity

Total Complexity 54

Size/Duplication

Total Lines 379
Duplicated Lines 0 %

Importance

Changes 12
Bugs 0 Features 0
Metric Value
eloc 171
c 12
b 0
f 0
dl 0
loc 379
rs 6.4799
wmc 54

7 Methods

Rating   Name   Duplication   Size   Complexity  
D isEndpoint() 0 134 22
A uriCheckSize() 0 5 1
A __construct() 0 2 1
A filterParts() 0 15 5
B isSystemEndpoint() 0 37 7
A getClassModel() 0 16 3
C register() 0 83 15

How to fix   Complexity   

Complex Class

Complex classes like map often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use map, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * ==================================
5
 * Responsible PHP API
6
 * ==================================
7
 *
8
 * @link Git https://github.com/vince-scarpa/responsibleAPI.git
9
 *
10
 * @api Responible API
11
 * @package responsible\core\endpoints
12
 *
13
 * @author Vince scarpa <[email protected]>
14
 *
15
 */
16
17
namespace responsible\core\endpoints;
18
19
use responsible\core\endpoints;
20
use responsible\core\exception;
21
use responsible\core\route;
22
use responsible\core\interfaces;
23
24
class map extends route\router implements interfaces\optionsInterface
25
{
26
    use \responsible\core\traits\optionsTrait;
27
28
    /**
29
     * [$BASE_ENDPOINTS]
30
     * @var array
31
     */
32
    private $BASE_ENDPOINTS = array();
33
34
    /**
35
     * [$BASE_ENDPOINTS]
36
     * @var array
37
     */
38
    private $NAMESPACE_ENDPOINTS = array();
39
40
    /**
41
     * [$registry]
42
     * @var array
43
     */
44
    private $registry = array();
45
46
    /**
47
     * [$middleWareClass Holds middleware class object]
48
     * @var object
49
     */
50
    private static $middleWareClass;
51
52
    /**
53
     * [$SYSTEM_ENDPOINTS Reserved system Endpoints]
54
     * @var array
55
     */
56
    public const SYSTEM_ENDPOINTS = [
57
        'token' => '/token/access_token',
58
        'user' => [
59
            '/user/create',
60
            '/user/load',
61
        ],
62
    ];
63
64
    /**
65
     * [__construct Silence...]
66
     */
67
    public function __construct()
68
    {
69
    }
70
71
    /**
72
     * [register Scan and register endpoints defined in services]
73
     * @return array
74
     */
75
    public function register()
76
    {
77
        $options = $this->options;
78
79
        /**
80
         * Check if a custom directory was set in the Responsible API options
81
         */
82
        if (
83
            (isset($options['classRoute']) && !empty($options['classRoute'])) &&
84
            (isset($options['classRoute']['directory']) && isset($options['classRoute']['namespace']))
85
        ) {
86
            $customService = $this->options['classRoute'];
87
            $directory = $customService['directory'];
88
            $middleware = $customService['namespace'];
89
        } else {
90
            $middleware = 'responsible';
91
92
            $endpoint = str_replace(
93
                array('core', '/', '\\'),
94
                array('service', DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR),
95
                __NAMESPACE__
96
            );
97
98
            $directory = $this->route()->base['root'] . '/' . str_replace('responsible/', '', $endpoint);
99
        }
100
101
        if (!is_dir($directory)) {
102
            (new exception\errorException())
103
                ->setOptions($this->getOptions())
104
                ->message('Directory Error:: responsible\service needs to exist. See documentation on setting up a service.')
105
                ->error('NOT_EXTENDED');
106
        }
107
108
        $scanned = '';
109
        $scanDir = scandir($directory);
110
111
        if (!empty($scanDir)) {
112
            $scanned = array_values(
113
                array_diff(
114
                    $scanDir,
115
                    array('..', '.', '.DS_Store')
116
                )
117
            );
118
        }
119
120
        if (empty($scanned)) {
121
            (new exception\errorException())
122
                ->setOptions($this->getOptions())
123
                ->message('Class Error:: responsible\service\endpoints needs at least 1 class file. See documentation on setting up a service.')
124
                ->error('NOT_EXTENDED');
125
        }
126
127
        foreach ($scanned as $e => $point) {
128
            if (substr($point, -4) == '.php') {
129
                $point = str_replace('.php', '', $point);
130
131
                $this->BASE_ENDPOINTS[] = $point;
132
133
                $endpoint = str_replace('core', 'service', __NAMESPACE__) . '\\' . $point;
134
135
                if ($middleware !== 'responsible') {
136
                    $endpoint = $middleware . '\\service\\endpoints\\' . $point;
137
                }
138
139
                $child = $endpoint;
140
141
                $this->NAMESPACE_ENDPOINTS[$point] = $endpoint;
142
143
                if (class_exists($child) && method_exists($child, 'middleware')) {
144
                    self::$middleWareClass = new $child();
145
                    $this->registry[$point] = self::$middleWareClass->middleware();
146
                } elseif (class_exists($child) && method_exists($child, 'register')) {
147
                    self::$middleWareClass = new $child();
148
                    $this->registry[$point] = self::$middleWareClass->register();
149
                } else {
150
                    (new exception\errorException())
151
                        ->setOptions($this->getOptions())
152
                        ->message("Class Error:: class {$child} needs to exist. See documentation on setting up a service.")
153
                        ->error('NOT_EXTENDED');
154
                }
155
            }
156
        }
157
        return $this->registry;
158
    }
159
160
    /**
161
     * [isSystemEndpoint Check if the endpoint request is a ResponsibleAPI reserved endpoint]
162
     * @param  string  $api
163
     * @param  string  $endpoint
164
     * @return object|null
165
     */
166
    private function isSystemEndpoint($api, $endpoint)
167
    {
168
        if (
169
            isset(self::SYSTEM_ENDPOINTS[$api]) &&
170
            (
171
                in_array($endpoint, self::SYSTEM_ENDPOINTS) ||
172
                array_search($endpoint, self::SYSTEM_ENDPOINTS[$api]) !== false
173
            )
174
        ) {
175
            $endpointSettings = [];
176
            $methodCreate = explode('/', $endpoint);
177
            $methodCreate = array_values(array_filter($methodCreate));
178
            $method = '';
179
180
            foreach ($methodCreate as $i => $parts) {
181
                if (preg_match_all('#_#', $parts)) {
182
                    $parts = str_replace('_', '', lcfirst(ucwords($parts, '_')));
183
                }
184
                if ($i > 0) {
185
                    $method .= ucfirst($parts);
186
                } else {
187
                    $method .= $parts;
188
                }
189
            }
190
191
            $endpointSettings['model'] = array(
192
                'scope' => 'system',
193
                'namespace' => 'responsible\core\endpoints\system',
194
                'class' => 'system',
195
                'method' => $method,
196
                'arguments' => '',
197
            );
198
199
            return (object) $endpointSettings;
200
        }
201
202
        return null;
203
    }
204
205
    /**
206
     * [isEndpoint Check the requested endpoint, scope and tier parts]
207
     * @param  string  $api
208
     * @param  string  $endpoint
209
     * @return object|null
210
     */
211
    public function isEndpoint($api, $endpoint)
212
    {
213
        /**
214
         * Return if it's a system endpoint
215
         */
216
        if (null !== ($endpointSettings = $this->isSystemEndpoint($api, $endpoint))) {
217
            return $endpointSettings;
218
        }
219
220
        /**
221
         * Check if the endpoint is a RouterInterface
222
         */
223
        $endpoint = htmlspecialchars($endpoint, ENT_QUOTES, 'UTF-8');
224
        $index = array_search($api, $this->BASE_ENDPOINTS);
225
226
        if ($index !== false) {
227
            if (isset($this->registry[$api])) {
228
                $endpointSettings = array(
229
                    'path' => $endpoint,
230
                    'model' => array(
231
                        'namespace' => $this->NAMESPACE_ENDPOINTS[$api],
232
                        'class' => $this->BASE_ENDPOINTS[$index],
233
                        'method' => basename($endpoint),
234
                        'scope' => 'private',
235
                    ),
236
                );
237
238
                /**
239
                 * Nothing dynamic, found an exact match
240
                 * @var array
241
                 */
242
                if (array_search($endpoint, $this->registry[$api]) !== false) {
243
                    if (method_exists($this->NAMESPACE_ENDPOINTS[$api], 'scope')) {
244
                        $classScope = (new $this->NAMESPACE_ENDPOINTS[$api]())->scope();
245
                        $position = array_search($endpoint, $this->registry[$api]);
246
247
                        if (is_array($classScope) && isset($classScope[$position])) {
248
                            $endpointSettings['model']['scope'] = $classScope[$position];
249
                        } else {
250
                            if (!is_array($classScope)) {
251
                                $endpointSettings['model']['scope'] = $classScope;
252
                            }
253
                        }
254
                    }
255
                    return (object) $endpointSettings;
256
                }
257
258
                /**
259
                 * Check for dynamic uri eg: {asset_id}
260
                 * Dynamic uri's must be wrapped in {} for a true return
261
                 */
262
                foreach ($this->registry[$api] as $i => $path) {
263
                    $endpointRegister = $path;
264
                    $methodArgs = [];
265
266
                    $routeInstance = null;
267
                    if ($path instanceof \responsible\core\endpoints\RouteMiddlewareInterface) {
268
                        $routeInstance = $path;
269
                        $endpointRegister = $path = $routeInstance->getRoute();
270
                        $scope = $routeInstance->getScope();
0 ignored issues
show
Unused Code introduced by
The assignment to $scope is dead and can be removed.
Loading history...
271
                    }
272
273
                    /**
274
                     * If comparing the two sizes are not equal
275
                     * then no use continuing through the loop
276
                     */
277
                    if (!$this->uriCheckSize($endpointRegister, $endpoint)) {
278
                        continue;
279
                    }
280
281
                    /**
282
                     * This replacment will create a pattern to use as a match all expression
283
                     * @var [string]
284
                     */
285
                    $endpointRegister = preg_replace('@/{(.*?)}@', '/(.*?)', $endpointRegister);
286
287
                    if (preg_match_all('@^' . $endpointRegister . '$@i', $endpoint, $dynamicParts)) {
288
                        $endpointFilter = $this->filterParts($endpoint, $dynamicParts);
289
                        $model = $this->getClassModel($path);
290
291
                        /**
292
                         * Find the dynamic parts and set them as argument key(s)
293
                         * then combine them with the endpoint request and set the request parts
294
                         * as argument value(s)
295
                         */
296
                        if (preg_match_all("/(?<={).*?(?=})/", $path, $registerParts)) {
297
                            if (isset($registerParts[0][0])) {
298
                                $registerParts = $registerParts[0];
299
300
                                if (sizeof($endpointFilter) == sizeof($registerParts)) {
301
                                    $methodArgs = array_combine($registerParts, $endpointFilter);
302
                                }
303
                            }
304
                        }
305
306
                        $scope = 'private';
307
                        if ($routeInstance instanceof \responsible\core\endpoints\RouteMiddlewareInterface) {
308
                            $scope = $routeInstance->getScope();
309
                            if ($scope == 'public') {
310
                                $scope = 'anonymous';
311
                            }
312
                        }
313
314
                        if (method_exists($this->NAMESPACE_ENDPOINTS[$api], 'scope')) {
315
                            $classScope = (new $this->NAMESPACE_ENDPOINTS[$api]())->scope();
316
                            $position = array_search($path, $this->registry[$api]);
317
318
                            if (is_array($classScope) && isset($classScope[$position])) {
319
                                $scope = $classScope[$position];
320
                            } else {
321
                                if (!is_array($classScope)) {
322
                                    $scope = $classScope;
323
                                }
324
                            }
325
                        }
326
327
                        $endpointSettings['model'] = array(
328
                            'scope' => $scope,
329
                            'namespace' => $this->NAMESPACE_ENDPOINTS[$api],
330
                            'class' => $model['class'],
331
                            'method' => $model['method'],
332
                            'arguments' => $methodArgs,
333
                            'middleware' => $routeInstance,
334
                        );
335
336
                        return (object) $endpointSettings;
337
                    } else {
338
                        continue;
339
                    }
340
                }
341
            }
342
        }
343
344
        return;
345
    }
346
347
    /**
348
     * [filterParts Prepare routed parts]
349
     * @return array
350
     */
351
    private function filterParts($uri, $parts)
352
    {
353
        $filter = array();
354
355
        foreach ($parts as $p => $part) {
356
            if (is_array($part)) {
357
                foreach ($part as $i => $parti) {
358
                    if ($parti !== $uri) {
359
                        $filter[] = $parti;
360
                    }
361
                }
362
            }
363
        }
364
365
        return $filter;
366
    }
367
368
    /**
369
     * [uriCheckSize]
370
     *
371
     * Compare the current request endpoint with the registered endpoint
372
     * only return the same tier sizes
373
     *
374
     * @return boolean
375
     */
376
    private function uriCheckSize($endpointRegister, $endpoint)
377
    {
378
        $registerExplode = explode('/', $endpointRegister);
379
        $endpointExplode = explode('/', $endpoint);
380
        return (sizeof($registerExplode) === sizeof($endpointExplode));
381
    }
382
383
    /**
384
     * [getClassModel Class, Method]
385
     * @return array
386
     */
387
    private function getClassModel($request_path)
388
    {
389
        $cm = explode('/', $request_path);
390
391
        if (!empty($cm) && sizeof($cm) >= 2) {
392
            $cm = array_values(array_filter($cm));
393
394
            return array(
395
                'class' => $cm[0],
396
                'method' => $cm[1] ?? '',
397
            );
398
        }
399
400
        return [
401
            'class' => '',
402
            'method' => '',
403
        ];
404
    }
405
}
406