Passed
Pull Request — master (#18)
by
unknown
01:51
created

RequestModelFactory::processModel()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 8
c 1
b 0
f 0
nc 3
nop 2
dl 0
loc 13
ccs 9
cts 9
cp 1
crap 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\RequestModel;
6
7
use Psr\Http\Message\ServerRequestInterface;
8
use ReflectionClass;
9
use ReflectionException;
10
use ReflectionParameter;
11
use Yiisoft\Injector\Injector;
12
use Yiisoft\Validator\Result;
13
use Yiisoft\Validator\ResultSet;
14
use Yiisoft\Validator\Validator;
15
use Generator;
16
17
final class RequestModelFactory
18
{
19
    private Injector $injector;
20
21 15
    public function __construct(Injector $injector)
22
    {
23 15
        $this->injector = $injector;
24 15
    }
25
26
    /**
27
     * @param ServerRequestInterface $request
28
     * @param array|ReflectionParameter[] $handlerParams
29
     *
30
     * @return array
31
     * @throws ReflectionException
32
     *
33
     */
34 9
    public function createInstances(ServerRequestInterface $request, array $handlerParams): array
35
    {
36 9
        $requestModelInstances = [];
37 9
        foreach ($this->getModelRequestClasses($handlerParams) as $modelClass) {
38 8
            $requestModelInstances[] = $this->processModel($request, $this->injector->make($modelClass));
39
        }
40
41 8
        return $requestModelInstances;
42
    }
43
44 8
    private function processModel(ServerRequestInterface $request, RequestModelInterface $model): RequestModelInterface
45
    {
46 8
        $requestData = $this->getRequestData($request);
47 8
        $model->setRequestData($requestData);
48 8
        if ($model instanceof ValidatableModelInterface) {
49 2
            $result = $this->createValidator($model)->validate($model);
50 2
            $errors = $this->getErrorsFromValidationResult($result);
51 2
            if ($errors->valid()) {
52 1
                throw new RequestValidationException($errors);
53
            }
54
        }
55
56 7
        return $model;
57
    }
58
59
    /**
60
     * @param array|ReflectionParameter[] $handlerParams
61
     *
62
     * @return array
63
     */
64 9
    private function getModelRequestClasses(array $handlerParams): array
65
    {
66 9
        $modelClasses = [];
67 9
        foreach ($handlerParams as $param) {
68 9
            if ($this->paramsIsRequestModel($param)) {
69 8
                $modelClasses[] = $param->getType()->getName();
70
            }
71
        }
72
73 9
        return $modelClasses;
74
    }
75
76 9
    private function paramsIsRequestModel(ReflectionParameter $param): bool
77
    {
78 9
        if (!$param->hasType() || $param->getType()->isBuiltin()) {
79
            return false;
80
        }
81
82 9
        return (new ReflectionClass($param->getType()->getName()))->implementsInterface(RequestModelInterface::class);
0 ignored issues
show
Bug introduced by
The method getName() does not exist on ReflectionType. It seems like you code against a sub-type of ReflectionType such as ReflectionNamedType. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

82
        return (new ReflectionClass($param->getType()->/** @scrutinizer ignore-call */ getName()))->implementsInterface(RequestModelInterface::class);
Loading history...
83
    }
84
85 8
    private function getRequestData(ServerRequestInterface $request): array
86
    {
87
        return [
88 8
            'query' => $request->getQueryParams(),
89 8
            'body' => $request->getParsedBody(),
90 8
            'attributes' => $request->getAttributes(),
91 8
            'headers' => $request->getHeaders(),
92 8
            'files' => $request->getUploadedFiles(),
93 8
            'cookie' => $request->getCookieParams(),
94
        ];
95
    }
96
97 2
    private function createValidator(ValidatableModelInterface $model): Validator
98
    {
99 2
        return new Validator($model->getRules());
100
    }
101
102 2
    private function getErrorsFromValidationResult(ResultSet $result): Generator
103
    {
104 2
        foreach ($result->getIterator() as $field => $fieldResult) {
105 2
            if (!$fieldResult->isValid()) {
106 1
                yield $field => $fieldResult->getErrors();
107
            }
108
        }
109 1
    }
110
}
111