Test Setup Failed
Push — master ( 08eb9d...10c71b )
by Php Easy Api
04:31
created

Client::capsule()   B

Complexity

Conditions 8
Paths 7

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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