Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
93.85% covered (success)
93.85%
61 / 65
85.71% covered (warning)
85.71%
12 / 14
CRAP
0.00% covered (danger)
0.00%
0 / 1
Schema
93.85% covered (success)
93.85%
61 / 65
85.71% covered (warning)
85.71%
12 / 14
39.35
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 withResolvedReferences
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 resolveKey
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
4
 resolveReferences
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 toJsonObject
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 setJsonObject
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setDefaults
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setJsonCompressLevel
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 toSanitizedArray
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 toSanitizedValue
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
7
 toSanitizedList
66.67% covered (warning)
66.67%
6 / 9
0.00% covered (danger)
0.00%
0 / 1
8.81
 isItemEmpty
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 withoutRefs
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getWithoutRefs
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
4.07
1<?php
2
3namespace BO\Zmsentities\Schema;
4
5/**
6 * @extends \ArrayObject<array-key, mixed>
7 */
8class Schema extends \ArrayObject
9{
10    protected $input = null;
11
12    protected $asObject = null;
13
14    protected $defaults = [];
15
16    /**
17     * @var Int $jsonCompressLevel
18     */
19    protected $jsonCompressLevel = 0;
20
21    /**
22     * Read the json schema and let array act like an object
23     */
24    public function __construct($input = [], $flags = \ArrayObject::ARRAY_AS_PROPS, $iterator_class = "ArrayIterator")
25    {
26        $this->input = $input;
27        parent::__construct($input, $flags, $iterator_class);
28    }
29
30    public function withResolvedReferences($resolveLevel)
31    {
32        if ($resolveLevel > 0) {
33            $schema = clone $this;
34            $schema = $this->resolveReferences($schema, $resolveLevel);
35            $schema->setJsonObject(json_decode(json_encode($schema->toSanitizedArray(true))));
36            return $schema;
37        }
38        return $this;
39    }
40
41    protected function resolveKey($key, $value, $resolveLevel)
42    {
43        if (is_array($value)) {
44            $value = $this->resolveReferences($value, $resolveLevel);
45        } elseif ($key === '$ref' && $value[0] != '#') {
46            $value = Loader::asArray($value)->withResolvedReferences($resolveLevel - 1);
47        }
48        return $value;
49    }
50
51    protected function resolveReferences($hash, $resolveLevel)
52    {
53        foreach ($hash as $key => $value) {
54            $hash[$key] = $this->resolveKey($key, $value, $resolveLevel);
55            if ($hash[$key] instanceof self) {
56                // Schema from Loader::asArray() is returned, we guess $key is '$ref' and should be replaced
57                return $hash[$key]->getArrayCopy();
58            }
59        }
60        return $hash;
61    }
62
63    public function toJsonObject($keepEmpty = false)
64    {
65        if (null !== $this->asObject) {
66            $data = $this->asObject;
67        } elseif (! $keepEmpty) {
68            $data = json_decode(json_encode($this->toSanitizedArray($keepEmpty)));
69        } else {
70            $data = json_decode(json_encode($this->toSanitizedArray($keepEmpty)));
71        }
72        return $data;
73    }
74
75    public function setJsonObject(\stdClass $asObject)
76    {
77        $this->asObject = $asObject;
78        return $this;
79    }
80
81    public function setDefaults($defaults)
82    {
83        $this->defaults = $defaults;
84    }
85
86    public function setJsonCompressLevel($jsonCompressLevel)
87    {
88        $this->jsonCompressLevel = $jsonCompressLevel;
89        return $this;
90    }
91
92    public function toSanitizedArray($keepEmpty = false)
93    {
94        $data = $this->getArrayCopy();
95        $data = $this->toSanitizedValue($data, $keepEmpty, $this->defaults);
96        return $data;
97    }
98
99    /**
100     * Sanitize value for valid export as JSON
101     *
102     */
103    protected function toSanitizedValue($value, $keepEmpty = false, $defaults = [])
104    {
105        if ($value instanceof \BO\Zmsentities\Helper\NoSanitize) {
106            return $value;
107        }
108        if ($value instanceof \BO\Zmsentities\Collection\JsonUnindexed) {
109            $value = array_values($value->getArrayCopy());
110        } elseif ($value instanceof \ArrayObject) {
111            if (method_exists($value, 'getDefaults')) {
112                $defaults = $value->getDefaults();
113            }
114            $value = $value->getArrayCopy();
115        }
116        if (is_array($value)) {
117            $value = $this->toSanitizedList($value, $keepEmpty, $defaults);
118        }
119        if ($value instanceof \JsonSerializable) {
120            $value = $value->jsonSerialize();
121        }
122        return $value;
123    }
124
125    protected function toSanitizedList($value, $keepEmpty, $defaults = [])
126    {
127        foreach ($value as $key => $item) {
128            if ($this->jsonCompressLevel > 0 && isset($defaults[$key])) {
129                $value[$key] = $this->toSanitizedValue($item, $keepEmpty, $defaults[$key]);
130                if ($defaults[$key] === $value[$key]) {
131                    $value[$key] = null;
132                }
133            } else {
134                $value[$key] = $this->toSanitizedValue($item, $keepEmpty);
135            }
136            if (! $keepEmpty && $this->isItemEmpty($value[$key])) {
137                unset($value[$key]);
138            }
139        }
140        return $value;
141    }
142
143    protected static function isItemEmpty($item)
144    {
145        return (
146            null === $item
147            || (is_array($item) && count($item) == 0)
148        );
149    }
150
151    /*
152     * Uses a path like '/changePassword/0' to fetch property settings
153     *
154    public function toProperty()
155    {
156        return new \BO\Zmsentities\Helper\Property($this);
157    }
158
159
160    public function getPropertyByPath($path)
161    {
162        $pointerList = explode('/', trim($path, '/ '));
163        $property = $this->toProperty();
164        $property = $pointerList[0] == 'properties' ? $property : $property->properties;
165        foreach ($pointerList as $pointer) {
166            if ($property->type->get() == 'array') {
167                $property = $property['items'];
168            } elseif ($property->type->get() == 'object' && $pointer !== 'properties') {
169                $property = $property->properties[$pointer];
170            } elseif (is_numeric($pointer)) {
171                // ignore array items
172            } else {
173                $property = $property[$pointer];
174            }
175        }
176        return $property->get([]);
177    }
178    */
179
180    public function withoutRefs()
181    {
182        return $this->getWithoutRefs(clone $this);
183    }
184
185    protected function getWithoutRefs($data)
186    {
187        foreach ($data as $key => $value) {
188            if (is_array($value)) {
189                $data[$key] = $this->getWithoutRefs($value);
190            }
191            if ($key === '$ref') {
192                unset($data[$key]);
193            }
194        }
195        return $data;
196    }
197}