Test Setup Failed
Push — master ( b4fcac...70c0c0 )
by Php Easy Api
03:53
created

Client::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 16
rs 10
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
 */
17
class Client extends ClientAbstract implements HandleContracts
18
{
19
    /**
20
     * @var array
21
     */
22
    protected $capsule = [];
23
24
    /**
25
     * @var null|string
26
     */
27
    protected $clientName;
28
29
    /**
30
     * @var array
31
     */
32
    protected $except = [];
33
34
    /**
35
     * @var null|string
36
     */
37
    protected $method;
38
39
    /**
40
     * @var ReflectionProcess
41
     */
42
    protected $reflection;
43
44
    /**
45
     * @var null|ClientHttpManager
46
     */
47
    protected $requestHttp;
48
49
    /**
50
     * @var null|array
51
     */
52
    protected $clientData;
53
54
    /**
55
     * @var array
56
     */
57
    protected $requestData = [];
58
59
    /**
60
     * @var array
61
     */
62
    protected $generatorList = [];
63
64
    /**
65
     * Request constructor.
66
     *
67
     * @param null|array $clientData
68
     *
69
     * @throws ReflectionExceptionAlias
70
     */
71
    public function __construct($clientData=null)
72
    {
73
        //reflection process
74
        $this->reflection = app()['reflection']($this);
75
76
        //set clientName for client
77
        $this->setClientName();
78
79
        //get http method via request http manager class
80
        $this->requestHttp = app()->resolve(ClientHttpManager::class,['client'=>$this]);
81
82
        //get request client data
83
        $this->clientData = ($clientData===null) ? $this->requestHttp->resolve() : $clientData;
84
85
        //handle request
86
        $this->handle();
87
    }
88
89
    /**
90
     * auto validate
91
     *
92
     * @param $validate
93
     */
94
    private function autoValidate($validate)
95
    {
96
        //we get the values ​​to auto-validate.
97
        foreach ($this->{$validate} as $object=>$datas){
98
99
            if(false===Utils::isNamespaceExists($object)){
100
                return;
101
            }
102
103
            // the auto-validate value must necessarily represent a class.
104
            // otherwise auto-validate is not used.
105
            $getObjectInstance = app()->resolve($object);
106
107
            // we get the index values,
108
            // which are called methods of the auto-validate value that represents the class.
109
            foreach ($datas as $dataKey=>$data){
110
111
                // if the methods of the auto-validate class resolved by the container resolve method apply,
112
                // the process of auto-validate automatic implementation will be completed.
113
                if(is_numeric($dataKey) && method_exists($getObjectInstance,$data) && isset($this->origin[$data])){
114
                    if(!is_array($this->origin[$data])){
115
                        $this->origin[$data] = array($this->origin[$data]);
116
                    }
117
                    foreach ($this->origin[$data] as $originData){
118
                        $getObjectInstance->{$data}($originData);
119
                    }
120
                }
121
            }
122
        }
123
    }
124
125
    /**
126
     * capsule inputs
127
     *
128
     * @return void|mixed
129
     */
130
    private function capsule()
131
    {
132
        //a process can be added to the capsule array using the method.
133
        if(method_exists($this,'capsuleMethod')){
134
            $this->capsule = array_merge($this->capsule,$this->capsuleMethod());
135
        }
136
137
        // expected method is executed.
138
        // this method is a must for http method values to be found in this property.
139
        if($this->checkProperties('capsule')){
140
141
            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...
142
                $this->capsule = array_merge($this->capsule,$this->auto_capsule);
143
            }
144
145
            $caret = $this->capsuleCaret();
146
147
            foreach($this->inputs as $input=>$value){
148
149
                if(isset($caret[$input]) || (
150
                        $this->checkProperties('capsule') && !in_array($input,$this->capsule)
151
                    )){
152
                    exception('clientCapsule',['key'=>$input])
153
                        ->overflow('The '.$input.' value cannot be sent.');
154
                }
155
            }
156
        }
157
    }
158
159
    /**
160
     * get capsule caret for request
161
     *
162
     * @return array
163
     */
164
    private function capsuleCaret()
165
    {
166
        $caret = [];
167
168
        foreach($this->inputs as $input=>$item){
169
            if(in_array('@'.$input,$this->capsule)){
170
                $caret[$input] = $item;
171
            }
172
        }
173
174
        foreach ($this->capsule as $item) {
175
            if(preg_match('#@.*#is',$item)){
176
                $this->capsule = array_diff($this->capsule,[$item]);
177
            }
178
        }
179
180
        return $caret;
181
    }
182
183
    /**
184
     * check http method
185
     *
186
     * @return void|mixed
187
     */
188
    private function checkHttpMethod()
189
    {
190
        //get http method
191
        $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

191
        /** @scrutinizer ignore-call */ 
192
        $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...
192
193
        // Determines which HTTP method
194
        // the request object will be exposed to.
195
        if($this->checkProperties('http')){
196
197
            // if the current http method does not exist
198
            // in the http object, the exception will be thrown.
199
            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

199
            if(!in_array($method,/** @scrutinizer ignore-type */ $this->http)){
Loading history...
200
201
                //exception batMethodCall
202
                exception()->badMethodCall(
203
                    'Invalid http method process for '.basename($this).'.That is accepted http methods ['.implode(",",$this->http).'] ');
0 ignored issues
show
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

203
                    'Invalid http method process for '.basename(/** @scrutinizer ignore-type */ $this).'.That is accepted http methods ['.implode(",",$this->http).'] ');
Loading history...
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

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

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

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