Passed
Pull Request — master (#17)
by
unknown
06:49
created

RequestModelFactory   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 104
Duplicated Lines 0 %

Test Coverage

Coverage 97.83%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 38
c 1
b 0
f 0
dl 0
loc 104
ccs 45
cts 46
cp 0.9783
rs 10
wmc 18

9 Methods

Rating   Name   Duplication   Size   Complexity  
A paramsIsRequestModel() 0 7 3
A processModel() 0 9 2
A getRequestData() 0 9 1
A getModelRequestClasses() 0 10 3
A __construct() 0 3 1
A getErrorsFromValidationResult() 0 13 3
A createValidator() 0 3 1
A validateRequest() 0 7 2
A createInstances() 0 8 2
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
16
final class RequestModelFactory
17
{
18
    private Injector $injector;
19
20 15
    public function __construct(Injector $injector)
21
    {
22 15
        $this->injector = $injector;
23 15
    }
24
25
    /**
26
     * @param ServerRequestInterface $request
27
     * @param array|ReflectionParameter[] $handlerParams
28
     *
29
     * @return array
30
     * @throws ReflectionException
31
     *
32
     */
33 9
    public function createInstances(ServerRequestInterface $request, array $handlerParams): array
34
    {
35 9
        $requestModelInstances = [];
36 9
        foreach ($this->getModelRequestClasses($handlerParams) as $modelClass) {
37 8
            $requestModelInstances[] = $this->processModel($request, $this->injector->make($modelClass));
38
        }
39
40 8
        return $requestModelInstances;
41
    }
42
43 8
    private function processModel(ServerRequestInterface $request, RequestModelInterface $model): RequestModelInterface
44
    {
45 8
        $requestData = $this->getRequestData($request);
46 8
        $model->setRequestData($requestData);
47 8
        if ($model instanceof ValidatableModelInterface) {
48 2
            $this->validateRequest($model, $requestData);
49
        }
50
51 7
        return $model;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $model could return the type Yiisoft\RequestModel\ValidatableModelInterface which is incompatible with the type-hinted return Yiisoft\RequestModel\RequestModelInterface. Consider adding an additional type-check to rule them out.
Loading history...
52
    }
53
54
    /**
55
     * @param array|ReflectionParameter[] $handlerParams
56
     *
57
     * @return array
58
     */
59 9
    private function getModelRequestClasses(array $handlerParams): array
60
    {
61 9
        $modelClasses = [];
62 9
        foreach ($handlerParams as $param) {
63 9
            if ($this->paramsIsRequestModel($param)) {
64 8
                $modelClasses[] = $param->getType()->getName();
65
            }
66
        }
67
68 9
        return $modelClasses;
69
    }
70
71 9
    private function paramsIsRequestModel(ReflectionParameter $param): bool
72
    {
73 9
        if (!$param->hasType() || $param->getType()->isBuiltin()) {
74
            return false;
75
        }
76
77 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

77
        return (new ReflectionClass($param->getType()->/** @scrutinizer ignore-call */ getName()))->implementsInterface(RequestModelInterface::class);
Loading history...
78
    }
79
80 8
    private function getRequestData(ServerRequestInterface $request): array
81
    {
82
        return [
83 8
            'query' => $request->getQueryParams(),
84 8
            'body' => $request->getParsedBody(),
85 8
            'attributes' => $request->getAttributes(),
86 8
            'headers' => $request->getHeaders(),
87 8
            'files' => $request->getUploadedFiles(),
88 8
            'cookie' => $request->getCookieParams(),
89
        ];
90
    }
91
92 2
    private function validateRequest(ValidatableModelInterface $model, array $requestData): void
93
    {
94 2
        $requestDataSet = new RequestDataSet($requestData);
95 2
        $result = $this->createValidator($model)->validate($requestDataSet);
96 2
        $errors = $this->getErrorsFromValidationResult($result);
97 2
        if (!empty($errors)) {
98 1
            throw new RequestValidationException($errors);
99
        }
100 1
    }
101
102 2
    private function createValidator(ValidatableModelInterface $model): Validator
103
    {
104 2
        return new Validator($model->getRules());
105
    }
106
107 2
    private function getErrorsFromValidationResult(ResultSet $result): array
108
    {
109
        /**
110
         * @var $fieldResult Result
111
         */
112 2
        $errors = [];
113 2
        foreach ($result->getIterator() as $field => $fieldResult) {
114 2
            if (!empty($fieldResult->getErrors())) {
115 1
                $errors[$field] = $fieldResult->getErrors();
116
            }
117
        }
118
119 2
        return $errors;
120
    }
121
}
122