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

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