Passed
Push — main ( f92c16...da47e6 )
by Stéphane
09:15 queued 06:41
created

ResponseValidator::findOperation()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 4

Importance

Changes 0
Metric Value
eloc 11
c 0
b 0
f 0
dl 0
loc 22
ccs 13
cts 13
cp 1
rs 9.9
cc 4
nc 4
nop 1
crap 4
1
<?php
2
3
namespace CHStudio\Raven\Bridge\LeagueOpenAPIValidation;
4
5
use CHStudio\Raven\Bridge\LeagueOpenAPIValidation\Exception\ValidationExceptionMapper;
6
use CHStudio\Raven\Validator\Exception\OperationNotFoundException;
7
use CHStudio\Raven\Validator\Exception\ResponseNotExpectedException;
8
use CHStudio\Raven\Validator\ResponseValidatorInterface;
9
use League\OpenAPIValidation\PSR7\Exception\NoResponseCode;
10
use League\OpenAPIValidation\PSR7\OperationAddress;
11
use League\OpenAPIValidation\PSR7\PathFinder;
12
use League\OpenAPIValidation\PSR7\ResponseValidator as LeagueResponseValidator;
13
use Psr\Http\Message\RequestInterface;
14
use Psr\Http\Message\ResponseInterface;
15
16
class ResponseValidator implements ResponseValidatorInterface
17
{
18 11
    public function __construct(
19
        private readonly LeagueResponseValidator $adapted,
20
        private readonly ValidationExceptionMapper $mapper
21
    ) {
22 11
    }
23
24 7
    public function validate(ResponseInterface $input, RequestInterface $request): void
25
    {
26
        try {
27 7
            $this->adapted->validate(
28 7
                $this->findOperation($request),
29 7
                $input
30 7
            );
31 5
        } catch (NoResponseCode $e) {
32 1
            throw new ResponseNotExpectedException($request, $input, $e);
33 4
        } catch (\Throwable $e) {
34
            // Capture league/openapi-psr7-validator SpecFinder errors
35
            // it reads properties that might not exists.
36 4
            if (str_contains($e->getFile(), 'SpecFinder.php')) {
37 1
                throw new ResponseNotExpectedException($request, $input, $e);
38
            }
39
40 3
            $error = $this->mapper->map($e);
41 3
            if ($error !== null) {
42 1
                throw $error;
43
            }
44 2
            throw $e;
45
        }
46
    }
47
48
    /**
49
     * Find the best OperationAdress to use to validate the current response
50
     */
51 7
    private function findOperation(RequestInterface $request): OperationAddress
52
    {
53 7
        $pathFinder = new PathFinder(
54 7
            $this->adapted->getSchema(),
55 7
            $request->getUri(),
56 7
            $request->getMethod()
57 7
        );
58
59 7
        $operations = $pathFinder->search();
60 7
        if (\count($operations) === 0) {
61 1
            throw new OperationNotFoundException($request);
62
        }
63
64 6
        foreach ($operations as $operation) {
65
            //If we got an exact path match, we use the current Operation
66 6
            if ($operation->path() === $request->getUri()->getPath()) {
67 1
                return $operation;
68
            }
69
        }
70
71
        //If we haven't an exact match, use the first in the list
72 5
        return $operations[0];
73
    }
74
}
75