Passed
Push — master ( b99b0a...be2805 )
by Sergei
05:00 queued 02:01
created

RequestModelFactory   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 89
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 14
eloc 36
c 2
b 0
f 0
dl 0
loc 89
ccs 41
cts 41
cp 1
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A createInstances() 0 8 2
A processModel() 0 13 3
A __construct() 0 5 1
A getRequestData() 0 10 1
A getModelRequestClasses() 0 21 5
A isInstantiableRequestModel() 0 6 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 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 13
    public function __construct(
20
        private ValidatorInterface $validator,
21
        private Injector $injector,
22
        private CurrentRoute $currentRoute
23
    ) {
24 13
    }
25
26
    /**
27
     * @param ReflectionParameter[] $handlerParams
28
     *
29
     * @throws ReflectionException
30
     */
31 11
    public function createInstances(ServerRequestInterface $request, array $handlerParams): array
32
    {
33 11
        $requestModelInstances = [];
34 11
        foreach ($this->getModelRequestClasses($handlerParams) as $modelClass) {
35 5
            $requestModelInstances[] = $this->processModel($request, $this->injector->make($modelClass));
36
        }
37
38 10
        return $requestModelInstances;
39
    }
40
41 5
    private function processModel(ServerRequestInterface $request, RequestModelInterface $model): RequestModelInterface
42
    {
43 5
        $requestData = $this->getRequestData($request);
44 5
        $model->setRequestData($requestData);
45 5
        if ($model instanceof RulesProviderInterface) {
46 2
            $result = $this->validator->validate($model);
47 2
            if (!$result->isValid()) {
48 1
                $errorMessagesIndexedByAttribute = $result->getErrorMessagesIndexedByAttribute();
49 1
                throw new RequestValidationException($errorMessagesIndexedByAttribute);
50
            }
51
        }
52
53 4
        return $model;
54
    }
55
56
    /**
57
     * @param ReflectionParameter[] $handlerParams
58
     *
59
     * @psalm-return list<class-string<RequestModelInterface>>
60
     */
61 11
    private function getModelRequestClasses(array $handlerParams): array
62
    {
63 11
        $modelClasses = [];
64 11
        foreach ($handlerParams as $param) {
65 11
            $type = $param->getType();
66
            if (
67 11
                !$type instanceof ReflectionNamedType
68 11
                || $type->isBuiltin()
69
            ) {
70 3
                continue;
71
            }
72
73 8
            $className = $type->getName();
74 8
            if (!$this->isInstantiableRequestModel($className)) {
75 3
                continue;
76
            }
77
78 5
            $modelClasses[] = $className;
79
        }
80
81 11
        return $modelClasses;
82
    }
83
84
    /**
85
     * @psalm-param class-string $className
86
     * @psalm-assert-if-true class-string<RequestModelInterface> $className
87
     */
88 8
    private function isInstantiableRequestModel(string $className): bool
89
    {
90 8
        $reflectionClass = new ReflectionClass($className);
91
92 8
        return $reflectionClass->isInstantiable()
93 8
            && $reflectionClass->implementsInterface(RequestModelInterface::class);
94
    }
95
96 5
    private function getRequestData(ServerRequestInterface $request): array
97
    {
98 5
        return [
99 5
            'query' => $request->getQueryParams(),
100 5
            'body' => $request->getParsedBody(),
101 5
            'attributes' => $request->getAttributes(),
102 5
            'headers' => $request->getHeaders(),
103 5
            'files' => $request->getUploadedFiles(),
104 5
            'cookie' => $request->getCookieParams(),
105 5
            'router' => $this->currentRoute->getArguments(),
106 5
        ];
107
    }
108
}
109