Passed
Pull Request — master (#41)
by Dmitriy
15:09 queued 13:01
created

RequestModelFactory::paramsIsRequestModel()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.2098

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 6
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 13
ccs 5
cts 7
cp 0.7143
crap 3.2098
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 ReflectionNamedType;
11
use ReflectionParameter;
12
use Yiisoft\Injector\Injector;
13
use Yiisoft\Router\CurrentRoute;
14
use Yiisoft\Validator\RulesProviderInterface;
15
use Yiisoft\Validator\ValidatorInterface;
16
17
final class RequestModelFactory
18
{
19
    private Injector $injector;
20
    private ValidatorInterface $validator;
21
    private CurrentRoute $currentRoute;
22
23 16
    public function __construct(ValidatorInterface $validator, Injector $injector, CurrentRoute $currentRoute)
24
    {
25 16
        $this->validator = $validator;
26 16
        $this->injector = $injector;
27 16
        $this->currentRoute = $currentRoute;
28
    }
29
30
    /**
31
     * @param ServerRequestInterface $request
32
     * @param array|ReflectionParameter[] $handlerParams
33
     *
34
     * @throws ReflectionException
35
     *
36
     * @return array
37
     */
38 10
    public function createInstances(ServerRequestInterface $request, array $handlerParams): array
39
    {
40 10
        $requestModelInstances = [];
41 10
        foreach ($this->getModelRequestClasses($handlerParams) as $modelClass) {
42 9
            $requestModelInstances[] = $this->processModel($request, $this->injector->make($modelClass));
43
        }
44
45 9
        return $requestModelInstances;
46
    }
47
48 9
    private function processModel(ServerRequestInterface $request, RequestModelInterface $model): RequestModelInterface
49
    {
50 9
        $requestData = $this->getRequestData($request);
51 9
        $model->setRequestData($requestData);
52 9
        if ($model instanceof RulesProviderInterface) {
53 2
            $result = $this->validator->validate($model);
54 2
            if (!$result->isValid()) {
55 1
                $errors = $result->getErrors();
56 1
                $errorMessagesIndexedByAttribute = [];
57 1
                foreach ($errors as $error) {
58 1
                    $errorMessagesIndexedByAttribute[(string)$error->getAttribute()][] = $error->getMessage();
59
                }
60 1
                throw new RequestValidationException($errorMessagesIndexedByAttribute);
61
            }
62
        }
63
64 8
        return $model;
65
    }
66
67
    /**
68
     * @param array|ReflectionParameter[] $handlerParams
69
     *
70
     * @return array
71
     */
72 10
    private function getModelRequestClasses(array $handlerParams): array
73
    {
74 10
        $modelClasses = [];
75 10
        foreach ($handlerParams as $param) {
76 10
            if (!$this->paramsIsRequestModel($param)) {
77 1
                continue;
78
            }
79
80
            /** @var ReflectionNamedType $type */
81 9
            $type = $param->getType();
82 9
            $modelClasses[] = $type->getName();
83
        }
84
85 10
        return $modelClasses;
86
    }
87
88 10
    private function paramsIsRequestModel(ReflectionParameter $param): bool
89
    {
90 10
        if (!$param->hasType()) {
91
            return false;
92
        }
93
94
        /** @var ReflectionNamedType $type */
95 10
        $type = $param->getType();
96 10
        if ($type->isBuiltin()) {
97
            return false;
98
        }
99
100 10
        return (new ReflectionClass($type->getName()))->implementsInterface(RequestModelInterface::class);
101
    }
102
103 9
    private function getRequestData(ServerRequestInterface $request): array
104
    {
105
        return [
106 9
            'query' => $request->getQueryParams(),
107 9
            'body' => $request->getParsedBody(),
108 9
            'attributes' => $request->getAttributes(),
109 9
            'headers' => $request->getHeaders(),
110 9
            'files' => $request->getUploadedFiles(),
111 9
            'cookie' => $request->getCookieParams(),
112 9
            'router' => $this->currentRoute->getArguments(),
113
        ];
114
    }
115
}
116