Passed
Push — master ( 0010b4...ff0e1a )
by Mr
02:16
created

ValidationService::silent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 3
dl 0
loc 3
ccs 0
cts 3
cp 0
crap 2
rs 10
c 1
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace Daikon\Boot\Middleware;
4
5
use Daikon\Boot\Middleware\ActionHandler;
6
use Daikon\Boot\Middleware\ResolvesDependency;
7
use Daikon\Interop\AssertionFailedException;
8
use Daikon\Interop\LazyAssertionException;
9
use Daikon\Interop\RuntimeException;
10
use Daikon\Validize\Validation\ValidationIncident;
11
use Daikon\Validize\Validation\ValidationReport;
0 ignored issues
show
Bug introduced by
The type Daikon\Validize\Validation\ValidationReport was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
use Daikon\Validize\Validation\ValidatorDefinition;
13
use Daikon\Validize\Validator\ValidatorInterface;
14
use Daikon\Validize\ValueObject\Severity;
15
use DomainException;
16
use Fig\Http\Message\StatusCodeInterface;
17
use Psr\Container\ContainerInterface;
18
use Psr\Http\Message\ServerRequestInterface;
19
20
final class ValidationService implements ValidatorInterface, StatusCodeInterface
21
{
22
    use ResolvesDependency;
23
24
    public const ATTR_VALIDATION_REPORT = '_validation_report';
25
26
    private ContainerInterface $container;
27
28
    /** @var ValidatorDefinition[] */
29
    private array $definitions = [];
30
31
    public function __construct(ContainerInterface $container)
32
    {
33
        $this->container = $container;
34
    }
35
36
    public function critical(string $argument, string $validator, array $settings = []): self
37
    {
38
        return $this->register(Severity::critical(), $argument, $validator, $settings);
39
    }
40
41
    public function error(string $argument, string $validator, array $settings = []): self
42
    {
43
        return $this->register(Severity::error(), $argument, $validator, $settings);
44
    }
45
46
    public function notice(string $argument, string $validator, array $settings = []): self
47
    {
48
        return $this->register(Severity::notice(), $argument, $validator, $settings);
49
    }
50
51
    public function silent(string $argument, string $validator, array $settings = []): self
52
    {
53
        return $this->register(Severity::silent(), $argument, $validator, $settings);
54
    }
55
56
    private function register(Severity $severity, string $argument, string $validator, array $settings): self
57
    {
58
        $definition = new ValidatorDefinition($argument, $validator, $severity, $settings);
59
        $this->definitions[] = $definition;
60
        return $this;
61
    }
62
63
    public function __invoke(ServerRequestInterface $request): ServerRequestInterface
64
    {
65
        if (!empty($request->getAttribute(ActionHandler::ATTR_PAYLOAD))) {
66
            throw new RuntimeException('Action payload already exists.');
67
        }
68
69
        $request = $this->validate($request);
70
71
        /** @var ValidationReport $report */
72
        if ($report = $request->getAttribute(self::ATTR_VALIDATION_REPORT)) {
73
            $errorReport = $report->getErrors();
74
            if (!$errorReport->isEmpty()) {
75
                $request = $request->withAttribute(ActionHandler::ATTR_ERRORS, $errorReport->getMessages());
76
                if ($statusCode = $errorReport->getStatusCode()) {
77
                    $request = $request->withAttribute(ActionHandler::ATTR_STATUS_CODE, $statusCode);
78
                }
79
            }
80
        }
81
82
        return $request;
83
    }
84
85
    public function validate(ServerRequestInterface $request): ServerRequestInterface
86
    {
87
        $report = new ValidationReport;
88
        foreach ($this->definitions as $definition) {
89
            $settings = $definition->getSettings();
90
            $severity = $definition->getSeverity();
91
            $validator = $this->getValidator($this->container, $definition);
92
            try {
93
                if (array_key_exists('depends', $settings)) {
94
                    foreach ((array)$settings['depends'] as $dependent) {
95
                        if (!$report->isProvided($dependent)) {
96
                            throw new DomainException("Dependent validator '$dependent' not provided.");
97
                        }
98
                    }
99
                }
100
                $result = $validator($request);
101
                $request = ($settings['export'] ?? true) ? $result : $request;
102
                $report = $report->push(new ValidationIncident($definition, Severity::success()));
103
            } catch (DomainException $error) {
104
                $incident = new ValidationIncident($definition, Severity::unexecuted());
105
                $report = $report->push($incident->addMessage($error->getMessage()));
106
            } catch (AssertionFailedException $error) {
107
                if ($severity->isGreaterThanOrEqual(Severity::notice())) {
108
                    $incident = new ValidationIncident($definition, $severity);
109
                    switch (true) {
110
                        case $error instanceof LazyAssertionException:
111
                            /** @var LazyAssertionException $error */
112
                            foreach ($error->getErrorExceptions() as $exception) {
113
                                $incident = $incident->addMessage($exception->getMessage());
114
                            }
115
                            break;
116
                        default:
117
                            $incident = $incident->addMessage($error->getMessage());
118
                            break;
119
                    }
120
                    $report = $report->push($incident);
121
                }
122
                if ($severity->equals(Severity::critical())) {
123
                    break;
124
                }
125
            }
126
        }
127
128
        return $request->withAttribute(self::ATTR_VALIDATION_REPORT, $report);
129
    }
130
131
    private function getValidator(ContainerInterface $container, ValidatorDefinition $definition): ValidatorInterface
132
    {
133
        $dependency = [$definition->getImplementor(), [':definition' => $definition]];
134
        /** @var ValidatorInterface $validator */
135
        $validator = $this->resolve($container, $dependency, ValidatorInterface::class);
136
        return $validator;
137
    }
138
}
139