Passed
Push — master ( 9b5861...5bdc47 )
by Joao
06:11 queued 16s
created

SwaggerSchema::getSpecificationVersion()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace ByJG\Swagger;
4
5
use ByJG\Swagger\Exception\DefinitionNotFoundException;
6
use ByJG\Swagger\Exception\HttpMethodNotFoundException;
7
use ByJG\Swagger\Exception\InvalidDefinitionException;
8
use ByJG\Swagger\Exception\NotMatchedException;
9
use ByJG\Swagger\Exception\PathNotFoundException;
10
use ByJG\Util\Uri;
11
12
class SwaggerSchema
13
{
14
    protected $jsonFile;
15
    protected $allowNullValues;
16
    protected $specificationVersion;
17
18
    const SWAGGER_PATHS="paths";
19
    const SWAGGER_PARAMETERS="parameters";
20
    const SWAGGER_COMPONENTS="components";
21
22
    public function __construct($jsonFile, $allowNullValues = false)
23
    {
24
        $this->jsonFile = json_decode($jsonFile, true);
25
        $this->allowNullValues = (bool) $allowNullValues;
26
        $this->specificationVersion = isset($this->jsonFile['swagger']) ? '2' : '3';
27
    }
28
29
    /**
30
     * Returns the major specification version
31
     * @return string
32
     */
33
    public function getSpecificationVersion()
34
    {
35
        return $this->specificationVersion;
36
    }
37
38
    public function getServerUrl()
39
    {
40
        return isset($this->jsonFile['servers']) ? $this->jsonFile['servers'][0]['url'] : '';
41
    }
42
43
    public function getHttpSchema()
44
    {
45
        return isset($this->jsonFile['schemes']) ? $this->jsonFile['schemes'][0] : '';
46
    }
47
48
    public function getHost()
49
    {
50
        return isset($this->jsonFile['host']) ? $this->jsonFile['host'] : '';
51
    }
52
53
    public function getBasePath()
54
    {
55
        if ($this->getSpecificationVersion() === '3') {
56
            $basePath =isset($this->jsonFile['servers']) ? explode('/', $this->jsonFile['servers'][0]['url']) : '';
57
            return is_array($basePath) ? '/' . end($basePath) : $basePath;
58
        }
59
60
        return isset($this->jsonFile['basePath']) ? $this->jsonFile['basePath'] : '';
61
    }
62
63
    /**
64
     * @param $path
65
     * @param $method
66
     * @return mixed
67
     * @throws DefinitionNotFoundException
68
     * @throws HttpMethodNotFoundException
69
     * @throws InvalidDefinitionException
70
     * @throws NotMatchedException
71
     * @throws PathNotFoundException
72
     */
73
    public function getPathDefinition($path, $method)
74
    {
75
        $method = strtolower($method);
76
77
        $path = preg_replace('~^' . $this->getBasePath() . '~', '', $path);
78
79
        $uri = new Uri($path);
80
81
        // Try direct match
82
        if (isset($this->jsonFile[self::SWAGGER_PATHS][$uri->getPath()])) {
83
            if (isset($this->jsonFile[self::SWAGGER_PATHS][$uri->getPath()][$method])) {
84
                return $this->jsonFile[self::SWAGGER_PATHS][$uri->getPath()][$method];
85
            }
86
            throw new HttpMethodNotFoundException("The http method '$method' not found in '$path'");
87
        }
88
89
        // Try inline parameter
90
        foreach (array_keys($this->jsonFile[self::SWAGGER_PATHS]) as $pathItem) {
91
            if (strpos($pathItem, '{') === false) {
92
                continue;
93
            }
94
95
            $pathItemPattern = '~^' . preg_replace('~{(.*?)}~', '(?<\1>[^/]+)', $pathItem) . '$~';
96
97
            $matches = [];
98
            if (preg_match($pathItemPattern, $uri->getPath(), $matches)) {
99
                $pathDef = $this->jsonFile[self::SWAGGER_PATHS][$pathItem];
100
                if (!isset($pathDef[$method])) {
101
                    throw new HttpMethodNotFoundException("The http method '$method' not found in '$path'");
102
                }
103
104
                $parametersPathMethod = [];
105
                $parametersPath = [];
106
107
                if (isset($pathDef[$method][self::SWAGGER_PARAMETERS])) {
108
                    $parametersPathMethod = $pathDef[$method][self::SWAGGER_PARAMETERS];
109
                }
110
111
                if (isset($pathDef[self::SWAGGER_PARAMETERS])) {
112
                    $parametersPath = $pathDef[self::SWAGGER_PARAMETERS];
113
                }
114
115
                $this->validateArguments('path', array_merge($parametersPathMethod, $parametersPath), $matches);
116
117
                return $pathDef[$method];
118
            }
119
        }
120
121
        throw new PathNotFoundException('Path "' . $path . '" not found');
122
    }
123
124
    /**
125
     * @param $parameterIn
126
     * @param $parameters
127
     * @param $arguments
128
     * @throws DefinitionNotFoundException
129
     * @throws InvalidDefinitionException
130
     * @throws NotMatchedException
131
     */
132
    private function validateArguments($parameterIn, $parameters, $arguments)
133
    {
134
        if ($this->getSpecificationVersion() === '3') {
135
            foreach ($parameters as $parameter) {
136
                if (isset($parameter['$ref'])) {
137
                    $paramParts = explode("/", $parameter['$ref']);
138
                    if (count($paramParts) != 4 || $paramParts[0] != "#" || $paramParts[1] != self::SWAGGER_COMPONENTS || $paramParts[2] != self::SWAGGER_PARAMETERS) {
139
                        throw new InvalidDefinitionException(
140
                            "Not get the reference in the expected format #/components/parameters/<NAME>"
141
                        );
142
                    }
143
                    if (!isset($this->jsonFile[self::SWAGGER_COMPONENTS][self::SWAGGER_PARAMETERS][$paramParts[3]])) {
144
                        throw new DefinitionNotFoundException(
145
                            "Not find reference #/components/parameters/${paramParts[3]}"
146
                        );
147
                    }
148
                    $parameter = $this->jsonFile[self::SWAGGER_COMPONENTS][self::SWAGGER_PARAMETERS][$paramParts[3]];
149
                }
150 View Code Duplication
                if ($parameter['in'] === $parameterIn &&
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
151
                    $parameter['schema']['type'] === "integer"
152
                    && filter_var($arguments[$parameter['name']], FILTER_VALIDATE_INT) === false) {
153
                    throw new NotMatchedException('Path expected an integer value');
154
                }
155
            }
156
            return;
157
        }
158
159
        foreach ($parameters as $parameter) {
160 View Code Duplication
            if ($parameter['in'] === $parameterIn
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
161
                && $parameter['type'] === "integer"
162
                && filter_var($arguments[$parameter['name']], FILTER_VALIDATE_INT) === false) {
163
                throw new NotMatchedException('Path expected an integer value');
164
            }
165
        }
166
    }
167
168
    /**
169
     * @param $name
170
     * @return mixed
171
     * @throws DefinitionNotFoundException
172
     * @throws InvalidDefinitionException
173
     */
174
    public function getDefintion($name)
175
    {
176
        $nameParts = explode('/', $name);
177
178
        if ($this->getSpecificationVersion() === '3') {
179 View Code Duplication
            if (count($nameParts) < 4 || $nameParts[0] !== '#') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
180
                throw new InvalidDefinitionException('Invalid Component');
181
            }
182
183 View Code Duplication
            if (!isset($this->jsonFile[$nameParts[1]][$nameParts[2]][$nameParts[3]])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
184
                throw new DefinitionNotFoundException("Component'$name' not found");
185
            }
186
187
            return $this->jsonFile[$nameParts[1]][$nameParts[2]][$nameParts[3]];
188
        }
189
190 View Code Duplication
        if (count($nameParts) < 3 || $nameParts[0] !== '#') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
191
            throw new InvalidDefinitionException('Invalid Definition');
192
        }
