Test Setup Failed
Push — master ( 5617df...bb1833 )
by Php Easy Api
04:40
created

Client::autoValidate()   C

Complexity

Conditions 13
Paths 13

Size

Total Lines 35
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 14
nc 13
nop 1
dl 0
loc 35
rs 6.6166
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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

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

157
                $this->capsule = array_merge($this->capsule,/** @scrutinizer ignore-type */ $this->groups);
Loading history...
158
159
                foreach ($this->capsule as $item) {
160
                    $groupProcess = $this->groupsProcess($item,true);
161
                    if(is_array($groupProcess)){
162
                        $defaultInputs = $this->inputs;
163
                        $this->inputs = array_merge($this->inputs,$groupProcess);
164
                    }
165
                }
166
            }
167
168
            foreach($this->inputs as $input=>$value){
169
170
                if($this->checkProperties('capsule') && !in_array($input,$this->capsule)){
171
                    exception('clientCapsule',['key'=>$input])
172
                        ->overflow('The '.$input.' value cannot be sent.');
173
                }
174
            }
175
176
            if(isset($defaultInputs)){
177
                $this->inputs = $defaultInputs;
178
            }
179
        }
180
    }
181
182
    /**
183
     * check http method
184
     *
185
     * @return void|mixed
186
     */
187
    private function checkHttpMethod()
188
    {
189
        //get http method
190
        $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

190
        /** @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...
191
192
        // Determines which HTTP method
193
        // the request object will be exposed to.
194
        if($this->checkProperties('http')){
195
196
            // if the current http method does not exist
197
            // in the http object, the exception will be thrown.
198
            if(!in_array($method,$this->http)){
0 ignored issues
show
Bug introduced by
$this->http of type Resta\Client\Client is incompatible with the type array expected by parameter $haystack of in_array(). ( Ignorable by Annotation )

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

198
            if(!in_array($method,/** @scrutinizer ignore-type */ $this->http)){
Loading history...
199
200
                //exception batMethodCall
201
                exception()->badMethodCall(
202
                    'Invalid http method process for '.basename($this).'.That is accepted http methods ['.implode(",",$this->http).'] ');
0 ignored issues
show
Bug introduced by
$this->http of type Resta\Client\Client is incompatible with the type array expected by parameter $pieces of implode(). ( Ignorable by Annotation )

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

202
                    'Invalid http method process for '.basename($this).'.That is accepted http methods ['.implode(",",/** @scrutinizer ignore-type */ $this->http).'] ');
Loading history...
Bug introduced by
$this of type Resta\Client\Client is incompatible with the type string expected by parameter $path of basename(). ( Ignorable by Annotation )

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

202
                    'Invalid http method process for '.basename(/** @scrutinizer ignore-type */ $this).'.That is accepted http methods ['.implode(",",$this->http).'] ');
Loading history...
203
            }
204
        }
205
    }
206
207
    /**
208
     * check properties
209
     *
210
     * @param $properties
211
     * @return bool
212
     */
213
    private function checkProperties($properties)
214
    {
215
        // from the properties of the object properties to
216
        // the existing variables, control the array and at least one element.
217
        return (property_exists($this,$properties)
218
            && is_array($this->{$properties}) && count($this->{$properties})) ? true : false;
219
    }
220
221
    /**
222
     * register container for request
223
     *
224
     * @return mixed|void
225
     */
226
    private function containerRegister()
227
    {
228
        // we are saving the expected values ​​for the request in container.
229
        // this record can be returned in exception information.
230
        app()->register('requestExpected',$this->expected);
231
    }
232
233
    /**
234
     * get request except
235
     *
236
     * @param $except
237
     * @return $this
238
     */
239
    public function except($except)
240
    {
241
        // the except parameter is a callable value.
242
        if(is_callable($except)){
243
            $call = call_user_func_array($except,[$this]);
244
            $except = $call;
245
        }
246
247
        // except with the except exceptions property
248
        // and then assigning them to the inputs property.
249
        $this->except = array_merge($this->except,$except);
250
        $this->inputs = array_diff_key($this->inputs,array_flip($this->except));
251
252
        return $this;
253
    }
