Completed
Push — master ( ef226e...0390c0 )
by
unknown
46:40 queued 21:40
created
lib/public/AppFramework/Db/Entity.php 1 patch
Indentation   +289 added lines, -289 removed lines patch added patch discarded remove patch
@@ -19,293 +19,293 @@
 block discarded – undo
19 19
  * @psalm-consistent-constructor
20 20
  */
21 21
 abstract class Entity {
22
-	/** @var int $id */
23
-	public $id;
24
-	/** @var array<string, true> $_updatedFields */
25
-	private array $_updatedFields = [];
26
-	/** @var array<string, Types::*> $_fieldTypes */
27
-	protected array $_fieldTypes = ['id' => 'integer'];
28
-
29
-	/**
30
-	 * Simple alternative constructor for building entities from a request
31
-	 * @param array $params the array which was obtained via $this->params('key')
32
-	 *                      in the controller
33
-	 * @since 7.0.0
34
-	 */
35
-	public static function fromParams(array $params): static {
36
-		$instance = new static();
37
-
38
-		foreach ($params as $key => $value) {
39
-			$method = 'set' . ucfirst($key);
40
-			$instance->$method($value);
41
-		}
42
-
43
-		return $instance;
44
-	}
45
-
46
-	/**
47
-	 * Maps the keys of the row array to the attributes
48
-	 * @param array $row the row to map onto the entity
49
-	 * @since 7.0.0
50
-	 */
51
-	public static function fromRow(array $row): static {
52
-		$instance = new static();
53
-
54
-		foreach ($row as $key => $value) {
55
-			$prop = $instance->columnToProperty($key);
56
-			$instance->setter($prop, [$value]);
57
-		}
58
-
59
-		$instance->resetUpdatedFields();
60
-
61
-		return $instance;
62
-	}
63
-
64
-
65
-	/**
66
-	 * @return array<string, Types::*> with attribute and type
67
-	 * @since 7.0.0
68
-	 */
69
-	public function getFieldTypes(): array {
70
-		return $this->_fieldTypes;
71
-	}
72
-
73
-
74
-	/**
75
-	 * Marks the entity as clean needed for setting the id after the insertion
76
-	 * @since 7.0.0
77
-	 */
78
-	public function resetUpdatedFields(): void {
79
-		$this->_updatedFields = [];
80
-	}
81
-
82
-	/**
83
-	 * Generic setter for properties
84
-	 *
85
-	 * @throws \InvalidArgumentException
86
-	 * @since 7.0.0
87
-	 *
88
-	 */
89
-	protected function setter(string $name, array $args): void {
90
-		// setters should only work for existing attributes
91
-		if (!property_exists($this, $name)) {
92
-			throw new \BadFunctionCallException($name . ' is not a valid attribute');
93
-		}
94
-
95
-		if ($args[0] === $this->$name) {
96
-			return;
97
-		}
98
-		$this->markFieldUpdated($name);
99
-
100
-		// if type definition exists, cast to correct type
101
-		if ($args[0] !== null && array_key_exists($name, $this->_fieldTypes)) {
102
-			$type = $this->_fieldTypes[$name];
103
-			if ($type === Types::BLOB) {
104
-				// (B)LOB is treated as string when we read from the DB
105
-				if (is_resource($args[0])) {
106
-					$args[0] = stream_get_contents($args[0]);
107
-				}
108
-				$type = Types::STRING;
109
-			}
110
-
111
-			switch ($type) {
112
-				case Types::BIGINT:
113
-				case Types::SMALLINT:
114
-					settype($args[0], Types::INTEGER);
115
-					break;
116
-				case Types::BINARY:
117
-				case Types::DECIMAL:
118
-				case Types::TEXT:
119
-					settype($args[0], Types::STRING);
120
-					break;
121
-				case Types::TIME:
122
-				case Types::DATE:
123
-				case Types::DATETIME:
124
-				case Types::DATETIME_TZ:
125
-					if (!$args[0] instanceof \DateTime) {
126
-						$args[0] = new \DateTime($args[0]);
127
-					}
128
-					break;
129
-				case Types::TIME_IMMUTABLE:
130
-				case Types::DATE_IMMUTABLE:
131
-				case Types::DATETIME_IMMUTABLE:
132
-				case Types::DATETIME_TZ_IMMUTABLE:
133
-					if (!$args[0] instanceof \DateTimeImmutable) {
134
-						$args[0] = new \DateTimeImmutable($args[0]);
135
-					}
136
-					break;
137
-				case Types::JSON:
138
-					if (!is_array($args[0])) {
139
-						$args[0] = json_decode($args[0], true);
140
-					}
141
-					break;
142
-				default:
143
-					settype($args[0], $type);
144
-			}
145
-		}
146
-		$this->$name = $args[0];
147
-
148
-	}
149
-
150
-	/**
151
-	 * Generic getter for properties
152
-	 * @since 7.0.0
153
-	 */
154
-	protected function getter(string $name): mixed {
155
-		// getters should only work for existing attributes
156
-		if (property_exists($this, $name)) {
157
-			return $this->$name;
158
-		} else {
159
-			throw new \BadFunctionCallException($name
160
-				. ' is not a valid attribute');
161
-		}
162
-	}
163
-
164
-
165
-	/**
166
-	 * Each time a setter is called, push the part after set
167
-	 * into an array: for instance setId will save Id in the
168
-	 * updated fields array so it can be easily used to create the
169
-	 * getter method
170
-	 * @since 7.0.0
171
-	 */
172
-	public function __call(string $methodName, array $args) {
173
-		if (str_starts_with($methodName, 'set')) {
174
-			$this->setter(lcfirst(substr($methodName, 3)), $args);
175
-		} elseif (str_starts_with($methodName, 'get')) {
176
-			return $this->getter(lcfirst(substr($methodName, 3)));
177
-		} elseif ($this->isGetterForBoolProperty($methodName)) {
178
-			return $this->getter(lcfirst(substr($methodName, 2)));
179
-		} else {
180
-			throw new \BadFunctionCallException($methodName
181
-				. ' does not exist');
182
-		}
183
-	}
184
-
185
-	/**
186
-	 * @param string $methodName
187
-	 * @return bool
188
-	 * @since 18.0.0
189
-	 */
190
-	protected function isGetterForBoolProperty(string $methodName): bool {
191
-		if (str_starts_with($methodName, 'is')) {
192
-			$fieldName = lcfirst(substr($methodName, 2));
193
-			return isset($this->_fieldTypes[$fieldName]) && str_starts_with($this->_fieldTypes[$fieldName], 'bool');
194
-		}
195
-		return false;
196
-	}
197
-
198
-	/**
199
-	 * Mark am attribute as updated
200
-	 * @param string $attribute the name of the attribute
201
-	 * @since 7.0.0
202
-	 */
203
-	protected function markFieldUpdated(string $attribute): void {
204
-		$this->_updatedFields[$attribute] = true;
205
-	}
206
-
207
-
208
-	/**
209
-	 * Transform a database columnname to a property
210
-	 *
211
-	 * @param string $columnName the name of the column
212
-	 * @return string the property name
213
-	 * @since 7.0.0
214
-	 */
215
-	public function columnToProperty(string $columnName) {
216
-		$parts = explode('_', $columnName);
217
-		$property = '';
218
-
219
-		foreach ($parts as $part) {
220
-			if ($property === '') {
221
-				$property = $part;
222
-			} else {
223
-				$property .= ucfirst($part);
224
-			}
225
-		}
226
-
227
-		return $property;
228
-	}
229
-
230
-
231
-	/**
232
-	 * Transform a property to a database column name
233
-	 *
234
-	 * @param string $property the name of the property
235
-	 * @return string the column name
236
-	 * @since 7.0.0
237
-	 */
238
-	public function propertyToColumn(string $property): string {
239
-		$parts = preg_split('/(?=[A-Z])/', $property);
240
-
241
-		$column = '';
242
-		foreach ($parts as $part) {
243
-			if ($column === '') {
244
-				$column = $part;
245
-			} else {
246
-				$column .= '_' . lcfirst($part);
247
-			}
248
-		}
249
-
250
-		return $column;
251
-	}
252
-
253
-
254
-	/**
255
-	 * @return array<string, true> array of updated fields for update query
256
-	 * @since 7.0.0
257
-	 */
258
-	public function getUpdatedFields(): array {
259
-		return $this->_updatedFields;
260
-	}
261
-
262
-
263
-	/**
264
-	 * Adds type information for a field so that it's automatically cast to
265
-	 * that value once its being returned from the database
266
-	 *
267
-	 * @param string $fieldName the name of the attribute
268
-	 * @param Types::* $type the type which will be used to match a cast
269
-	 * @since 31.0.0 Parameter $type is now restricted to {@see Types} constants. The formerly accidentally supported types 'int'|'bool'|'double' are mapped to Types::INTEGER|Types::BOOLEAN|Types::FLOAT accordingly.
270
-	 * @since 7.0.0
271
-	 */
272
-	protected function addType(string $fieldName, string $type): void {
273
-		/** @psalm-suppress TypeDoesNotContainType */
274
-		if (in_array($type, ['bool', 'double', 'int', 'array', 'object'], true)) {
275
-			// Mapping legacy strings to the actual types
276
-			$type = match ($type) {
277
-				'int' => Types::INTEGER,
278
-				'bool' => Types::BOOLEAN,
279
-				'double' => Types::FLOAT,
280
-				'array',
281
-				'object' => Types::STRING,
282
-			};
283
-		}
284
-
285
-		$this->_fieldTypes[$fieldName] = $type;
286
-	}
287
-
288
-
289
-	/**
290
-	 * Slugify the value of a given attribute
291
-	 * Warning: This doesn't result in a unique value
292
-	 *
293
-	 * @param string $attributeName the name of the attribute, which value should be slugified
294
-	 * @return string slugified value
295
-	 * @since 7.0.0
296
-	 * @deprecated 24.0.0
297
-	 */
298
-	public function slugify(string $attributeName): string {
299
-		// toSlug should only work for existing attributes
300
-		if (property_exists($this, $attributeName)) {
301
-			$value = $this->$attributeName;
302
-			// replace everything except alphanumeric with a single '-'
303
-			$value = preg_replace('/[^A-Za-z0-9]+/', '-', $value);
304
-			$value = strtolower($value);
305
-			// trim '-'
306
-			return trim($value, '-');
307
-		}
308
-
309
-		throw new \BadFunctionCallException($attributeName . ' is not a valid attribute');
310
-	}
22
+    /** @var int $id */
23
+    public $id;
24
+    /** @var array<string, true> $_updatedFields */
25
+    private array $_updatedFields = [];
26
+    /** @var array<string, Types::*> $_fieldTypes */
27
+    protected array $_fieldTypes = ['id' => 'integer'];
28
+
29
+    /**
30
+     * Simple alternative constructor for building entities from a request
31
+     * @param array $params the array which was obtained via $this->params('key')
32
+     *                      in the controller
33
+     * @since 7.0.0
34
+     */
35
+    public static function fromParams(array $params): static {
36
+        $instance = new static();
37
+
38
+        foreach ($params as $key => $value) {
39
+            $method = 'set' . ucfirst($key);
40
+            $instance->$method($value);
41
+        }
42
+
43
+        return $instance;
44
+    }
45
+
46
+    /**
47
+     * Maps the keys of the row array to the attributes
48
+     * @param array $row the row to map onto the entity
49
+     * @since 7.0.0
50
+     */
51
+    public static function fromRow(array $row): static {
52
+        $instance = new static();
53
+
54
+        foreach ($row as $key => $value) {
55
+            $prop = $instance->columnToProperty($key);
56
+            $instance->setter($prop, [$value]);
57
+        }
58
+
59
+        $instance->resetUpdatedFields();
60
+
61
+        return $instance;
62
+    }
63
+
64
+
65
+    /**
66
+     * @return array<string, Types::*> with attribute and type
67
+     * @since 7.0.0
68
+     */
69
+    public function getFieldTypes(): array {
70
+        return $this->_fieldTypes;
71
+    }
72
+
73
+
74
+    /**
75
+     * Marks the entity as clean needed for setting the id after the insertion
76
+     * @since 7.0.0
77
+     */
78
+    public function resetUpdatedFields(): void {
79
+        $this->_updatedFields = [];
80
+    }
81
+
82
+    /**
83
+     * Generic setter for properties
84
+     *
85
+     * @throws \InvalidArgumentException
86
+     * @since 7.0.0
87
+     *
88
+     */
89
+    protected function setter(string $name, array $args): void {
90
+        // setters should only work for existing attributes
91
+        if (!property_exists($this, $name)) {
92
+            throw new \BadFunctionCallException($name . ' is not a valid attribute');
93
+        }
94
+
95
+        if ($args[0] === $this->$name) {
96
+            return;
97
+        }
98
+        $this->markFieldUpdated($name);
99
+
100
+        // if type definition exists, cast to correct type
101
+        if ($args[0] !== null && array_key_exists($name, $this->_fieldTypes)) {
102
+            $type = $this->_fieldTypes[$name];
103
+            if ($type === Types::BLOB) {
104
+                // (B)LOB is treated as string when we read from the DB
105
+                if (is_resource($args[0])) {
106
+                    $args[0] = stream_get_contents($args[0]);
107
+                }
108
+                $type = Types::STRING;
109
+            }
110
+
111
+            switch ($type) {
112
+                case Types::BIGINT:
113
+                case Types::SMALLINT:
114
+                    settype($args[0], Types::INTEGER);
115
+                    break;
116
+                case Types::BINARY:
117
+                case Types::DECIMAL:
118
+                case Types::TEXT:
119
+                    settype($args[0], Types::STRING);
120
+                    break;
121
+                case Types::TIME:
122
+                case Types::DATE:
123
+                case Types::DATETIME:
124
+                case Types::DATETIME_TZ:
125
+                    if (!$args[0] instanceof \DateTime) {
126
+                        $args[0] = new \DateTime($args[0]);
127
+                    }
128
+                    break;
129
+                case Types::TIME_IMMUTABLE:
130
+                case Types::DATE_IMMUTABLE:
131
+                case Types::DATETIME_IMMUTABLE:
132
+                case Types::DATETIME_TZ_IMMUTABLE:
133
+                    if (!$args[0] instanceof \DateTimeImmutable) {
134
+                        $args[0] = new \DateTimeImmutable($args[0]);
135
+                    }
136
+                    break;
137
+                case Types::JSON:
138
+                    if (!is_array($args[0])) {
139
+                        $args[0] = json_decode($args[0], true);
140
+                    }
141
+                    break;
142
+                default:
143
+                    settype($args[0], $type);
144
+            }
145
+        }
146
+        $this->$name = $args[0];
147
+
148
+    }
149
+
150
+    /**
151
+     * Generic getter for properties
152
+     * @since 7.0.0
153
+     */
154
+    protected function getter(string $name): mixed {
155
+        // getters should only work for existing attributes
156
+        if (property_exists($this, $name)) {
157
+            return $this->$name;
158
+        } else {
159
+            throw new \BadFunctionCallException($name
160
+                . ' is not a valid attribute');
161
+        }
162
+    }
163
+
164
+
165
+    /**
166
+     * Each time a setter is called, push the part after set
167
+     * into an array: for instance setId will save Id in the
168
+     * updated fields array so it can be easily used to create the
169
+     * getter method
170
+     * @since 7.0.0
171
+     */
172
+    public function __call(string $methodName, array $args) {
173
+        if (str_starts_with($methodName, 'set')) {
174
+            $this->setter(lcfirst(substr($methodName, 3)), $args);
175
+        } elseif (str_starts_with($methodName, 'get')) {
176
+            return $this->getter(lcfirst(substr($methodName, 3)));
177
+        } elseif ($this->isGetterForBoolProperty($methodName)) {
178
+            return $this->getter(lcfirst(substr($methodName, 2)));
179
+        } else {
180
+            throw new \BadFunctionCallException($methodName
181
+                . ' does not exist');
182
+        }
183
+    }
184
+
185
+    /**
186
+     * @param string $methodName
187
+     * @return bool
188
+     * @since 18.0.0
189
+     */
190
+    protected function isGetterForBoolProperty(string $methodName): bool {
191
+        if (str_starts_with($methodName, 'is')) {
192
+            $fieldName = lcfirst(substr($methodName, 2));
193
+            return isset($this->_fieldTypes[$fieldName]) && str_starts_with($this->_fieldTypes[$fieldName], 'bool');
194
+        }
195
+        return false;
196
+    }
197
+
198
+    /**
199
+     * Mark am attribute as updated
200
+     * @param string $attribute the name of the attribute
201
+     * @since 7.0.0
202
+     */
203
+    protected function markFieldUpdated(string $attribute): void {
204
+        $this->_updatedFields[$attribute] = true;
205
+    }
206
+
207
+
208
+    /**
209
+     * Transform a database columnname to a property
210
+     *
211
+     * @param string $columnName the name of the column
212
+     * @return string the property name
213
+     * @since 7.0.0
214
+     */
215
+    public function columnToProperty(string $columnName) {
216
+        $parts = explode('_', $columnName);
217
+        $property = '';
218
+
219
+        foreach ($parts as $part) {
220
+            if ($property === '') {
221
+                $property = $part;
222
+            } else {
223
+                $property .= ucfirst($part);
224
+            }
225
+        }
226
+
227
+        return $property;
228
+    }
229
+
230
+
231
+    /**
232
+     * Transform a property to a database column name
233
+     *
234
+     * @param string $property the name of the property
235
+     * @return string the column name
236
+     * @since 7.0.0
237
+     */
238
+    public function propertyToColumn(string $property): string {
239
+        $parts = preg_split('/(?=[A-Z])/', $property);
240
+
241
+        $column = '';
242
+        foreach ($parts as $part) {
243
+            if ($column === '') {
244
+                $column = $part;
245
+            } else {
246
+                $column .= '_' . lcfirst($part);
247
+            }
248
+        }
249
+
250
+        return $column;
251
+    }
252
+
253
+
254
+    /**
255
+     * @return array<string, true> array of updated fields for update query
256
+     * @since 7.0.0
257
+     */
258
+    public function getUpdatedFields(): array {
259
+        return $this->_updatedFields;
260
+    }
261
+
262
+
263
+    /**
264
+     * Adds type information for a field so that it's automatically cast to
265
+     * that value once its being returned from the database
266
+     *
267
+     * @param string $fieldName the name of the attribute
268
+     * @param Types::* $type the type which will be used to match a cast
269
+     * @since 31.0.0 Parameter $type is now restricted to {@see Types} constants. The formerly accidentally supported types 'int'|'bool'|'double' are mapped to Types::INTEGER|Types::BOOLEAN|Types::FLOAT accordingly.
270
+     * @since 7.0.0
271
+     */
272
+    protected function addType(string $fieldName, string $type): void {
273
+        /** @psalm-suppress TypeDoesNotContainType */
274
+        if (in_array($type, ['bool', 'double', 'int', 'array', 'object'], true)) {
275
+            // Mapping legacy strings to the actual types
276
+            $type = match ($type) {
277
+                'int' => Types::INTEGER,
278
+                'bool' => Types::BOOLEAN,
279
+                'double' => Types::FLOAT,
280
+                'array',
281
+                'object' => Types::STRING,
282
+            };
283
+        }
284
+
285
+        $this->_fieldTypes[$fieldName] = $type;
286
+    }
287
+
288
+
289
+    /**
290
+     * Slugify the value of a given attribute
291
+     * Warning: This doesn't result in a unique value
292
+     *
293
+     * @param string $attributeName the name of the attribute, which value should be slugified
294
+     * @return string slugified value
295
+     * @since 7.0.0
296
+     * @deprecated 24.0.0
297
+     */
298
+    public function slugify(string $attributeName): string {
299
+        // toSlug should only work for existing attributes
300
+        if (property_exists($this, $attributeName)) {
301
+            $value = $this->$attributeName;
302
+            // replace everything except alphanumeric with a single '-'
303
+            $value = preg_replace('/[^A-Za-z0-9]+/', '-', $value);
304
+            $value = strtolower($value);
305
+            // trim '-'
306
+            return trim($value, '-');
307
+        }
308
+
309
+        throw new \BadFunctionCallException($attributeName . ' is not a valid attribute');
310
+    }
311 311
 }
Please login to merge, or discard this patch.