Test Setup Failed
Push — master ( 9d5d98...5901a9 )
by Php Easy Api
04:16
created

Client::requestExcept()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 4
nc 4
nop 0
dl 0
loc 6
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
 */
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
            foreach($this->inputs as $input=>$value){
146
147
                if($this->checkProperties('capsule') && !in_array($input,$this->capsule)){
148
                    exception('clientCapsule',['key'=>$input])
149
                        ->overflow('The '.$input.' value cannot be sent.');
150
                }
151
            }
152
        }
153
    }
154
155
    /**
156
     * check http method
157
     *
158
     * @return void|mixed
159
     */
160
    private function checkHttpMethod()
161
    {
162
        //get http method
163
        $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

163
        /** @scrutinizer ignore-call */ 
164
        $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...
164
165
        // Determines which HTTP method
166
        // the request object will be exposed to.
167
        if($this->checkProperties('http')){
168
169
            // if the current http method does not exist
170
            // in the http object, the exception will be thrown.
171
            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

171
            if(!in_array($method,/** @scrutinizer ignore-type */ $this->http)){
Loading history...
172
173
                //exception batMethodCall
174
                exception()->badMethodCall(
175
                    '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

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

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

279
            $generators = array_merge(isset($generators) ? $generators: [],/** @scrutinizer ignore-type */ $this->getGenerators());
Loading history...
280
        }
281
282
        if(isset($generators)){
283
            $this->generatorMethod($generators);
284
        }
285
    }
286
287
    /**
288
     * generator method
289
     *
290
     * @param $generators
291
     *
292
     * @throws ReflectionExceptionAlias
293
     */
294
    private function generatorMethod($generators)
295
    {
296
        //generator array object
297
        foreach ($generators as $generator){
298
299
            //generator method name
300
            $generatorMethodName = $generator.'Generator';
301
302
            // if the generator method is present,
303
            // the fake value is assigned.
304
            if(method_exists($this,$generatorMethodName)){
305
306
                //fake registration
307
                if(!isset($this->inputs[$generator])){
308
309
                    $generatorMethodNameResult = $this->{$generatorMethodName}();
310
311
                    if(!is_null($generatorMethodNameResult)){
312
                        $this->{$generator} = $this->{$generatorMethodName}();
313
                        $this->inputs[$generator] = $this->{$generatorMethodName}();
314
                        $this->generatorList[] = $generator;
315
                    }
316
                }
317
                else {
318
319
                    if($this->checkProperties('auto_generators_dont_overwrite')
320
                        && 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

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