1313/**
1414 * @method int getId()
1515 * @method void setId(int $id)
16+ * @psalm-type AllowedTypes = 'json'|'blob'|'datetime'|'string'|'int'|'integer'|'bool'|'boolean'|'float'|'double'|'array'|'object'
1617 * @since 7.0.0
1718 * @psalm-consistent-constructor
1819 */
@@ -23,6 +24,7 @@ abstract class Entity {
2324 public $ id ;
2425
2526 private array $ _updatedFields = [];
27+ /** @var array<string, AllowedTypes> */
2628 private array $ _fieldTypes = ['id ' => 'integer ' ];
2729
2830 /**
@@ -64,10 +66,10 @@ public static function fromRow(array $row): static {
6466
6567
6668 /**
67- * @return array with attribute and type
69+ * @return array<string, AllowedTypes> with attribute and type
6870 * @since 7.0.0
6971 */
70- public function getFieldTypes () {
72+ public function getFieldTypes (): array {
7173 return $ this ->_fieldTypes ;
7274 }
7375
@@ -76,50 +78,62 @@ public function getFieldTypes() {
7678 * Marks the entity as clean needed for setting the id after the insertion
7779 * @since 7.0.0
7880 */
79- public function resetUpdatedFields () {
81+ public function resetUpdatedFields (): void {
8082 $ this ->_updatedFields = [];
8183 }
8284
8385 /**
8486 * Generic setter for properties
87+ *
88+ * @throws \InvalidArgumentException
8589 * @since 7.0.0
90+ *
8691 */
8792 protected function setter (string $ name , array $ args ): void {
8893 // setters should only work for existing attributes
89- if (property_exists ($ this , $ name )) {
90- if ($ args [0 ] === $ this ->$ name ) {
91- return ;
92- }
93- $ this ->markFieldUpdated ($ name );
94-
95- // if type definition exists, cast to correct type
96- if ($ args [0 ] !== null && array_key_exists ($ name , $ this ->_fieldTypes )) {
97- $ type = $ this ->_fieldTypes [$ name ];
98- if ($ type === 'blob ' ) {
99- // (B)LOB is treated as string when we read from the DB
100- if (is_resource ($ args [0 ])) {
101- $ args [0 ] = stream_get_contents ($ args [0 ]);
102- }
103- $ type = 'string ' ;
94+ if (!property_exists ($ this , $ name )) {
95+ throw new \BadFunctionCallException ($ name . ' is not a valid attribute ' );
96+ }
97+
98+ if ($ args [0 ] === $ this ->$ name ) {
99+ return ;
100+ }
101+ $ this ->markFieldUpdated ($ name );
102+
103+ // if type definition exists, cast to correct type
104+ if ($ args [0 ] !== null && array_key_exists ($ name , $ this ->_fieldTypes )) {
105+ $ type = $ this ->_fieldTypes [$ name ];
106+ if ($ type === 'blob ' ) {
107+ // (B)LOB is treated as string when we read from the DB
108+ if (is_resource ($ args [0 ])) {
109+ $ args [0 ] = stream_get_contents ($ args [0 ]);
104110 }
111+ $ type = 'string ' ;
112+ }
105113
106- if ($ type === 'datetime ' ) {
107- if (!$ args [0 ] instanceof \DateTime) {
108- $ args [0 ] = new \DateTime ($ args [0 ]);
109- }
110- } elseif ($ type === 'json ' ) {
111- if (!is_array ($ args [0 ])) {
112- $ args [0 ] = json_decode ($ args [0 ], true );
113- }
114- } else {
115- settype ($ args [0 ], $ type );
114+ if ($ type === 'datetime ' ) {
115+ if (!$ args [0 ] instanceof \DateTime) {
116+ $ args [0 ] = new \DateTime ($ args [0 ]);
116117 }
118+ } elseif ($ type === 'json ' ) {
119+ if (!is_array ($ args [0 ])) {
120+ $ args [0 ] = json_decode ($ args [0 ], true );
121+ }
122+ } else {
123+ $ args [0 ] = match ($ type ) {
124+ 'string ' => (string )$ args [0 ],
125+ 'bool ' , 'boolean ' , => (bool )$ args [0 ],
126+ 'int ' , 'integer ' , => (int )$ args [0 ],
127+ 'float ' => (float )$ args [0 ],
128+ 'double ' => (float )$ args [0 ],
129+ 'array ' => (array )$ args [0 ],
130+ 'object ' => (object )$ args [0 ],
131+ default => new \InvalidArgumentException ()
132+ };
117133 }
118- $ this ->$ name = $ args [0 ];
119- } else {
120- throw new \BadFunctionCallException ($ name .
121- ' is not a valid attribute ' );
122134 }
135+ $ this ->$ name = $ args [0 ];
136+
123137 }
124138
125139 /**
@@ -182,16 +196,17 @@ protected function markFieldUpdated(string $attribute): void {
182196
183197 /**
184198 * Transform a database columnname to a property
199+ *
185200 * @param string $columnName the name of the column
186201 * @return string the property name
187202 * @since 7.0.0
188203 */
189- public function columnToProperty ($ columnName ) {
204+ public function columnToProperty (string $ columnName ): string {
190205 $ parts = explode ('_ ' , $ columnName );
191- $ property = null ;
206+ $ property = '' ;
192207
193208 foreach ($ parts as $ part ) {
194- if ($ property === null ) {
209+ if ($ property === '' ) {
195210 $ property = $ part ;
196211 } else {
197212 $ property .= ucfirst ($ part );
@@ -204,16 +219,17 @@ public function columnToProperty($columnName) {
204219
205220 /**
206221 * Transform a property to a database column name
222+ *
207223 * @param string $property the name of the property
208224 * @return string the column name
209225 * @since 7.0.0
210226 */
211- public function propertyToColumn ($ property ) {
227+ public function propertyToColumn (string $ property ): string {
212228 $ parts = preg_split ('/(?=[A-Z])/ ' , $ property );
213- $ column = null ;
214229
230+ $ column = '' ;
215231 foreach ($ parts as $ part ) {
216- if ($ column === null ) {
232+ if ($ column === '' ) {
217233 $ column = $ part ;
218234 } else {
219235 $ column .= '_ ' . lcfirst ($ part );
@@ -228,32 +244,34 @@ public function propertyToColumn($property) {
228244 * @return array array of updated fields for update query
229245 * @since 7.0.0
230246 */
231- public function getUpdatedFields () {
247+ public function getUpdatedFields (): array {
232248 return $ this ->_updatedFields ;
233249 }
234250
235251
236252 /**
237- * Adds type information for a field so that its automatically casted to
253+ * Adds type information for a field so that it's automatically cast to
238254 * that value once its being returned from the database
255+ *
239256 * @param string $fieldName the name of the attribute
240- * @param string $type the type which will be used to call settype()
257+ * @param AllowedTypes $type the type which will be used to match a cast
241258 * @since 7.0.0
242259 */
243- protected function addType ($ fieldName , $ type ) {
260+ protected function addType (string $ fieldName , string $ type ): void {
244261 $ this ->_fieldTypes [$ fieldName ] = $ type ;
245262 }
246263
247264
248265 /**
249266 * Slugify the value of a given attribute
250267 * Warning: This doesn't result in a unique value
268+ *
251269 * @param string $attributeName the name of the attribute, which value should be slugified
252270 * @return string slugified value
253271 * @since 7.0.0
254272 * @deprecated 24.0.0
255273 */
256- public function slugify ($ attributeName ) {
274+ public function slugify (string $ attributeName ): string {
257275 // toSlug should only work for existing attributes
258276 if (property_exists ($ this , $ attributeName )) {
259277 $ value = $ this ->$ attributeName ;
@@ -262,9 +280,8 @@ public function slugify($attributeName) {
262280 $ value = strtolower ($ value );
263281 // trim '-'
264282 return trim ($ value , '- ' );
265- } else {
266- throw new \BadFunctionCallException ($ attributeName .
267- ' is not a valid attribute ' );
268283 }
284+
285+ throw new \BadFunctionCallException ($ attributeName . ' is not a valid attribute ' );
269286 }
270287}
0 commit comments