Request   F
last analyzed

Complexity

Total Complexity 70

Size/Duplication

Total Lines 484
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 119
dl 0
loc 484
rs 2.8
c 0
b 0
f 0
wmc 70

18 Methods

Rating   Name   Duplication   Size   Complexity  
B setRequestInputs() 0 24 7
A containerRegister() 0 5 1
A checkHttpMethod() 0 16 3
A requestProperties() 0 21 1
A capsuleCaret() 0 17 5
A capsule() 0 15 6
A validation() 0 7 4
A handle() 0 17 1
B autoValidate() 0 23 9
A initClient() 0 9 2
A setClientObjects() 0 16 3
A checkProperties() 0 6 4
A expectedInputs() 0 25 6
A __construct() 0 13 2
B generatorMethod() 0 34 8
A generatorManager() 0 16 5
A registerRequestInputs() 0 13 1
A except() 0 14 2

How to fix   Complexity   

Complex Class

Complex classes like Request 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 Request, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Resta\Request;
4
5
use Resta\Support\Arr;
6
use Resta\Support\Utils;
7
use Resta\Contracts\HandleContracts;
8
use Resta\Support\ReflectionProcess;
9
use ReflectionException as ReflectionExceptionAlias;
10
11
class Request extends RequestAbstract implements HandleContracts
12
{
13
    /**
14
     * @var array
15
     */
16
    protected $capsule = [];
17
18
    /**
19
     * @var array
20
     */
21
    protected $except = [];
22
23
    /**
24
     * @var string
25
     */
26
    protected $method;
27
28
    /**
29
     * @var ReflectionProcess
30
     */
31
    protected $reflection;
32
33
    /**
34
     * @var null|object
35
     */
36
    protected $requestHttp;
37
38
    /**
39
     * @var null|array
40
     */
41
    protected $clientData;
42
43
    /**
44
     * Request constructor.
45
     *
46
     * @param null|array $clientData
47
     *
48
     * @throws ReflectionExceptionAlias
49
     */
50
    public function __construct($clientData=null)
51
    {
52
        //reflection process
53
        $this->reflection = app()['reflection']($this);
54
55
        //get http method via request http manager class
56
        $this->requestHttp = app()->resolve(RequestHttpManager::class);
57
58
        //get request client data
59
        $this->clientData = ($clientData===null) ? $this->requestHttp->resolve() : $clientData;
60
61
        //handle request
62
        $this->handle();
63
    }
64
65
    /**
66
     * auto validate
67
     *
68
     * @param $validate
69
     */
70
    private function autoValidate($validate)
71
    {
72
        //we get the values ​​to auto-validate.
73
        foreach ($this->{$validate} as $object=>$datas){
74
75
            // the auto-validate value must necessarily represent a class.
76
            // otherwise auto-validate is not used.
77
            if(Utils::isNamespaceExists($object)){
78
                $getObjectInstance = app()->resolve($object);
79
80
                // we get the index values,
81
                // which are called methods of the auto-validate value that represents the class.
82
                foreach ($datas as $dataKey=>$data){
83
84
                    // if the methods of the auto-validate class resolved by the container resolve method apply,
85
                    // the process of auto-validate automatic implementation will be completed.
86
                    if(is_numeric($dataKey) && method_exists($getObjectInstance,$data)){
87
                        if(isset($this->origin[$data])){
88
                            if(!is_array($this->origin[$data])){
89
                                $this->origin[$data] = array($this->origin[$data]);
90
                            }
91
                            foreach ($this->origin[$data] as $originData){
92
                                $getObjectInstance->{$data}($originData);
93
                            }
94
                        }
95
                    }
96
                }
97
            }
98
        }
99
    }
100
101
    /**
102
     * capsule inputs
103
     *
104
     * @return void|mixed
105
     */
106
    private function capsule()
107
    {
108
        // expected method is executed.
109
        // this method is a must for http method values to be found in this property.
110
        if($this->checkProperties('capsule')){
111
112
            $caret = $this->capsuleCaret();
113
114
            foreach($this->inputs as $input=>$value){
115
116
                if(isset($caret[$input]) || (
117
                        $this->checkProperties('capsule') && !in_array($input,$this->capsule)
118
                    )){
119
                    exception('capsuleRequestException')
120
                        ->overflow('The '.$input.' value cannot be sent.');
121
                }
122
            }
123
        }
124
    }
125
126
    /**
127
     * get capsule caret for request
128
     *
129
     * @return array
130
     */
131
    private function capsuleCaret()
132
    {
133
        $caret = [];
134
135
        foreach($this->inputs as $input=>$item){
136
            if(in_array('@'.$input,$this->capsule)){
137
                $caret[$input] = $item;
138
            }
139
        }
140
141
        foreach ($this->capsule as $item) {
142
            if(preg_match('#@.*#is',$item)){
143
                $this->capsule = array_diff($this->capsule,[$item]);
144
            }
145
        }
146
147
        return $caret;
148
    }
149
150
    /**
151
     * check http method
152
     *
153
     * @return void|mixed
154
     */
155
    private function checkHttpMethod()
156
    {
157
        //get http method
158
        $method = $this->requestHttp->getMethod();
0 ignored issues
show
Bug introduced by
The method getMethod() does not exist on null. ( Ignorable by Annotation )

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

158
        /** @scrutinizer ignore-call */ $method = $this->requestHttp->getMethod();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
159
160
        // Determines which HTTP method
161
        // the request object will be exposed to.
162
        if($this->checkProperties('http')){
163
164
            // if the current http method does not exist
165
            // in the http object, the exception will be thrown.
166
            if(!in_array($method,$this->http)){
0 ignored issues
show
Bug Best Practice introduced by
The property http does not exist on Resta\Request\Request. Did you maybe forget to declare it?
Loading history...
167
168
                //exception batMethodCall
169
                exception()->badMethodCall(
170
                    'Invalid http method process for '.class_basename($this).'.That is accepted http methods ['.implode(",",$this->http).'] ');
171
            }
172
        }
173
    }
174
175
    /**
176
     * check properties
177
     *
178
     * @param $properties
179
     * @return bool
180
     */
181
    private function checkProperties($properties)
182
    {
183
        // from the properties of the object properties to
184
        // the existing variables, control the array and at least one element.
185
        return (property_exists($this,$properties)
186
            && is_array($this->{$properties}) && count($this->{$properties})) ? true : false;
187
    }
188
189
    /**
190
     * register container for request
191
     *
192
     * @return mixed|void
193
     */
194
    private function containerRegister()
195
    {
196
        // we are saving the expected values ​​for the request in container.
197
        // this record can be returned in exception information.
198
        app()->register('requestExpected',$this->expected);
0 ignored issues
show
Bug Best Practice introduced by
The property expected does not exist on Resta\Request\Request. Did you maybe forget to declare it?
Loading history...
199
    }
200
201
    /**
202
     * get request except
203
     *
204
     * @param $except
205
     * @return $this
206
     */
207
    public function except($except)
208
    {
209
        // the except parameter is a callable value.
210
        if(is_callable($except)){
211
            $call = call_user_func_array($except,[$this]);
212
            $except = $call;
213
        }
214
215
        // except with the except exceptions property
216
        // and then assigning them to the inputs property.
217
        $this->except = array_merge($this->except,$except);
218
        $this->inputs = array_diff_key($this->inputs,array_flip($this->except));
219
220
        return $this;
221
    }
222
223
    /**
224
     * expected inputs
225
     *
226
     * @return void|mixed
227
     */
228
    private function expectedInputs()
229
    {
230
        // expected method is executed.
231
        // this method is a must for http method values to be found in this property.
232
        if($this->checkProperties('expected')){
233
234
            // if the expected values are not found in the inputs array,
235
            // the exception will be thrown.
236
            foreach ($this->expected as $expected){
0 ignored issues
show
Bug Best Practice introduced by
The property expected does not exist on Resta\Request\Request. Did you maybe forget to declare it?
Loading history...
237
238
                $expectedValues = [];
239
240
                // mandatory expected data for each key can be separated by | operator.
241
                // this is evaluated as "or".
242
                foreach($expectedData = explode("|",$expected) as $inputs){
243
                    if(!isset($this->inputs[$inputs])){
244
                        $expectedValues[] = $inputs;
245
                    }
246
                }
247
248
                // if the expectedData and expectedValues ​​
249
                // array are numerically equal to the expected key, the exception is thrown.
250
                if(count($expectedData)===count($expectedValues)){
251
                    exception($expected)
252
                        ->unexpectedValue('You absolutely have to send the value '.implode(" or ",$expectedValues).' for request object');
253
                }
254
            }
255
        }
256
    }
257
258
    /**
259
     * generator manager
260
     *
261
     * @throws ReflectionExceptionAlias
262
     */
263
    private function generatorManager()
264
    {
265
        // check the presence of the generator object
266
        // and operate the generator over this object.
267
        if($this->checkProperties('auto_generators')){
268
            $generators = $this->getAutoGenerators();
269
        }
270
271
        // check the presence of the generator object
272
        // and operate the generator over this object.
273
        if($this->checkProperties('generators')){
274
            $generators = array_merge(isset($generators) ? $generators: [],$this->getGenerators());
275
        }
276
277
        if(isset($generators)){
278
            $this->generatorMethod($generators);
279
        }
280
    }
281
282
    /**
283
     * generator method
284
     *
285
     * @param $generators
286
     *
287
     * @throws ReflectionExceptionAlias
288
     */
289
    private function generatorMethod($generators)
290
    {
291
        //generator array object
292
        foreach ($generators as $generator){
293
294
            //generator method name
295
            $generatorMethodName = $generator.'Generator';
296
297
            // if the generator method is present,
298
            // the fake value is assigned.
299
            if(method_exists($this,$generatorMethodName)){
300
301
                //fake registration
302
                if(!isset($this->inputs[$generator])){
303
                    $this->{$generator} = $this->{$generatorMethodName}();
304
                    $this->inputs[$generator] = $this->{$generatorMethodName}();
305
                }
306
                else {
307
308
                    if($this->checkProperties('auto_generators_dont_overwrite')
309
                        && in_array($generator,$this->getAutoGeneratorsDontOverwrite())){
310
                        $this->{$generator} = $this->{$generatorMethodName}();
311
                        $this->inputs[$generator] = $this->{$generatorMethodName}();
312
                    }
313
314
                    if($this->checkProperties('generators_dont_overwrite')
315
                        && in_array($generator,$this->getGeneratorsDontOverwrite())){
316
                        $this->{$generator} = $this->{$generatorMethodName}();
317
                        $this->inputs[$generator] = $this->{$generatorMethodName}();
318
                    }
319
320
                }
321
322
                $this->registerRequestInputs($generator);
323
            }
324
        }
325
    }
326
327
    /**
328
     * request handle
329
     *
330
     * @return mixed|void
331
     *
332
     * @throws ReflectionExceptionAlias
333
     */
334
    public function handle()
335
    {
336
        //set container for request
337
        $this->containerRegister();
338
339
        //we record the values ​​
340
        //that coming with the post.
341
        $this->initClient();
342
343
        // we update the input values ​​after
344
        // we receive and check the saved objects.
345
        $this->setClientObjects();
346
347
        // we add our user-side properties for the request object,
348
        // and on this we will set all the request object properties
349
        // that may be useful for the application.
350
        $this->requestProperties();
351
    }
352
353
    /**
354
     * get init client
355
     *
356
     * @return void
357
     */
358
    private function initClient()
359
    {
360
        // we use the http method to write
361
        // the values to the inputs and origin properties.
362
        foreach($this->clientData as $key=>$value){
363
364
            //inputs and origin properties
365
            $this->inputs[$key] = $value;
366
            $this->origin[$key] = $value;
367
        }
368
    }
369
370
    /**
371
     * request properties
372
     *
373
     * @throws ReflectionExceptionAlias
374
     */
375
    private function requestProperties()
376
    {
377
        // if a fake method is defined and it is not in
378
        // the context of any key method when access is granted,
379
        // it can be filled with fake method.
380
        $this->generatorManager();
381
382
        // contrary to capsule method,
383
        // expected values must be in the key being sent.
384
        $this->expectedInputs();
385
386
        // get capsule as mandatory values
387
        $this->capsule();
388
389
        // this method determines
390
        // how the request object will be requested,
391
        $this->checkHttpMethod();
392
393
        // it passes all keys that are sent through
394
        // a validation method on the user side.
395
        $this->validation();
396
    }
397
398
    /**
399
     * set client objects
400
     *
401
     * @throws ReflectionExceptionAlias
402
     */
403
    private function setClientObjects()
404
    {
405
        $clientObjects = $this->getClientObjects();
406
407
        // we update the input values ​​after
408
        // we receive and check the saved objects.
409
        foreach ($clientObjects as $key=>$value){
410
411
            if(isset($clientObjects['origin'][$key])){
412
413
                $this->{$key} = $clientObjects['origin'][$key];
414
                $this->inputs[$key] = $this->{$key};
415
416
                // the request update to be performed using
417
                // the method name to be used with the http method.
418
                $this->registerRequestInputs($key);
419
            }
420
        }
421
    }
422
423
    /**
424
     * register request inputs
425
     *
426
     * @param $key
427
     *
428
     * @throws ReflectionExceptionAlias
429
     */
430
    private function registerRequestInputs($key)
431
    {
432
        // the method name to be used with
433
        // the http method.
434
        $requestMethod = $this->requestHttp->getMethod().''.ucfirst($key);
435
436
        // the request update to be performed using
437
        // the method name to be used with the http method.
438
        $this->setRequestInputs($requestMethod,$key);
439
440
        // the request update to be performed using
441
        // the method name to be used without the http method.
442
        $this->setRequestInputs($key,$key);
443
    }
444
445
    /**
446
     * set request inputs
447
     *
448
     * @param $method
449
     * @param $key
450
     *
451
     * @throws ReflectionExceptionAlias
452
     */
453
    private function setRequestInputs($method,$key)
454
    {
455
        if(method_exists($this,$method) && $this->reflection->reflectionMethodParams($method)->isProtected){
456
457
            //check annotations for method
458
            $annotation = app()->resolve(RequestAnnotationManager::class,['request'=>$this]);
459
            $annotation->annotation($method,$key);
460
461
            if(isset($this->inputs[$key]) && is_array($this->inputs[$key])){
462
463
                $inputKeys = $this->inputs[$key];
464
465
                $this->inputs[$key] = [];
466
                foreach ($inputKeys as $input){
467
468
                    $this->{$key}           = $input;
469
                    $keyMethod              = $this->{$method}();
470
                    $this->inputs[$key][]   = $keyMethod;
471
                }
472
            }
473
            else{
474
                if(isset($this->inputs[$key])){
475
                    $keyMethod = $this->{$method}();
476
                    $this->inputs[$key] = $keyMethod;
477
                }
478
479
            }
480
        }
481
    }
482
483
    /**
484
     * validation for request
485
     *
486
     * @return void
487
     */
488
    private function validation()
489
    {
490
        // the auto object validate property is the property
491
        // where all of your request values ​​are automatically validated.
492
        if(property_exists($this,'autoObjectValidate')
493
            && is_array($this->autoObjectValidate) && count($this->autoObjectValidate)){
494
            $this->autoValidate('autoObjectValidate');
495
        }
496
    }
497
}