Passed
Pull Request — master (#1)
by
unknown
14:51
created

RequestModelFactory::validateRequest()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 2
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\RequestModel;
6
7
use Psr\Http\Message\ServerRequestInterface;
8
use ReflectionParameter;
9
use Yiisoft\Injector\Injector;
10
use ReflectionException;
11
use ReflectionClass;
12
13
final class RequestModelFactory
14
{
15
    private Injector $injector;
16
    private RequestModelValidator $validator;
17
18
    public function __construct(RequestModelValidator $validator, Injector $injector)
19
    {
20
        $this->validator = $validator;
21
        $this->injector = $injector;
22
    }
23
24
    /**
25
     * @param ServerRequestInterface $request
26
     * @param array|ReflectionParameter[] $handlerParams
27
     * @return array
28
     * @throws ReflectionException
29
     */
30
    public function createInstances(ServerRequestInterface $request, array $handlerParams): array
31
    {
32
        $requestModelInstances = [];
33
        foreach ($this->getModelRequestClasses($handlerParams) as $modelClass) {
34
            $requestModelInstances[] = $this->processModel($request, $this->injector->make($modelClass));
35
        }
36
37
        return $requestModelInstances;
38
    }
39
40
    private function processModel(ServerRequestInterface $request, RequestModelInterface $model): RequestModelInterface
41
    {
42
        $requestData = $this->getRequestData($request);
43
        $model->setRequestData($requestData);
44
        if ($model instanceof ValidatableModelInterface) {
45
            $this->validateRequest($model, $requestData);
46
        }
47
48
        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...
49
    }
50
51
    /**
52
     * @param array|ReflectionParameter[] $handlerParams
53
     * @return array
54
     */
55
    private function getModelRequestClasses(array $handlerParams): array
56
    {
57
        $modelClasses = [];
58
        foreach ($handlerParams as $param) {
59
            if ($this->paramsIsRequestModel($param)) {
60
                $modelClasses[] = $param->getType()->getName();
61
            }
62
        }
63
64
        return $modelClasses;
65
    }
66
67
    private function paramsIsRequestModel(ReflectionParameter $param): bool
68
    {
69
        if (!$param->hasType() || $param->getType()->isBuiltin()) {
70
            return false;
71
        }
72
73
        return (new ReflectionClass($param->getType()->getName()))->implementsInterface(RequestModelInterface::class);
74
    }
75
76
    private function getRequestData(ServerRequestInterface $request): array
77
    {
78
        return [
79
            'query' => $request->getQueryParams(),
80
            'body' => $request->getParsedBody(),
81
            'attributes' => $request->getAttributes(),
82
            'headers' => $request->getHeaders(),
83
            'files' => $request->getUploadedFiles(),
84
            'cookie' => $request->getCookieParams()
85
        ];
86
    }
87
88
    private function validateRequest(ValidatableModelInterface $model, array $requestData): void
89
    {
90
        $errors = $this->validator->validate($requestData, $model->getRules());
91
        if (!empty($errors)) {
92
            throw new RequestValidationException($errors);
93
        }
94
    }
95
}
96