254
255
    /**
256
     * expected inputs
257
     *
258
     * @return void|mixed
259
     */
260
    private function expectedInputs()
261
    {
262
        // expected method is executed.
263
        // this method is a must for http method values to be found in this property.
264
        if($this->checkProperties('expected')){
265
266
            // if the expected values are not found in the inputs array,
267
            // the exception will be thrown.
268
            foreach ($this->expected as $expected){
269
270
                $expectedValues = [];
271
272
                // mandatory expected data for each key can be separated by | operator.
273
                // this is evaluated as "or".
274
                foreach($expectedData = explode("|",$expected) as $inputs){
275
276
                    // we should do key control for group format.
277
                    // this process will allow us to perform key control for 2D array correctly.
278
                    $this->groupsProcess($inputs);
279
280
                    if(!isset($this->inputs[$inputs])){
281
                        $expectedValues[$inputs] = $inputs;
282
                    }
283
                }
284
285
                // if the expectedData and expectedValues ​​
286
                // array are numerically equal to the expected key, the exception is thrown.
287
                if(count($expectedData)===count($expectedValues)){
288
                    exception('clientExpected',['key'=>$expected])
289
                        ->unexpectedValue('You absolutely have to send the value '.implode(" or ",$expectedValues).' for request object');
290
                }
291
            }
292
        }
293
    }
294
295
    /**
296
     * generator manager
297
     *
298
     * @throws ReflectionExceptionAlias
299
     */
300
    private function generatorManager()
301
    {
302
        // check the presence of the generator object
303
        // and operate the generator over this object.
304
        if($this->checkProperties('auto_generators')){
305
            $generators = $this->getAutoGenerators();
306
        }
307
308
        // check the presence of the generator object
309
        // and operate the generator over this object.
310
        if($this->checkProperties('generators')){
311
            $generators = array_merge(isset($generators) ? $generators: [],$this->getGenerators());
0 ignored issues
show
Bug introduced by
It seems like $this->getGenerators() can also be of type Resta\Client\ClientAbstract; however, parameter $array2 of array_merge() does only seem to accept array|null, 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

311
            $generators = array_merge(isset($generators) ? $generators: [],/** @scrutinizer ignore-type */ $this->getGenerators());
Loading history...
312
        }
313
314
        if(isset($generators)){
315
            $this->generatorMethod($generators);
316
        }
317
    }
318
319
    /**
320
     * generator method
321
     *
322
     * @param $generators
323
     *
324
     * @throws ReflectionExceptionAlias
325
     */
326
    private function generatorMethod($generators)
327
    {
328
        //generator array object
329
        foreach ($generators as $generator){
330
331
            //generator method name
332
            $generatorMethodName = $generator.'Generator';
333
334
            // if the generator method is present,
335
            // the fake value is assigned.
336
            if(method_exists($this,$generatorMethodName)){
337
338
                //fake registration
339
                if(!isset($this->inputs[$generator])){
340
341
                    $generatorMethodNameResult = $this->{$generatorMethodName}();
342
343
                    if(!is_null($generatorMethodNameResult)){
344
                        $this->{$generator} = $this->{$generatorMethodName}();
345
                        $this->inputs[$generator] = $this->{$generatorMethodName}();
346
                        $this->generatorList[] = $generator;
347
                    }
348
                }
349
                else {
350
351
                    if($this->checkProperties('auto_generators_dont_overwrite')
352
                        && in_array($generator,$this->getAutoGeneratorsDontOverwrite())){
0 ignored issues
show
Bug introduced by
It seems like $this->getAutoGeneratorsDontOverwrite() can also be of type Resta\Client\ClientAbstract; however, parameter $haystack of in_array() 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

352
                        && in_array($generator,/** @scrutinizer ignore-type */ $this->getAutoGeneratorsDontOverwrite())){
Loading history...
353
                        $this->{$generator} = $this->{$generatorMethodName}();
354
                        $this->inputs[$generator] = $this->{$generatorMethodName}();
355
                        $this->generatorList[] = $generator;
356
                    }
357
358
                    if($this->checkProperties('generators_dont_overwrite')
359
                        && in_array($generator,$this->getGeneratorsDontOverwrite())){
360
                        $this->{$generator} = $this->{$generatorMethodName}();
361
                        $this->inputs[$generator] = $this->{$generatorMethodName}();
362
                        $this->generatorList[] = $generator;
363
                    }
364
365
                }
366
367
                $this->registerRequestInputs($generator);
368
            }
369
        }
370
    }
