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

map::options()   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
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
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
namespace responsible\core\endpoints;
17
18
use responsible\core\endpoints;
19
use responsible\core\exception;
20
use responsible\core\route;
21
use responsible\core\interfaces;
22
23
class map extends route\router implements interfaces\optionsInterface
24
{
25
    use \responsible\core\traits\optionsTrait;
26
27
    /**
28
     * [$BASE_ENDPOINTS]
29
     * @var array
30
     */
31
    private $BASE_ENDPOINTS = array();
32
33
    /**
34
     * [$BASE_ENDPOINTS]
35
     * @var array
36
     */
37
    private $NAMESPACE_ENDPOINTS = array();
38
39
    /**
40
     * [$registry]
41
     * @var array
42
     */
43
    private $registry = array();
44
45
    /**
46
     * [$middleWareClass Holds middleware class object]
47
     * @var object
48
     */
49
    private static $middleWareClass;
50
51
    /**
52
     * [$SYSTEM_ENDPOINTS Reserved system Endpoints]
53
     * @var array
54
     */
55
    const SYSTEM_ENDPOINTS = [
56
        'token' => '/token/access_token',
57
        'user' => [
58
            '/user/create',
59
            '/user/load',
60
        ],
61
    ];
62
63
    /**
64
     * [__construct Silence...]
65
     */
66
    public function __construct() {}
67
68
    /**
69
     * [register Scan and register endpoints defined in services]
70
     * @return array
71
     */
72
    public function register()
73
    {
74
        $options = $this->options;
0 ignored issues
show
Unused Code introduced by
The assignment to $options is dead and can be removed.
Loading history...
75
76
        /**
77
         * Check if a custom directory was set in the Responsible API options
78
         */
79
        if( (isset($this->options['classRoute']) && !empty($this->options['classRoute'])) && 
80
            (isset($this->options['classRoute']['directory']) && isset($this->options['classRoute']['namespace']))
81
        ) {
82
            $customService = $this->options['classRoute'];
83
            $directory = $customService['directory'];
84
            $middleware = $customService['namespace'];
85
86
        }else {
87
            $middleware = 'responsible';
88
89
            $endpoint = str_replace(
90
                array('core', '/', '\\'),
91
                array('service', DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR),
92
                __NAMESPACE__
93
            );
94
95
            $directory = $this->route()->base['root'] . '/' . str_replace('responsible/', '', $endpoint);
96
        }
97
98
        if (!is_dir($directory)) {
99
            (new exception\errorException)
100
                ->message('Directory Error:: responsible\service needs to exist. See documentation on setting up a service.')
101
                ->error('NOT_EXTENDED');
102
        }
103
104
        $scanned = array_values(
105
            array_diff(
106
                scandir($directory),
0 ignored issues
show
Bug introduced by
It seems like scandir($directory) can also be of type false; however, parameter $array1 of array_diff() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

106
                /** @scrutinizer ignore-type */ scandir($directory),
Loading history...
107
                array('..', '.', '.DS_Store')
108
            )
109
        );
110
111
        if (empty($scanned)) {
112
            (new exception\errorException)
113
                ->message('Class Error:: responsible\service\endpoints needs at least 1 class file. See documentation on setting up a service.')
114
                ->error('NOT_EXTENDED');
115
        }
116
117
        foreach ($scanned as $e => $point) {
118
119
            if (substr($point, -4) == '.php') {
120
                $point = str_replace('.php', '', $point);
121
122
                $this->BASE_ENDPOINTS[] = $point;
123
124
                $endpoint = str_replace('core', 'service', __NAMESPACE__) . '\\' . $point;
0 ignored issues
show
Unused Code introduced by
The assignment to $endpoint is dead and can be removed.
Loading history...
125
                $endpoint = $middleware . '\\service\\endpoints\\' . $point;
126
                $child = $endpoint;
127
128
                $this->NAMESPACE_ENDPOINTS[$point] = $endpoint;
129
130
                if (class_exists($child)) {
131
                    self::$middleWareClass = new $child;
132
                    $this->registry[$point] = self::$middleWareClass->register();
133
                }else{
134
                    (new exception\errorException)
135
                        ->message("Class Error:: class {$child} needs to exist. See documentation on setting up a service.")
136
                        ->error('NOT_EXTENDED');
137
                }
138
            }
139
        }
140
141
        return $this->registry;
142
    }
143
144
    /**
145
     * [isEndpoint Check the requested endpoint, scope and tier parts]
146
     * @return object|null
147
     */
148
    public function isEndpoint($api, $endpoint)
149
    {
150
        $endpointSettings = [];
151
152
        if (isset(self::SYSTEM_ENDPOINTS[$api]) &&
153
            (
154
                in_array($endpoint, self::SYSTEM_ENDPOINTS) ||
155
                array_search($endpoint, self::SYSTEM_ENDPOINTS[$api]) !== false
156
            )
157
        ) {
158
            $methodCreate = explode('/', $endpoint);
159
            $methodCreate = array_values(array_filter($methodCreate));
160
            $method = '';
161
162
            foreach ($methodCreate as $i => $parts) {
163
                if (preg_match_all('#_#', $parts)) {
164
                    $parts = str_replace('_', '', lcfirst(ucwords($parts, '_')));
165
                }
166
                if ($i > 0) {
167
                    $method .= ucfirst($parts);
168
                } else {
169
                    $method .= $parts;
170
                }
171
            }
172
173
            $endpointSettings['model'] = array(
174
                'scope' => 'system',
175
                'namespace' => 'responsible\core\endpoints\system',
176
                'class' => 'system',
177
                'method' => $method,
178
                'arguments' => '',
179
            );
180
181
            return (object) $endpointSettings;
182
        }        
183
184
        $endpoint = htmlspecialchars($endpoint, ENT_QUOTES, 'UTF-8');
185
        $index = array_search($api, $this->BASE_ENDPOINTS);
186
187
        if ($index !== false) {
188
            if (isset($this->registry[$api])) {
189
                $endpointSettings = array(
190
                    'path' => $endpoint,
191
                    'model' => array(
192
                        'namespace' => $this->NAMESPACE_ENDPOINTS[$api],
193
                        'class' => $this->BASE_ENDPOINTS[$index],
194
                        'method' => basename($endpoint),
195
                        'scope' => 'private',
196
                    ),
197
                );
198
199
                /**
200
                 * Nothing dynamic, found an exact match
201
                 * @var array
202
                 */
203
                if (array_search($endpoint, $this->registry[$api]) !== false) {
204
                    if( method_exists($this->NAMESPACE_ENDPOINTS[$api], 'scope') ) {
205
                        $classScope = (new $this->NAMESPACE_ENDPOINTS[$api])->scope();
206
                        $position = array_search($endpoint, $this->registry[$api]);
207
                        
208
                        if( is_array($classScope) && isset($classScope[$position]) ) {
209
                            $endpointSettings['model']['scope'] = $classScope[$position];
210
211
                        }else{
212
213
                            if( !is_array($classScope) ) {
214
                                $endpointSettings['model']['scope'] = $classScope;
215
                            }
216
                        }
217
                    }
218
                    return (object) $endpointSettings;
219
                }
220
221
                /**
222
                 * Check for dynamic uri eg: {asset_id}
223
                 * Dynamic uri's must be wrapped in {} for a true return
224
                 */
225
                foreach ($this->registry[$api] as $i => $path) {
226
                    $endpointRegister = $path;
227
                    $methodArgs = [];
228
229
                    /**
230
                     * If comparing the two sizes are not equal
231
                     * then no use continuing through the loop
232
                     */
233
                    if (!$this->uriCheckSize($endpointRegister, $endpoint)) {
234
                        continue;
235
                    }
236
237
                    /**
238
                     * This replacment will create a pattern to use as a match all expression
239
                     * @var [string]
240
                     */
241
                    $endpointRegister = preg_replace('@/{(.*?)}@', '/(.*?)', $endpointRegister);
242
243
                    if (preg_match_all('@^' . $endpointRegister . '$@i', $endpoint, $dynamicParts)) {
244
                        $endpointFilter = $this->filterParts($endpoint, $dynamicParts);
245
                        $model = $this->getClassModel($path);
246
247
                        /**
248
                         * Find the dynamic parts and set them as argument key(s)
249
                         * then combine them with the endpoint request and set the request parts
250
                         * as argument value(s)
251
                         */
252
                        if (preg_match_all("/(?<={).*?(?=})/", $path, $registerParts)) {
253
                            if (isset($registerParts[0][0])) {
254
                                $registerParts = $registerParts[0];
255
256
                                if (sizeof($endpointFilter) == sizeof($registerParts)) {
257
                                    $methodArgs = array_combine($registerParts, $endpointFilter);
258
                                }
259
                            }
260
                        }
261
262
                        $scope = 'private';
263
264
                        if( method_exists($this->NAMESPACE_ENDPOINTS[$api], 'scope') ) {
265
                            $classScope = (new $this->NAMESPACE_ENDPOINTS[$api])->scope();
266
                            $position = array_search($path, $this->registry[$api]);
267
                            
268
                            if( is_array($classScope) && isset($classScope[$position]) ) {
269
                                $scope = $classScope[$position];
270
271
                            }else{
272
273
                                if( !is_array($classScope) ) {
274
                                    $scope = $classScope;
275
                                }
276
                            }
277
                        }
278
279
                        $endpointSettings['model'] = array(
280
                            'scope' => $scope,
281
                            'namespace' => $this->NAMESPACE_ENDPOINTS[$api],
282
                            'class' => $model['class'],
283
                            'method' => $model['method'],
284
                            'arguments' => $methodArgs,
285
                        );
286
287
                        return (object) $endpointSettings;
288
                    } else {
289
                        continue;
290
                    }
291
                }
292
            }
293
        }
294
295
        return;
296
    }
297
298
    /**
299
     * [filterParts Prepare routed parts]
300
     * @return array
301
     */
302
    private function filterParts($uri, $parts)
303
    {
304
        $filter = array();
305
306
        foreach ($parts as $p => $part) {
307
            if (is_array($part)) {
308
                foreach ($part as $i => $parti) {
309
                    if ($parti !== $uri) {
310
                        $filter[] = $parti;
311
                    }
312
                }
313
            }
314
        }
315
316
        return $filter;
317
    }
318
319
    /**
320
     * [uriCheckSize]
321
     *
322
     * Compare the current request endpoint with the registered endpoint
323
     * only return the same tier sizes
324
     *
325
     * @return boolean
326
     */
327
    private function uriCheckSize($endpointRegister, $endpoint)
328
    {
329
        $registerExplode = explode('/', $endpointRegister);
330
        $endpointExplode = explode('/', $endpoint);
331
        return (sizeof($registerExplode) === sizeof($endpointExplode));
332
    }
333
334
    /**
335
     * [getClassModel Class, Method]
336
     * @return array
337
     */
338
    private function getClassModel($request_path)
339
    {
340
        $cm = explode('/', $request_path);
341
342
        if (!empty($cm) && sizeof($cm) >= 2) {
343
            $cm = array_values(array_filter($cm));
344
345
            return array(
346
                'class' => $cm[0],
347
                'method' => $cm[1],
348
            );
349
        }
350
351
        return;
352
    }
353
}
354