193
194 View Code Duplication
        if (!isset($this->jsonFile[$nameParts[1]][$nameParts[2]])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
195
            throw new DefinitionNotFoundException("Definition '$name' not found");
196
        }
197
198
        return $this->jsonFile[$nameParts[1]][$nameParts[2]];
199
    }
200
201
    /**
202
     * @param $path
203
     * @param $method
204
     * @return SwaggerRequestBody
205
     * @throws DefinitionNotFoundException
206
     * @throws HttpMethodNotFoundException
207
     * @throws InvalidDefinitionException
208
     * @throws NotMatchedException
209
     * @throws PathNotFoundException
210
     */
211
    public function getRequestParameters($path, $method)
212
    {
213
        $structure = $this->getPathDefinition($path, $method);
214
215
        if($this->getSpecificationVersion() === '3') {
216
            if (!isset($structure['requestBody'])) {
217
                return new SwaggerRequestBody($this, "$method $path", []);
218
            }
219
            return new SwaggerRequestBody($this, "$method $path", $structure['requestBody']);
220
        }
221
222
        if (!isset($structure[self::SWAGGER_PARAMETERS])) {
223
            return new SwaggerRequestBody($this, "$method $path", []);
224
        }
225
        return new SwaggerRequestBody($this, "$method $path", $structure[self::SWAGGER_PARAMETERS]);
226
    }
227
228
    /**
229
     * @param $path
230
     * @param $method
231
     * @param $status
232
     * @return SwaggerResponseBody
233
     * @throws HttpMethodNotFoundException
234
     * @throws InvalidDefinitionException
235
     * @throws NotMatchedException
236
     * @throws PathNotFoundException
237
     * @throws DefinitionNotFoundException
238
     */
239
    public function getResponseParameters($path, $method, $status)
240
    {
241
        $structure = $this->getPathDefinition($path, $method);
242
243
        if (!isset($structure['responses'][$status])) {
244
            throw new InvalidDefinitionException("Could not found status code '$status' in '$path' and '$method'");
245
        }
246
247
        return new SwaggerResponseBody($this, "$method $status $path", $structure['responses'][$status]);
248
    }
249
250
    /**
251
     * OpenApi 2.0 doesn't describe null values, so this flag defines,
252
     * if match is ok when one of property
253
     *
254
     * @return bool
255
     */
256
    public function isAllowNullValues()
257
    {
258
        return $this->allowNullValues;
259
    }
260
261
    /**
262
     * OpenApi 2.0 doesn't describe null values, so this flag defines,
263
     * if match is ok when one of property
264
     *
265
     * @param $value
266
     */
267
    public function setAllowNullValues($value)
268
    {
269
        $this->allowNullValues = (bool) $value;
270
    }
271
}
272