AbstractObject   A
last analyzed

Complexity

Total Complexity 30

Size/Duplication

Total Lines 190
Duplicated Lines 0 %

Test Coverage

Coverage 96.77%

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 48
c 1
b 1
f 0
dl 0
loc 190
rs 10
ccs 60
cts 62
cp 0.9677
wmc 30

14 Methods

Rating   Name   Duplication   Size   Complexity  
A toJson() 0 3 1
A offsetExists() 0 3 1
A offsetUnset() 0 3 1
A offsetGet() 0 3 1
A offsetSet() 0 3 1
A __get() 0 3 1
A toObject() 0 3 1
A __construct() 0 4 2
A toArray() 0 8 1
A jsonSerialize() 0 4 2
A __toString() 0 3 1
C exportValue() 0 54 15
A toYaml() 0 6 1
A __set() 0 3 1
1
<?php
2
3
namespace erasys\OpenApi\Spec\v3;
4
5
use ArrayAccess;
6
use erasys\OpenApi\Exceptions\ArrayKeyConflictException;
7
use erasys\OpenApi\Exceptions\UndefinedPropertyException;
8
use erasys\OpenApi\Exceptions\UnsupportedTypeException;
9
use erasys\OpenApi\ExtensionProperty;
10
use erasys\OpenApi\RawValue;
11
use Illuminate\Contracts\Support\Arrayable;
12
use Illuminate\Contracts\Support\Jsonable;
13
use JsonSerializable;
14
use stdClass;
15
use Symfony\Component\Yaml\Yaml;
16
17
/**
18
 * Base class for all Open API models.
19
 *
20
 * Note that defining or accessing properties dynamically is not supported by design
21
 * to avoid invalid schema generation. If you need to use specification extensions,
22
 * you can always extend the classes and add there your own properties.
23
 *
24
 */
25
abstract class AbstractObject implements ArrayAccess, Arrayable, Jsonable, JsonSerializable
26
{
27
    /**
28
     * @param array $properties
29
     */
30 132
    public function __construct(array $properties = [])
31
    {
32 132
        foreach ($properties as $k => $v) {
33 39
            $this->$k = $v;
34
        }
35 129
    }
36
37
    /**
38
     * @param string $name
39
     */
40 6
    final public function __get($name)
41
    {
42 6
        throw new UndefinedPropertyException(static::class . "::\${$name}", 1);
43
    }
44
45
    /**
46
     * @param string $name
47
     * @param mixed  $value
48
     */
49 9
    final public function __set($name, $value)
50
    {
51 9
        throw new UndefinedPropertyException(static::class . "::\${$name}", 2);
52
    }
53
54
    /**
55
     * @param string $offset
56
     *
57
     * @return bool
58
     */
59 6
    final public function offsetExists($offset)
60
    {
61 6
        return isset($this->$offset);
62
    }
63
64
    /**
65
     * @param string $offset
66
     *
67
     * @return mixed
68
     */
69 3
    final public function offsetGet($offset)
70
    {
71 3
        return $this->$offset;
72
    }
73
74
    /**
75
     * @param string $offset
76
     * @param mixed  $value
77
     */
78 3
    final public function offsetSet($offset, $value)
79
    {
80 3
        $this->$offset = $value;
81
    }
82
83
    /**
84
     * @param string $offset
85
     */
86 3
    final public function offsetUnset($offset)
87
    {
88 3
        unset($this->$offset);
89 3
    }
90
91
    /**
92
     * @param mixed $value
93
     *
94
     * @return array|mixed
95
     */
96 48
    private function exportValue($value)
97
    {
98 48
        if ($value instanceof RawValue) {
99
            // Unwrap value and return it raw, as it is.
100 3
            return $value->getValue();
101
        }
102
103 48
        if ($value instanceof AbstractObject) {
104 12
            return $value->toArray();
105
        }
106
107 48
        if ($value instanceof ExtensionProperty) {
108
            return [
109
                $value->getName() => $this->exportValue($value->getValue()),
110
            ];
111
        }
112
113 48
        if (is_array($value)) {
114 48
            $result = [];
115 48
            foreach ($value as $k => $v) {
116
                // Take key and value from extension property definition
117 48
                if ($v instanceof ExtensionProperty) {
118 3
                    $k = $v->getName();
119 3
                    $v = $this->exportValue($v->getValue());
120
                }
121
                // Ignore null properties
122 48
                if (is_null($v)) {
123 27
                    continue;
124
                }
125 48
                if (in_array($k, ['xml'])) {
126 3
                    $result[$k] = $this->exportValue($v);
127 3
                    continue;
128
                }
129
                // Transform extension property names using the 'x-respecT_caseFormat'
130 48
                if (preg_match('/^x/i', $k)) {
131 12
                    $k = 'x-' . preg_replace('/^(x[-]?)/i', '', str_replace('_', '-', $k));
132
                }
133
                // Transform reference property names
134 48
                if ($k === 'ref') {
135 3
                    $k = '$ref';
136
                }
137 48
                if (isset($result[$k])) {
138 3
                    throw new ArrayKeyConflictException($k);
139
                }
140 48
                $result[$k] = $this->exportValue($v);
141
            }
142 42
            return $result;
143
        }
144
145 48
        if (!is_null($value) && !is_scalar($value)) {
146 3
            throw new UnsupportedTypeException(is_object($value) ? get_class($value) : gettype($value));
147
        }
148
149 45
        return $value;
150
    }
151
152
    /**
153
     * @return array
154
     */
155
    public function toArray()
156
    {
157 48
        $vars = (function ($that) {
158
            // Only public variables
159 48
            return get_object_vars($that);
160 48
        })->bindTo(null, null)($this);
161
162 48
        return $this->exportValue($vars);
163
    }
164
165
    /**
166
     * @param int $options
167
     *
168
     * @return string
169
     */
170 15
    public function toJson($options = 0)
171
    {
172 15
        return json_encode($this, $options);
173
    }
174
175
    /**
176
     * Returns a plain object
177
     *
178
     * @return object|stdClass
179
     */
180 9
    public function toObject(): stdClass
181
    {
182 9
        return json_decode($this->toJson());
183
    }
184
185
    /**
186
     * @param int $inline
187
     * @param int $indentation
188
     * @param int $flags
189
     * @return string
190
     */
191 3
    public function toYaml(
192
        int $inline = 10,
193
        int $indentation = 2,
194
        int $flags = 0
195
    ): string {
196 3
        return Yaml::dump($this->toArray(), $inline, $indentation, $flags);
197
    }
198
199
    /**
200
     * Returns a value that is suitable for JSON serialization,
201
     * in order to be able to export empty objects correctly, so they
202
     * won't be treated as empty arrays.
203
     *
204
     * @return array|stdClass
205
     */
206 15
    public function jsonSerialize()
207
    {
208 15
        $properties = $this->toArray();
209 15
        return empty($properties) ? new stdClass() : $properties;
210
    }
211
212 3
    public function __toString()
213
    {
214 3
        return $this->toJson();
215
    }
216
}
217