Completed
Push — master ( bb12d3...dcbb11 )
by Joao
02:11
created

SwaggerBody   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 183
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
wmc 33
lcom 1
cbo 2
dl 0
loc 183
rs 9.3999
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 2
match() 0 1 ?
A matchString() 0 10 3
A matchNumber() 0 8 2
A matchBool() 0 8 2
A matchArray() 0 10 3
C matchSchema() 0 76 19
A matchNull() 0 11 2
1
<?php
2
3
namespace ByJG\Swagger;
4
5
use ByJG\Swagger\Exception\NotMatchedException;
6
7
abstract class SwaggerBody
8
{
9
    /**
10
     * @var \ByJG\Swagger\SwaggerSchema
11
     */
12
    protected $swaggerSchema;
13
14
    protected $structure;
15
16
    protected $name;
17
18
    /**
19
     * OpenApi 2.0 does not describe null values, so this flag defines,
20
     * if match is ok when one of property, which has type, is null
21
     *
22
     * @var bool
23
     */
24
    protected $allowNullValues;
25
26
    /**
27
     * SwaggerRequestBody constructor.
28
     *
29
     * @param \ByJG\Swagger\SwaggerSchema $swaggerSchema
30
     * @param string $name
31
     * @param array $structure
32
     * @param bool $allowNullValues
33
     */
34
    public function __construct(SwaggerSchema $swaggerSchema, $name, $structure, $allowNullValues = false)
35
    {
36
        $this->swaggerSchema = $swaggerSchema;
37
        $this->name = $name;
38
        if (!is_array($structure)) {
39
            throw new \InvalidArgumentException('I expected the structure to be an array');
40
        }
41
        $this->structure = $structure;
42
        $this->allowNullValues = $allowNullValues;
43
    }
44
45
    abstract public function match($body);
46
47
    protected function matchString($name, $schema, $body)
48
    {
49
        if (isset($schema['enum'])) {
50
            if (!in_array($body, $schema['enum'])) {
51
                throw new NotMatchedException("Value '$body' in '$name' not matched in ENUM. ", $this->structure);
52
            };
53
        }
54
55
        return true;
56
    }
57
58
    protected function matchNumber($name, $body)
59
    {
60
        if (!is_numeric($body)) {
61
            throw new NotMatchedException("Expected '$name' to be numeric, but found '$body'. ", $this->structure);
62
        }
63
64
        return true;
65
    }
66
67
    protected function matchBool($name, $body)
68
    {
69
        if (!is_bool($body)) {
70
            throw new NotMatchedException("Expected '$name' to be boolean, but found '$body'. ", $this->structure);
71
        }
72
73
        return true;
74
    }
75
76
    protected function matchArray($name, $schema, $body)
77
    {
78
        foreach ((array)$body as $item) {
79
            if (!isset($schema['items'])) {  // If there is no type , there is no test.
80
                continue;
81
            }
82
            $this->matchSchema($name, $schema['items'], $item);
83
        }
84
        return true;
85
    }
86
87
    /**
88
     * @param string $name
89
     * @param $schema
90
     * @param array $body
91
     * @return bool
92
     * @throws \ByJG\Swagger\Exception\NotMatchedException
93
     * @throws \Exception
94
     */
95
    protected function matchSchema($name, $schema, $body)
96
    {
97
        if (isset($schema['type'])) {
98
99
            $type = $schema['type'];
100
            if (is_null($body)) {
101
                return $this->matchNull($name, $type);
102
            }
103
104
            if ($type == 'string') {
105
                return $this->matchString($name, $schema, $body);
106
            }
107
108
            if ($type == 'integer' || $type == 'float' || $schema['type'] == 'number') {
109
                return $this->matchNumber($name, $body);
110
            }
111
112
            if ($type == 'bool' || $schema['type'] == 'boolean') {
113
                return $this->matchBool($name, $body);
114
            }
115
116
            if ($type == 'array') {
117
                return $this->matchArray($name, $schema, $body);
118
            }
119
        }
120
121
        if (isset($schema['$ref'])) {
122
            $defintion = $this->swaggerSchema->getDefintion($schema['$ref']);
123
            return $this->matchSchema($schema['$ref'], $defintion, $body);
124
        }
125
126
        if (isset($schema['properties'])) {
127
            if (!isset($schema['required'])) {
128
                $schema['required'] = [];
129
            }
130
            foreach ($schema['properties'] as $prop => $def) {
131
                $required = array_search($prop, $schema['required']);
132
133
                if (!array_key_exists($prop, $body)) {
134
                    if ($required !== false) {
135
                         throw new NotMatchedException("Required property '$prop' in '$name' not found in object");
136
                    }
137
                    unset($body[$prop]);
138
                    continue;
139
                }
140
141
                $this->matchSchema($prop, $def, $body[$prop]);
142
                unset($schema['properties'][$prop]);
143
                if ($required !== false) {
144
                    unset($schema['required'][$required]);
145
                }
146
                unset($body[$prop]);
147
            }
148
149
            if (count($schema['required']) > 0) {
150
                throw new NotMatchedException(
151
                    "The required property(ies) '"
152
                    . implode(', ', $schema['required'])
153
                    . "' does not exists in the body.",
154
                    $this->structure
155
                );
156
            }
157
158
            if (count($body) > 0) {
159
                throw new NotMatchedException(
160
                    "The property(ies) '"
161
                    . implode(', ', array_keys($body))
162
                    . "' has not defined in '$name'",
163
                    $body
164
                );
165
            }
166
            return true;
167
        }
168
169
        throw new \Exception("Not all cases are defined. Please open an issue about this. Schema: $name");
170
    }
171
172
    /**
173
     * @param $name
174
     * @param $type
175
     * @return bool
176
     * @throws NotMatchedException
177
     */
178
    protected function matchNull($name, $type)
179
    {
180
        if (false === $this->swaggerSchema->isAllowNullValues()) {
181
            throw new NotMatchedException(
182
                "Value of property '$name' is null, but should be of type '$type'",
183
                $this->structure
184
            );
185
        }
186
187
        return true;
188
    }
189
}
190