371
372
    /**
373
     * get client name for request
374
     *
375
     * @return string
376
     */
377
    public function getClientName()
378
    {
379
        return $this->clientName;
380
    }
381
382
    /**
383
     * we should do key control for group format.
384
     * this process will allow us to perform key control for 2D array correctly.
385
     *
386
     * @param null $key
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $key is correct as it would always require null to be passed?
Loading history...
387
     * @param null $callback
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $callback is correct as it would always require null to be passed?
Loading history...
388
     * @return mixed|void
389
     */
390
    public function groupsProcess($key=null,$callback=null)
391
    {
392
        if(property_exists($this,'groups') && is_array($this->groups)){
0 ignored issues
show
introduced by
The condition is_array($this->groups) is always false.
Loading history...
393
394
            $clientObjects = $this->getClientObjects();
395
396
            foreach ($this->groups as $group){
397
398
                if(true === $callback){
399
                    if(isset($clientObjects['origin'][$key])){
400
                        return $clientObjects['origin'][$key];
401
                    }
402
                    return [];
403
                }
404
405
                if(isset($clientObjects['origin'][$group][$key])){
406
407
                    $this->{$key} = $clientObjects['origin'][$group][$key];
408
                    $this->inputs[$key] = $this->{$key};
409
410
                    if(is_callable($callback)){
411
                        call_user_func_array($callback,[$key]);
412
                    }
413
                }
414
            }
415
        }
416
417
        return [];
418
    }
419
420
    /**
421
     * request handle
422
     *
423
     * @return mixed|void
424
     *
425
     * @throws ReflectionExceptionAlias
426
     */
427
    public function handle()
428
    {
429
        //set container for request
430
        $this->containerRegister();
431
432
        //we record the values ​​
433
        //that coming with the post.
434
        $this->initClient();
435
436
        // this method determines
437
        // how the request object will be requested,
438
        $this->checkHttpMethod();
439
440
        // it passes all keys that are sent through
441
        // a validation method on the user side.
442
        $this->validation();
443
444
        // get capsule as mandatory values
445
        $this->capsule();
446
447
        // if a fake method is defined and it is not in
448
        // the context of any key method when access is granted,
449
        // it can be filled with fake method.
450
        $this->generatorManager();
451
452
        // contrary to capsule method,
453
        // expected values must be in the key being sent.
454
        $this->expectedInputs();
455
456
        // we update the input values ​​after
457
        // we receive and check the saved objects.
458
        $this->setClientObjects();
459
460
        // the values ​​specified in request except property
461
        // are subtracted from all input values.
462
        $this->requestExcept();
463
    }
464
465
    /**
466
     * get init client
467
     *
468
     * @return void
469
     */
470
    private function initClient()
471
    {
472
        // we use the http method to write
473
        // the values to the inputs and origin properties.
474
        foreach($this->clientData as $key=>$value){
475
476
            //inputs and origin properties
477
            $this->inputs[$key] = $value;
478
            $this->origin[$key] = $value;
479
        }
480
    }
481
482
    /**
483
     * the values ​​specified in request except property
484
     * are subtracted from all input values.
485
     *
486
     * @return mixed|void
487
     */
488
    private function requestExcept()
489
    {
490
        if(property_exists($this,'requestExcept') && is_array($this->requestExcept)){
0 ignored issues
show
introduced by
The condition is_array($this->requestExcept) is always false.
Loading history...
491
            foreach ($this->requestExcept as $item){
492
                if(isset($this->inputs[$item])){
493
                    unset($this->inputs[$item]);
494
                }
495
            }
496
        }
497
    }
