• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

wol-soft / php-json-schema-model-generator-production / 20812890636

08 Jan 2026 09:58AM UTC coverage: 19.788% (-0.1%) from 19.929%
20812890636

push

github

wol-soft
correctly serialize nested empty objects into JSON (https://github.com/wol-soft/php-json-schema-model-generator/issues/109)

1 of 2 new or added lines in 1 file covered. (50.0%)

112 of 566 relevant lines covered (19.79%)

0.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.88
/src/Traits/SerializableTrait.php
1
<?php
2

3
declare(strict_types = 1);
4

5
namespace PHPModelGenerator\Traits;
6

7
use stdClass;
8

9
/**
10
 * Provide methods to serialize generated models
11
 *
12
 * Trait SerializableTrait
13
 *
14
 * @package PHPModelGenerator\Traits
15
 */
16
trait SerializableTrait
17
{
18
    private static $_customSerializer = [];
19

20
    /**
21
     * Get a JSON representation of the current state
22
     *
23
     * @param array $except provide a list of properties which shouldn't be contained in the resulting JSON.
24
     *                      eg. if you want to return an user model and don't want the password to be included
25
     * @param int $options  Bitmask for json_encode
26
     * @param int $depth    the maximum level of object nesting. Must be greater than 0
27
     *
28
     * @return string|false
29
     */
30
    public function toJSON(array $except = [], int $options = 0, int $depth = 512)
×
31
    {
32
        if ($depth < 1) {
×
33
            return false;
×
34
        }
35

36
        return json_encode($this->_getValues($depth, $except, true), $options, $depth);
×
37
    }
38

39
    /**
40
     * Return a JSON serializable representation of the current state
41
     */
42
    #[\ReturnTypeWillChange]
×
43
    public function jsonSerialize(array $except = [])
44
    {
NEW
45
        return $this->_getValues(512, $except, true);
×
46
    }
47

48
    /**
49
     * Get an array representation of the current state
50
     *
51
     * @param array $except provide a list of properties which shouldn't be contained in the resulting JSON.
52
     *                      eg. if you want to return an user model and don't want the password to be included
53
     * @param int $depth    the maximum level of object nesting. Must be greater than 0
54
     *
55
     * @return array|false
56
     */
57
    public function toArray(array $except = [], int $depth = 512)
1✔
58
    {
59
        if ($depth < 1) {
1✔
60
            return false;
×
61
        }
62

63
        return $this->_getValues($depth, $except, false);
1✔
64
    }
65

66
    /**
67
     * Get a representation of the current state
68
     *
69
     * @param array $except                provide a list of properties which shouldn't be contained in the resulting JSON.
70
     *                                     eg. if you want to return an user model and don't want the password to be included
71
     * @param int $depth                   the maximum level of object nesting. Must be greater than 0
72
     * @param bool $emptyObjectsAsStdClass If set to true, the wrapping data structure for empty objects will be an stdClass. Array otherwise
73
     *
74
     * @return array|stdClass
75
     */
76
    private function _getValues(int $depth, array $except, bool $emptyObjectsAsStdClass)
1✔
77
    {
78
        $depth--;
1✔
79
        $modelData = [];
1✔
80

81
        if (isset($this->_skipNotProvidedPropertiesMap, $this->_rawModelDataInput)) {
1✔
82
            $except = array_merge(
×
83
                $except,
×
84
                array_diff($this->_skipNotProvidedPropertiesMap, array_keys($this->_rawModelDataInput))
×
85
            );
×
86
        }
87

88
        foreach (get_class_vars(get_class($this)) as $key => $value) {
1✔
89
            if (in_array($key, $except) || str_starts_with($key, '_') !== false) {
1✔
90
                continue;
1✔
91
            }
92

93
            if ($customSerializer = $this->_getCustomSerializerMethod($key)) {
1✔
94
                $modelData[$key] = $this->_getSerializedValue($this->{$customSerializer}(), $depth, $except, $emptyObjectsAsStdClass);
×
95
                continue;
×
96
            }
97

98
            $modelData[$key] = $this->_getSerializedValue($this->$key, $depth, $except, $emptyObjectsAsStdClass);
1✔
99
        }
100

101
        $data = $this->resolveSerializationHook($modelData, $depth, $except);
1✔
102

103
        if ($emptyObjectsAsStdClass && empty($data)) {
1✔
104
            $data = new stdClass();
×
105
        }
106

107
        return $data;
1✔
108
    }
109

110
    /**
111
     * Function can be overwritten by classes using the trait to hook into serialization
112
     */
113
    protected function resolveSerializationHook(array $data, int $depth, array $except): array
1✔
114
    {
115
        return $data;
1✔
116
    }
117

118
    private function _getSerializedValue($value, int $depth, array $except, bool $emptyObjectsAsStdClass = false) {
1✔
119
        if (is_array($value)) {
1✔
120
            $subData = [];
1✔
121
            foreach ($value as $subKey => $element) {
1✔
122
                $subData[$subKey] = $this->_getSerializedValue($element, $depth - 1, $except, $emptyObjectsAsStdClass);
1✔
123
            }
124
            return $subData;
1✔
125
        }
126

127
        return $this->evaluateAttribute($value, $depth, $except, $emptyObjectsAsStdClass);
1✔
128
    }
129

130
    private function evaluateAttribute($attribute, int $depth, array $except, bool $emptyObjectsAsStdClass)
1✔
131
    {
132
        if (!is_object($attribute)) {
1✔
133
            return $attribute;
1✔
134
        }
135

136
        if ($depth === 0 && method_exists($attribute, '__toString')) {
1✔
137
            return (string) $attribute;
×
138
        }
139

140
        $data = match (true) {
1✔
141
            0 >= $depth                                                           => null,
1✔
142
            $emptyObjectsAsStdClass && method_exists($attribute, 'jsonSerialize') => $attribute->jsonSerialize($except),
1✔
143
            method_exists($attribute, 'toArray')                                  => $attribute->toArray($except),
1✔
144
            default                                                               => get_object_vars($attribute),
1✔
145
        };
1✔
146

147
        if ($data === [] && $emptyObjectsAsStdClass) {
1✔
148
            $data = new stdClass();
×
149
        }
150

151
        return $data;
1✔
152
    }
153

154
    private function _getCustomSerializerMethod(string $property) {
1✔
155
        if (isset(self::$_customSerializer[$property])) {
1✔
156
            return self::$_customSerializer[$property];
1✔
157
        }
158

159
        $customSerializer = 'serialize' . ucfirst($property);
1✔
160
        if (!method_exists($this, $customSerializer)) {
1✔
161
            $customSerializer = false;
1✔
162
        }
163

164
        return self::$_customSerializer[$property] = $customSerializer;
1✔
165
    }
166
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc