Passed
Pull Request — main (#24)
by
unknown
13:18
created

Factory::buildPathSegments()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 6
c 1
b 0
f 0
dl 0
loc 10
ccs 0
cts 0
cp 0
rs 10
cc 2
nc 2
nop 3
crap 6
1
<?php
2
3
namespace CHStudio\Raven\Bridge\LeagueOpenAPIValidation;
4
5
use CHStudio\Raven\Bridge\LeagueOpenAPIValidation\Exception\InvalidOpenApiDefinitionException;
6
use CHStudio\Raven\Bridge\LeagueOpenAPIValidation\Exception\ValidationExceptionMapper;
7
use InvalidArgumentException;
8
use League\OpenAPIValidation\PSR7\ValidatorBuilder;
9
use Throwable;
10
11
class Factory
12
{
13
    private readonly ValidationExceptionMapper $mapper;
14
15 5
    public function __construct(
16
        private readonly ValidatorBuilder $validator,
17
        ValidationExceptionMapper $mapper = null
18
    ) {
19 5
        $this->mapper = $mapper ?? new ValidationExceptionMapper();
0 ignored issues
show
Bug introduced by
The property mapper is declared read-only in CHStudio\Raven\Bridge\Le...enAPIValidation\Factory.
Loading history...
20
    }
21
22 2
    public static function fromYamlFile(string $path): self
23
    {
24 2
        if (!is_readable($path)) {
25 1
            throw new InvalidArgumentException(
26 1
                sprintf('Filename given isn\'t readable: %s', $path)
27 1
            );
28
        }
29
30 1
        return new self(
31 1
            (new ValidatorBuilder())->fromYamlFile($path)
32 1
        );
33
    }
34
35 2
    public static function fromJsonFile(string $path): self
36
    {
37 2
        if (!is_readable($path)) {
38 1
            throw new InvalidArgumentException(
39 1
                sprintf('Filename given isn\'t readable: %s', $path)
40 1
            );
41
        }
42
43 1
        return new self(
44 1
            (new ValidatorBuilder())->fromJsonFile($path)
45 1
        );
46
    }
47
48 4
    public function getRequestValidator(): RequestValidator
49
    {
50
        try {
51 4
            return new RequestValidator($this->validator->getRequestValidator(), $this->mapper);
52 1
        } catch (Throwable $error) {
53 1
            throw new InvalidOpenApiDefinitionException($error);
54
        }
55
    }
56
57 4
    public function getResponseValidator(): ResponseValidator
58
    {
59
        try {
60 4
            return new ResponseValidator($this->validator->getResponseValidator(), $this->mapper);
61 1
        } catch (Throwable $error) {
62 1
            throw new InvalidOpenApiDefinitionException($error);
63
        }
64
    }
65
    
66
    /**
67
     * OpenApi doc is internally transposed by Raven to a tree of infos.
68
     * This method gives the opportinity to retreive a subtree, based on the "path" in the api doc
69
     *  that is represented by the tupple: http method / uri / status code / content type
70
     * One usage can be to further process the resulting array
71
     *  in order to check an api json response object's structure conformity
72
     */
73
    public function getReferenceStructure(string $method, string $uri, int $statusCode, ?string $contentType): ?array
74
    {
75
        $decoded = json_decode(json_encode(
76
            $this->validator->getResponseValidator()->getSchema()->getSerializableData()
77
        ), true);
78
        // Looking for paths with care of parameters not necessarily named the same in both yaml files (test def & openApi)
79
        $workedUri = $this->cleanPath($uri);
80
        foreach ($decoded['paths'] as $path => $data) {
81
            if ($path === $uri || $this->cleanPath($path) === $workedUri) {
82
                // Path to access data in multiple levels nested object
83
                $pathSegments = $this->buildPathSegments($method, $statusCode, $contentType);
84
                $roadTraveled = '';
85
                foreach ($pathSegments as $segment) {
86
                    $roadTraveled .= '/'.$segment;
87
                    if (!isset($data[$segment])) {
88
                        throw new InvalidArgumentException(sprintf(
89
                            'The following path was not found in object definition from openApi: %s',
90
                            $roadTraveled
91
                        ));
92
                    }
93
                    $data = $data[$segment];
94
                }
95
96
                return $data;
97
            }
98
        }
99
100
        return null;
101
    }
102
103
    private function cleanPath(string $path): string
104
    {
105
        // Replace parameter by a star and remove query string
106
        return preg_replace(['/\{[^\}]+\}/', '/\?.+/'], ['*', ''], $path);
107
    }
108
109
    private function buildPathSegments(string $method, int $statusCode, ?string $contentType): array
110
    {
111
        $return = [strtolower($method), 'responses', $statusCode, 'content'];
112
        if ($contentType !== null) {
113
            $return[] = strtolower($contentType);
114
        }
115
        $return[] = 'schema';
116
        $return[] = 'properties';
117
118
        return $return;
119
    }
120
}
121