Passed
Pull Request — master (#32)
by Rustam
02:47 queued 44s
created

RequestModelFactory   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 102
Duplicated Lines 0 %

Test Coverage

Coverage 97.67%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 41
c 1
b 0
f 0
dl 0
loc 102
ccs 42
cts 43
cp 0.9767
rs 10
wmc 16

6 Methods

Rating   Name   Duplication   Size   Complexity  
A paramsIsRequestModel() 0 18 6
A processModel() 0 12 3
A getRequestData() 0 10 1
A getModelRequestClasses() 0 10 3
A __construct() 0 5 1
A createInstances() 0 10 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 ReflectionUnionType;
13
use Yiisoft\Injector\Injector;
14
use Yiisoft\Router\CurrentRouteInterface;
15
use Yiisoft\Validator\RulesProviderInterface;
16
use Yiisoft\Validator\ValidatorInterface;
17
18
final class RequestModelFactory
19
{
20
    private Injector $injector;
21
    private ValidatorInterface $validator;
22
    private CurrentRouteInterface $currentRoute;
23
24 16
    public function __construct(ValidatorInterface $validator, Injector $injector, CurrentRouteInterface $currentRoute)
25
    {
26 16
        $this->validator = $validator;
27 16
        $this->injector = $injector;
28 16
        $this->currentRoute = $currentRoute;
29 16
    }
30
31
    /**
32
     * @param ServerRequestInterface $request
33
     * @param array|ReflectionParameter[] $handlerParameters
34
     *
35
     * @throws ReflectionException
36
     *
37
     * @return array
38
     */
39 10
    public function createInstances(ServerRequestInterface $request, array $handlerParameters): array
40
    {
41 10
        $requestModelInstances = [];
42 10
        foreach ($this->getModelRequestClasses($handlerParameters) as $modelClass) {
43
            /** @var RequestModelInterface $modelInstance */
44 9
            $modelInstance = $this->injector->make($modelClass);
45 9
            $requestModelInstances[] = $this->processModel($request, $modelInstance);
46
        }
47
48 9
        return $requestModelInstances;
49
    }
50
51 9
    private function processModel(ServerRequestInterface $request, RequestModelInterface $model): RequestModelInterface
52
    {
53 9
        $requestData = $this->getRequestData($request);
54 9
        $model->setRequestData($requestData);
55 9
        if ($model instanceof RulesProviderInterface) {
56 2
            $result = $this->validator->validate($model, $model->getRules());
57 2
            if (!$result->isValid()) {
58 1
                throw new RequestValidationException($result->getErrors());
59
            }
60
        }
61
62 8
        return $model;
63
    }
64
65
    /**
66
     * @param array|ReflectionParameter[] $handlerParameters
67
     *
68
     * @return array
69
     */
70 10
    private function getModelRequestClasses(array $handlerParameters): array
71
    {
72 10
        $modelClasses = [];
73 10
        foreach ($handlerParameters as $parameter) {
74 10
            if ($this->paramsIsRequestModel($parameter, $parameterType)) {
75 9
                $modelClasses[] = $parameterType->getName();
76
            }
77
        }
78
79 10
        return $modelClasses;
80
    }
81
82
    /**
83
     * @param ReflectionParameter $parameter
84
     * @param mixed $parameterType
85
     *
86
     * @throws ReflectionException
87
     *
88
     * @return bool
89
     */
90 10
    private function paramsIsRequestModel(ReflectionParameter $parameter, &$parameterType): bool
91
    {
92 10
        if (!$parameter->hasType()) {
93
            return false;
94
        }
95
        /** @var ReflectionNamedType|ReflectionUnionType $reflectionType */
96 10
        $reflectionType = $parameter->getType();
97
98 10
        $types = $reflectionType instanceof ReflectionNamedType ? [$reflectionType] : $reflectionType->getTypes();
99
100
        /** @var ReflectionNamedType $type */
101 10
        foreach ($types as $type) {
102 10
            if (!$type->isBuiltin() && (new ReflectionClass($type->getName()))->implementsInterface(RequestModelInterface::class)) {
103 9
                $parameterType = $type;
104 9
                return true;
105
            }
106
        }
107 1
        return false;
108
    }
109
110 9
    private function getRequestData(ServerRequestInterface $request): array
111
    {
112
        return [
113 9
            'query' => $request->getQueryParams(),
114 9
            'body' => $request->getParsedBody(),
115 9
            'attributes' => $request->getAttributes(),
116 9
            'headers' => $request->getHeaders(),
117 9
            'files' => $request->getUploadedFiles(),
118 9
            'cookie' => $request->getCookieParams(),
119 9
            'router' => $this->currentRoute->getArguments(),
120
        ];
121
    }
122
}
123