498
499
    /**
500
     * set client name for client resolver
501
     *
502
     * @param null|string $clientName
503
     * @return void|mixed
504
     */
505
    public function setClientName($clientName=null)
506
    {
507
        if(!is_null($clientName) && is_string($clientName)){
508
            return $this->clientName = $clientName;
509
        }
510
511
        if(!is_null(Utils::trace(0)) && isset(Utils::trace(0)['object'])){
512
            $backTrace = Utils::trace(0)['object'];
513
514
            if(property_exists($backTrace,'clientName')){
515
                $this->clientName = $backTrace->clientName;
516
            }
517
        }
518
    }
519
520
    /**
521
     * set client objects
522
     *
523
     * @throws ReflectionExceptionAlias
524
     */
525
    private function setClientObjects()
526
    {
527
        $clientObjects = $this->getClientObjects();
528
529
        // we update the input values ​​after
530
        // we receive and check the saved objects.
531
        foreach ($clientObjects as $key=>$value){
532
533
            // we should do key control for group format.
534
            // this process will allow us to perform key control for 2D array correctly.
535
            $this->groupsProcess($key,function($key){
536
                $this->registerRequestInputs($key);
537
                unset($this->inputs[$key]);
538
            });
539
540
            if(!in_array($key,$this->generatorList) && isset($clientObjects['origin'][$key])){
541
542
                $this->{$key} = $clientObjects['origin'][$key];
543
                $this->inputs[$key] = $this->{$key};
544
545
                // the request update to be performed using
546
                // the method name to be used with the http method.
547
                $this->registerRequestInputs($key);
548
            }
549
        }
550
551
    }
552
553
    /**
554
     * register request inputs
555
     *
556
     * @param $key
557
     *
558
     * @throws ReflectionExceptionAlias
559
     */
560
    private function registerRequestInputs($key)
561
    {
562
        // the method name to be used with
563
        // the http method.
564
        $requestMethod = $this->requestHttp->getMethod().''.ucfirst($key);
565
566
        // the request update to be performed using
567
        // the method name to be used with the http method.
568
        $this->setRequestInputs($requestMethod,$key);
569
570
        // the request update to be performed using
571
        // the method name to be used without the http method.
572
        $this->setRequestInputs($key,$key);
573
    }
574
575
    /**
576
     * set request inputs
577
     *
578
     * @param $method
579
     * @param $key
580
     *
581
     * @throws ReflectionExceptionAlias
582
     */
583
    private function setRequestInputs($method,$key)
584
    {
585
        if(!in_array($key,$this->generatorList) && method_exists($this,$method) && $this->reflection->reflectionMethodParams($method)->isProtected){
586
587
            //check annotations for method
588
            $annotation = app()->resolve(ClientAnnotationManager::class,['request'=>$this]);
589
            $annotation->annotation($method,$key);
590
591
            if(isset($this->inputs[$key]) && is_array($this->inputs[$key])){
592
593
                $inputKeys = $this->inputs[$key];
594
595
                $this->inputs[$key] = [];
596
                foreach ($inputKeys as $input){
597
598
                    $this->{$key}               = $input;
599
                    $keyMethod                  = $this->{$method}();
600
                    $this->inputs[$key][]       = $keyMethod;
601
                }
602
            }
603
            else{
604
                if(isset($this->inputs[$key])){
605
                    $keyMethod = $this->{$method}();
606
                    $this->inputs[$key] = $keyMethod;
607
                }
608
609
            }
610
        }
611
    }
612
613
    /**
614
     * validation for request
615
     *
616
     * @return void
617
     */
618
    private function validation()
619
    {
620
        // the auto object validate property is the property
621
        // where all of your request values ​​are automatically validated.
622
        /** @noinspection PhpParamsInspection */
623
        if(property_exists($this,'autoObjectValidate')
624
            && is_array($this->autoObjectValidate) && count($this->autoObjectValidate)){
0 ignored issues
show
introduced by
The condition is_array($this->autoObjectValidate) is always false.
Loading history...
625
            $this->autoValidate('autoObjectValidate');
626
        }
627
    }
628
}