Completed
Push — master ( ebd1fd...6faa20 )
by Melech
04:36
created

ModelTrait::__changed()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 7
nc 3
nop 0
dl 0
loc 14
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Valkyrja Framework package.
7
 *
8
 * (c) Melech Mizrachi <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Valkyrja\Support\Model\Traits;
15
16
use JsonException;
17
use Valkyrja\Support\Type\Arr;
18
use Valkyrja\Support\Type\Obj;
19
use Valkyrja\Support\Type\Str;
20
21
use function method_exists;
22
use function property_exists;
23
24
/**
25
 * Trait ModelTrait.
26
 *
27
 * @author Melech Mizrachi
28
 */
29
trait ModelTrait
30
{
31
    /**
32
     * The properties to expose.
33
     *
34
     * @var string[]
35
     */
36
    protected static array $exposed = [];
37
38
    /**
39
     * The original properties.
40
     *
41
     * @var array
42
     */
43
    protected static array $originalProperties = [];
44
45
    /**
46
     * Set properties from an array of properties.
47
     *
48
     * @param array $properties
49
     *
50
     * @return static
51
     */
52
    public static function fromArray(array $properties): self
53
    {
54
        $model = new static();
55
56
        $model->__setProperties($properties);
57
58
        return $model;
59
    }
60
61
    /**
62
     * Get a property.
63
     *
64
     * @param string $name The property to get
65
     *
66
     * @return mixed
67
     */
68
    public function __get(string $name)
69
    {
70
        $methodName = 'get' . Str::toStudlyCase($name);
71
72
        if (method_exists($this, $methodName)) {
73
            return $this->$methodName();
74
        }
75
76
        return $this->{$name};
77
    }
78
79
    /**
80
     * Set a property.
81
     *
82
     * @param string $name  The property to set
83
     * @param mixed  $value The value to set
84
     *
85
     * @return void
86
     */
87
    public function __set(string $name, $value): void
88
    {
89
        $methodName = 'set' . Str::toStudlyCase($name);
90
91
        if (method_exists($this, $methodName)) {
92
            $this->$methodName($value);
93
94
            return;
95
        }
96
97
        $this->{$name} = $value;
98
    }
99
100
    /**
101
     * Check if a property is set.
102
     *
103
     * @param string $name The property to check
104
     *
105
     * @return bool
106
     */
107
    public function __isset(string $name): bool
108
    {
109
        $methodName = 'isset' . Str::toStudlyCase($name);
110
111
        if (method_exists($this, $methodName)) {
112
            return $this->$methodName();
113
        }
114
115
        return property_exists($this, $name);
116
    }
117
118
    /**
119
     * Set properties from an array of properties.
120
     *
121
     * @param array $properties
122
     *
123
     * @return void
124
     */
125
    public function __setProperties(array $properties): void
126
    {
127
        // Iterate through the properties
128
        foreach ($properties as $property => $value) {
129
            // Ensure the property exists before blindly setting
130
            if (property_exists($this, $property)) {
131
                static::$originalProperties[$property] = $value;
132
133
                // Set the property
134
                $this->__set($property, $value);
135
            }
136
        }
137
    }
138
139
    /**
140
     * Get model as an array.
141
     *
142
     * @return array
143
     */
144
    public function __toArray(): array
145
    {
146
        // Get the public properties
147
        $properties = Obj::getProperties($this);
148
149
        // Iterate through properties to expose
150
        foreach (static::$exposed as $exposedProperty => $value) {
151
            if (isset($this->{$exposedProperty})) {
152
                $properties[$exposedProperty] = $this->__get($exposedProperty);
153
            }
154
        }
155
156
        return $properties;
157
    }
158
159
    /**
160
     * Get an array of changed properties.
161
     *
162
     * @return array
163
     */
164
    public function __changed(): array
165
    {
166
        $originalProperties = static::$originalProperties;
167
        $changed = [];
168
169
        foreach ($this->__toArray() as $property => $value) {
170
            $originalProperty = $originalProperties[$property] ?? $value;
171
172
            if ($originalProperty !== $value) {
173
                $changed[$property] = $value;
174
            }
175
        }
176
177
        return $changed;
178
    }
179
180
    /**
181
     * Serialize properties for json_encode.
182
     *
183
     * @return array
184
     */
185
    public function jsonSerialize(): array
186
    {
187
        return $this->__toArray();
188
    }
189
190
    /**
191
     * To string.
192
     *
193
     * @throws JsonException
194
     *
195
     * @return string
196
     */
197
    public function __toString(): string
198
    {
199
        return Arr::toString($this->jsonSerialize());
200
    }
201
202
    /**
203
     * Expose hidden fields or all fields.
204
     *
205
     * @param string ...$properties The field(s) to expose
206
     *
207
     * @return void
208
     */
209
    public function __expose(string ...$properties): void
210
    {
211
        foreach ($properties as $property) {
212
            static::$exposed[$property] = true;
213
        }
214
    }
215
216
    /**
217
     * Un-expose hidden fields or all fields.
218
     *
219
     * @param string ...$properties The field(s) to expose
220
     *
221
     * @return void
222
     */
223
    public function __unexpose(string ...$properties): void
224
    {
225
        if (empty($properties)) {
226
            static::$exposed = [];
227
228
            return;
229
        }
230
231
        foreach ($properties as $property) {
232
            unset(static::$exposed[$property]);
233
        }
234
    }
235
}
236