Test Setup Failed
Push — master ( 11a9ee...dc5d9f )
by Php Easy Api
03:37
created

Client::generatorManager()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 16
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 6
nc 8
nop 0
dl 0
loc 16
rs 9.6111
c 0
b 0
f 0
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(is_numeric($dataKey) && method_exists($getObjectInstance,$data) && isset($this->origin[$data])){
115
                    if(!is_array($this->origin[$data])){
116
                        $this->origin[$data] = array($this->origin[$data]);
117
                    }
118
                    foreach ($this->origin[$data] as $originData){
119
                        $getObjectInstance->{$data}($originData);
120
                    }
121
                }
122
            }
123
        }
124
    }
125
126
    /**
127
     * capsule inputs
128
     *
129
     * @return void|mixed
130
     */
131
    private function capsule()
132
    {
133
        //a process can be added to the capsule array using the method.
134
        if(method_exists($this,'capsuleMethod')){
135
            $this->capsule = array_merge($this->capsule,$this->capsuleMethod());
136
        }
137
138
        // expected method is executed.
139
        // this method is a must for http method values to be found in this property.
140
        if($this->checkProperties('capsule')){
141
142
            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...
143
                $this->capsule = array_merge($this->capsule,$this->auto_capsule);
144
            }
145
146
            if($this->checkProperties('groups')){
147
                $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

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

180
        /** @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...
181
182
        // Determines which HTTP method
183
        // the request object will be exposed to.
184
        if($this->checkProperties('http')){
185
186
            // if the current http method does not exist
187
            // in the http object, the exception will be thrown.
188
            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

188
            if(!in_array($method,/** @scrutinizer ignore-type */ $this->http)){
Loading history...
189
190
                //exception batMethodCall
191
                exception()->badMethodCall(
192
                    '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

192
                    '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

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

301
            $generators = array_merge(isset($generators) ? $generators: [],/** @scrutinizer ignore-type */ $this->getGenerators());
Loading history...
302
        }
303
304
        if(isset($generators)){
305
            $this->generatorMethod($generators);
306
        }
307
    }
308
309
    /**
310
     * generator method
311
     *
312
     * @param $generators
313
     *
314
     * @throws ReflectionExceptionAlias
315
     */
316
    private function generatorMethod($generators)
317
    {
318
        //generator array object
319
        foreach ($generators as $generator){
320
321
            //generator method name
322
            $generatorMethodName = $generator.'Generator';
323
324
            // if the generator method is present,
325
            // the fake value is assigned.
326
            if(method_exists($this,$generatorMethodName)){
327
328
                //fake registration
329
                if(!isset($this->inputs[$generator])){
330
331
                    $generatorMethodNameResult = $this->{$generatorMethodName}();
332
333
                    if(!is_null($generatorMethodNameResult)){
334
                        $this->{$generator} = $this->{$generatorMethodName}();
335
                        $this->inputs[$generator] = $this->{$generatorMethodName}();
336
                        $this->generatorList[] = $generator;
337
                    }
338
                }
339
                else {
340
341
                    if($this->checkProperties('auto_generators_dont_overwrite')
342
                        && 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

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