Passed
Pull Request — master (#33)
by Melech
03:28
created

MessageCapableRouter   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 154
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 34
c 1
b 0
f 0
dl 0
loc 154
rs 10
wmc 15

10 Methods

Rating   Name   Duplication   Size   Complexity  
A ensureIsMessage() 0 3 1
A abortDueToExtraData() 0 3 1
A ensureRequestConformsToMessage() 0 4 1
A determineIsMessage() 0 3 1
A getValidatorRules() 0 12 2
A ensureRequestHasNoExtraData() 0 6 2
A abortDueToValidationErrors() 0 3 1
A ensureRequestIsValid() 0 11 3
A getRouteFromRequest() 0 10 2
A __construct() 0 20 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Valkyrja Framework package.
7
 *
8
 * (c) Melech Mizrachi <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Valkyrja\Routing\Dispatchers;
15
16
use Valkyrja\Container\Container;
17
use Valkyrja\Dispatcher\Dispatcher;
18
use Valkyrja\Event\Events;
19
use Valkyrja\Http\Request;
20
use Valkyrja\Http\ResponseFactory;
21
use Valkyrja\Routing\Collection;
22
use Valkyrja\Routing\Config\Config;
23
use Valkyrja\Routing\Matcher;
24
use Valkyrja\Routing\Message;
25
use Valkyrja\Routing\Route;
26
use Valkyrja\Routing\Support\Abort;
27
use Valkyrja\Validation\Validator;
28
29
use function assert;
30
31
/**
32
 * Class MessageCapableRouter.
33
 *
34
 * @author Melech Mizrachi
35
 */
36
class MessageCapableRouter extends Router
37
{
38
    /**
39
     * MessageCapableRouter constructor.
40
     */
41
    public function __construct(
42
        protected Validator $validator,
43
        Collection $collection,
44
        Container $container,
45
        Dispatcher $dispatcher,
46
        Events $events,
47
        Matcher $matcher,
48
        ResponseFactory $responseFactory,
49
        Config|array $config,
50
        bool $debug = false
51
    ) {
52
        parent::__construct(
53
            collection     : $collection,
54
            container      : $container,
55
            dispatcher     : $dispatcher,
56
            events         : $events,
57
            matcher        : $matcher,
58
            responseFactory: $responseFactory,
59
            config         : $config,
60
            debug          : $debug
61
        );
62
    }
63
64
    /**
65
     * @inheritDoc
66
     */
67
    public function getRouteFromRequest(Request $request): Route
68
    {
69
        $route = parent::getRouteFromRequest($request);
70
71
        foreach ($route->getMessages() ?? [] as $message) {
72
            $this->ensureIsMessage($message);
73
            $this->ensureRequestConformsToMessage($request, $message);
74
        }
75
76
        return $route;
77
    }
78
79
    /**
80
     * Ensure a message is a message.
81
     *
82
     * @param string $message The message
83
     *
84
     * @return void
85
     */
86
    protected function ensureIsMessage(string $message): void
87
    {
88
        assert($this->determineIsMessage($message));
89
    }
90
91
    /**
92
     * Determine if a dependency is a message.
93
     *
94
     * @param string $message The message
95
     *
96
     * @return bool
97
     */
98
    protected function determineIsMessage(string $message): bool
99
    {
100
        return is_a($message, Message::class, true);
101
    }
102
103
    /**
104
     * @param Request               $request The request
105
     * @param class-string<Message> $message The message class name
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<Message> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<Message>.
Loading history...
106
     *
107
     * @return void
108
     */
109
    protected function ensureRequestConformsToMessage(Request $request, string $message): void
110
    {
111
        $this->ensureRequestHasNoExtraData($request, $message);
112
        $this->ensureRequestIsValid($request, $message);
113
    }
114
115
    /**
116
     * @param Request               $request The request
117
     * @param class-string<Message> $message The message class name
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<Message> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<Message>.
Loading history...
118
     *
119
     * @return void
120
     */
121
    protected function ensureRequestHasNoExtraData(Request $request, string $message): void
122
    {
123
        // If there is extra data
124
        if ($message::determineIfRequestContainsExtraData($request)) {
125
            // Then the payload is too large
126
            $this->abortDueToExtraData($request, $message);
127
        }
128
    }
129
130
    /**
131
     * @param Request               $request The request
132
     * @param class-string<Message> $message The message class name
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<Message> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<Message>.
Loading history...
133
     *
134
     * @return void
135
     */
136
    protected function abortDueToExtraData(Request $request, string $message): void
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

136
    protected function abortDueToExtraData(/** @scrutinizer ignore-unused */ Request $request, string $message): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $message is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

136
    protected function abortDueToExtraData(Request $request, /** @scrutinizer ignore-unused */ string $message): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
137
    {
138
        Abort::abort413();
139
    }
140
141
    /**
142
     * @param Request               $request The request
143
     * @param class-string<Message> $message The message class name
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<Message> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<Message>.
Loading history...
144
     *
145
     * @return void
146
     */
147
    protected function ensureRequestIsValid(Request $request, string $message): void
148
    {
149
        if (($messageRules = $message::getValidationRules()) === null) {
150
            return;
151
        }
152
153
        $validator = $this->validator;
154
        $validator->setRules($this->getValidatorRules($message::getDataFromRequest($request), $messageRules));
155
156
        if (! $validator->validate()) {
157
            $this->abortDueToValidationErrors($request, $message);
158
        }
159
    }
160
161
    /**
162
     * @param Request               $request The request
163
     * @param class-string<Message> $message The message class name
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<Message> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<Message>.
Loading history...
164
     *
165
     * @return void
166
     */
167
    protected function abortDueToValidationErrors(Request $request, string $message): void
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

167
    protected function abortDueToValidationErrors(/** @scrutinizer ignore-unused */ Request $request, string $message): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $message is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

167
    protected function abortDueToValidationErrors(Request $request, /** @scrutinizer ignore-unused */ string $message): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
168
    {
169
        Abort::abort400();
170
    }
171
172
    /**
173
     * @param array                                                                        $data         The data
174
     * @param array<string, array<string, array{arguments: array, errorMessage?: string}>> $messageRules The message rules
175
     *
176
     * @return array
177
     */
178
    protected function getValidatorRules(array $data, array $messageRules): array
179
    {
180
        $rules = [];
181
182
        foreach ($messageRules as $param => $paramRule) {
183
            $rules[$param] = [
184
                'subject' => $data[$param],
185
                'rules'   => $paramRule,
186
            ];
187
        }
188
189
        return $rules;
190
    }
191
}
192