Passed
Pull Request — master (#33)
by Joao
01:51
created

Schema::getPathDefinition()   B

Complexity

Conditions 9
Paths 10

Size

Total Lines 50

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 50
rs 7.5353
c 0
b 0
f 0
cc 9
nc 10
nop 2
1
<?php
2
3
namespace ByJG\ApiTools\Base;
4
5
use ByJG\ApiTools\Exception\DefinitionNotFoundException;
6
use ByJG\ApiTools\Exception\HttpMethodNotFoundException;
7
use ByJG\ApiTools\Exception\InvalidDefinitionException;
8
use ByJG\ApiTools\Exception\NotMatchedException;
9
use ByJG\ApiTools\Exception\PathNotFoundException;
10
use ByJG\ApiTools\OpenApi\OpenApiResponseBody;
11
use ByJG\ApiTools\OpenApi\OpenApiSchema;
12
use ByJG\ApiTools\Swagger\SwaggerResponseBody;
13
use ByJG\ApiTools\Swagger\SwaggerSchema;
14
use ByJG\Util\Uri;
15
use InvalidArgumentException;
16
17
abstract class Schema
18
{
19
    protected $jsonFile;
20
    protected $allowNullValues = false;
21
    protected $specificationVersion;
22
23
    const SWAGGER_PATHS = "paths";
24
    const SWAGGER_PARAMETERS = "parameters";
25
    const SWAGGER_COMPONENTS = "components";
26
27
    /**
28
     * Returns the major specification version
29
     * @return string
30
     */
31
    public function getSpecificationVersion()
32
    {
33
        return $this->specificationVersion;
34
    }
35
36
    /**
37
     * Factory function for schemata.
38
     *
39
     * Initialize with schema data, which can be a PHP array or encoded as JSON.
40
     * This determines the type of the schema from the given data.
41
     *
42
     * @param array|string $data
43
     * @param bool $extraArgs
44
     * @return Schema
45
     */
46
    public static function getInstance($data, $extraArgs = false)
47
    {
48
        // when given a string, decode from JSON
49
        if (is_string($data)) {
50
            $data = json_decode($data, true);
51
        }
52
        // make sure we got an array
53
        if (!is_array($data)) {
54
            throw new InvalidArgumentException('schema must be given as array or JSON string');
55
        }
56
        // check which type of file we got and dispatch to derived class constructor
57
        if (isset($data['swagger'])) {
58
            return new SwaggerSchema($data, $extraArgs);
59
        }
60
        if (isset($data['openapi'])) {
61
            return new OpenApiSchema($data);
62
        }
63
64
        throw new InvalidArgumentException('failed to determine schema type from data');
65
    }
66
67
    /**
68
     * @param $path
69
     * @param $method
70
     * @return mixed
71
     * @throws DefinitionNotFoundException
72
     * @throws HttpMethodNotFoundException
73
     * @throws InvalidDefinitionException
74
     * @throws NotMatchedException
75
     * @throws PathNotFoundException
76
     */
77
    public function getPathDefinition($path, $method)
78
    {
79
        $method = strtolower($method);
80
81
        $path = preg_replace('~^' . $this->getBasePath() . '~', '', $path);
82
83
        $uri = new Uri($path);
84
85
        // Try direct match
86
        if (isset($this->jsonFile[self::SWAGGER_PATHS][$uri->getPath()])) {
87
            if (isset($this->jsonFile[self::SWAGGER_PATHS][$uri->getPath()][$method])) {
88
                return $this->jsonFile[self::SWAGGER_PATHS][$uri->getPath()][$method];
89
            }
90
            throw new HttpMethodNotFoundException("The http method '$method' not found in '$path'");
91
        }
92
93
        // Try inline parameter
94
        foreach (array_keys($this->jsonFile[self::SWAGGER_PATHS]) as $pathItem) {
95
            if (strpos($pathItem, '{') === false) {
96
                continue;
97
            }
98
99
            $pathItemPattern = '~^' . preg_replace('~{(.*?)}~', '(?<\1>[^/]+)', $pathItem) . '$~';
100
101
            $matches = [];
102
            if (preg_match($pathItemPattern, $uri->getPath(), $matches)) {
103
                $pathDef = $this->jsonFile[self::SWAGGER_PATHS][$pathItem];
104
                if (!isset($pathDef[$method])) {
105
                    throw new HttpMethodNotFoundException("The http method '$method' not found in '$path'");
106
                }
107
108
                $parametersPathMethod = [];
109
                $parametersPath = [];
110
111
                if (isset($pathDef[$method][self::SWAGGER_PARAMETERS])) {
112
                    $parametersPathMethod = $pathDef[$method][self::SWAGGER_PARAMETERS];
113
                }
114
115
                if (isset($pathDef[self::SWAGGER_PARAMETERS])) {
116
                    $parametersPath = $pathDef[self::SWAGGER_PARAMETERS];
117
                }
118
119
                $this->validateArguments('path', array_merge($parametersPathMethod, $parametersPath), $matches);
120
121
                return $pathDef[$method];
122
            }
123
        }
124
125
        throw new PathNotFoundException('Path "' . $path . '" not found');
126
    }
127
128
    /**
129
     * @param $path
130
     * @param $method
131
     * @param $status
132
     * @return Body
133
     * @throws DefinitionNotFoundException
134
     * @throws HttpMethodNotFoundException
135
     * @throws InvalidDefinitionException
136
     * @throws NotMatchedException
137
     * @throws PathNotFoundException
138
     */
139
    public function getResponseParameters($path, $method, $status)
140
    {
141
        $structure = $this->getPathDefinition($path, $method);
142
143
        if (!isset($structure['responses'][$status])) {
144
            if ($status != "200") {
145
                throw new InvalidDefinitionException("Could not found status code '$status' in '$path' and '$method'");
146
            }
147
            $structure['responses'][$status] = ["description" => "Auto Generated OK"];
148
        }
149
150
        if ($this instanceof SwaggerSchema) {
151
            return new SwaggerResponseBody($this, "$method $status $path", $structure['responses'][$status]);
152
        }
153
154
        return new OpenApiResponseBody($this, "$method $status $path", $structure['responses'][$status]);
155
    }
156
157
    /**
158
     * OpenApi 2.0 doesn't describe null values, so this flag defines,
159
     * if match is ok when one of property
160
     *
161
     * @return bool
162
     */
163
    public function isAllowNullValues()
164
    {
165
        return $this->allowNullValues;
166
    }
167
168
    abstract public function getServerUrl();
169
170
    /**
171
     * @param $parameterIn
172
     * @param $parameters
173
     * @param $arguments
174
     * @throws DefinitionNotFoundException
175
     * @throws InvalidDefinitionException
176
     * @throws NotMatchedException
177
     */
178
    abstract protected function validateArguments($parameterIn, $parameters, $arguments);
179
180
    abstract public function getBasePath();
181
182
    /**
183
     * @param $name
184
     * @return mixed
185
     * @throws DefinitionNotFoundException
186
     * @throws InvalidDefinitionException
187
     */
188
    abstract public function getDefinition($name);
189
190
    /**
191
     * @param $path
192
     * @param $method
193
     * @return Body
194
     * @throws HttpMethodNotFoundException
195
     * @throws PathNotFoundException
196
     */
197
    abstract public function getRequestParameters($path, $method);
198
}
199