Passed
Push — master ( 8b0ce8...222ac9 )
by Daniel
13:52 queued 12s
created
lib/public/AppFramework/Db/QBMapper.php 1 patch
Indentation   +316 added lines, -316 removed lines patch added patch discarded remove patch
@@ -44,320 +44,320 @@
 block discarded – undo
44 44
  */
45 45
 abstract class QBMapper {
46 46
 
47
-	/** @var string */
48
-	protected $tableName;
49
-
50
-	/** @var string|class-string<T> */
51
-	protected $entityClass;
52
-
53
-	/** @var IDBConnection */
54
-	protected $db;
55
-
56
-	/**
57
-	 * @param IDBConnection $db Instance of the Db abstraction layer
58
-	 * @param string $tableName the name of the table. set this to allow entity
59
-	 * @param string|null $entityClass the name of the entity that the sql should be
60
-	 * @psalm-param class-string<T>|null $entityClass the name of the entity that the sql should be
61
-	 * mapped to queries without using sql
62
-	 * @since 14.0.0
63
-	 */
64
-	public function __construct(IDBConnection $db, string $tableName, string $entityClass = null) {
65
-		$this->db = $db;
66
-		$this->tableName = $tableName;
67
-
68
-		// if not given set the entity name to the class without the mapper part
69
-		// cache it here for later use since reflection is slow
70
-		if ($entityClass === null) {
71
-			$this->entityClass = str_replace('Mapper', '', \get_class($this));
72
-		} else {
73
-			$this->entityClass = $entityClass;
74
-		}
75
-	}
76
-
77
-
78
-	/**
79
-	 * @return string the table name
80
-	 * @since 14.0.0
81
-	 */
82
-	public function getTableName(): string {
83
-		return $this->tableName;
84
-	}
85
-
86
-
87
-	/**
88
-	 * Deletes an entity from the table
89
-	 *
90
-	 * @param Entity $entity the entity that should be deleted
91
-	 * @psalm-param T $entity the entity that should be deleted
92
-	 * @return Entity the deleted entity
93
-	 * @psalm-return T the deleted entity
94
-	 * @throws Exception
95
-	 * @since 14.0.0
96
-	 */
97
-	public function delete(Entity $entity): Entity {
98
-		$qb = $this->db->getQueryBuilder();
99
-
100
-		$idType = $this->getParameterTypeForProperty($entity, 'id');
101
-
102
-		$qb->delete($this->tableName)
103
-			->where(
104
-				$qb->expr()->eq('id', $qb->createNamedParameter($entity->getId(), $idType))
105
-			);
106
-		$qb->executeStatement();
107
-		return $entity;
108
-	}
109
-
110
-
111
-	/**
112
-	 * Creates a new entry in the db from an entity
113
-	 *
114
-	 * @param Entity $entity the entity that should be created
115
-	 * @psalm-param T $entity the entity that should be created
116
-	 * @return Entity the saved entity with the set id
117
-	 * @psalm-return T the saved entity with the set id
118
-	 * @throws Exception
119
-	 * @since 14.0.0
120
-	 */
121
-	public function insert(Entity $entity): Entity {
122
-		// get updated fields to save, fields have to be set using a setter to
123
-		// be saved
124
-		$properties = $entity->getUpdatedFields();
125
-
126
-		$qb = $this->db->getQueryBuilder();
127
-		$qb->insert($this->tableName);
128
-
129
-		// build the fields
130
-		foreach ($properties as $property => $updated) {
131
-			$column = $entity->propertyToColumn($property);
132
-			$getter = 'get' . ucfirst($property);
133
-			$value = $entity->$getter();
134
-
135
-			$type = $this->getParameterTypeForProperty($entity, $property);
136
-			$qb->setValue($column, $qb->createNamedParameter($value, $type));
137
-		}
138
-
139
-		$qb->executeStatement();
140
-
141
-		if ($entity->id === null) {
142
-			// When autoincrement is used id is always an int
143
-			$entity->setId($qb->getLastInsertId());
144
-		}
145
-
146
-		return $entity;
147
-	}
148
-
149
-	/**
150
-	 * Tries to creates a new entry in the db from an entity and
151
-	 * updates an existing entry if duplicate keys are detected
152
-	 * by the database
153
-	 *
154
-	 * @param Entity $entity the entity that should be created/updated
155
-	 * @psalm-param T $entity the entity that should be created/updated
156
-	 * @return Entity the saved entity with the (new) id
157
-	 * @psalm-return T the saved entity with the (new) id
158
-	 * @throws Exception
159
-	 * @throws \InvalidArgumentException if entity has no id
160
-	 * @since 15.0.0
161
-	 */
162
-	public function insertOrUpdate(Entity $entity): Entity {
163
-		try {
164
-			return $this->insert($entity);
165
-		} catch (Exception $ex) {
166
-			if ($ex->getReason() === Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) {
167
-				return $this->update($entity);
168
-			}
169
-			throw $ex;
170
-		}
171
-	}
172
-
173
-	/**
174
-	 * Updates an entry in the db from an entity
175
-	 *
176
-	 * @param Entity $entity the entity that should be created
177
-	 * @psalm-param T $entity the entity that should be created
178
-	 * @return Entity the saved entity with the set id
179
-	 * @psalm-return T the saved entity with the set id
180
-	 * @throws Exception
181
-	 * @throws \InvalidArgumentException if entity has no id
182
-	 * @since 14.0.0
183
-	 */
184
-	public function update(Entity $entity): Entity {
185
-		// if entity wasn't changed it makes no sense to run a db query
186
-		$properties = $entity->getUpdatedFields();
187
-		if (\count($properties) === 0) {
188
-			return $entity;
189
-		}
190
-
191
-		// entity needs an id
192
-		$id = $entity->getId();
193
-		if ($id === null) {
194
-			throw new \InvalidArgumentException(
195
-				'Entity which should be updated has no id');
196
-		}
197
-
198
-		// get updated fields to save, fields have to be set using a setter to
199
-		// be saved
200
-		// do not update the id field
201
-		unset($properties['id']);
202
-
203
-		$qb = $this->db->getQueryBuilder();
204
-		$qb->update($this->tableName);
205
-
206
-		// build the fields
207
-		foreach ($properties as $property => $updated) {
208
-			$column = $entity->propertyToColumn($property);
209
-			$getter = 'get' . ucfirst($property);
210
-			$value = $entity->$getter();
211
-
212
-			$type = $this->getParameterTypeForProperty($entity, $property);
213
-			$qb->set($column, $qb->createNamedParameter($value, $type));
214
-		}
215
-
216
-		$idType = $this->getParameterTypeForProperty($entity, 'id');
217
-
218
-		$qb->where(
219
-			$qb->expr()->eq('id', $qb->createNamedParameter($id, $idType))
220
-		);
221
-		$qb->executeStatement();
222
-
223
-		return $entity;
224
-	}
225
-
226
-	/**
227
-	 * Returns the type parameter for the QueryBuilder for a specific property
228
-	 * of the $entity
229
-	 *
230
-	 * @param Entity $entity   The entity to get the types from
231
-	 * @psalm-param T $entity
232
-	 * @param string $property The property of $entity to get the type for
233
-	 * @return int|string
234
-	 * @since 16.0.0
235
-	 */
236
-	protected function getParameterTypeForProperty(Entity $entity, string $property) {
237
-		$types = $entity->getFieldTypes();
238
-
239
-		if (!isset($types[ $property ])) {
240
-			return IQueryBuilder::PARAM_STR;
241
-		}
242
-
243
-		switch ($types[ $property ]) {
244
-			case 'int':
245
-			case 'integer':
246
-				return IQueryBuilder::PARAM_INT;
247
-			case 'string':
248
-				return IQueryBuilder::PARAM_STR;
249
-			case 'bool':
250
-			case 'boolean':
251
-				return IQueryBuilder::PARAM_BOOL;
252
-			case 'blob':
253
-				return IQueryBuilder::PARAM_LOB;
254
-			case 'datetime':
255
-				return IQueryBuilder::PARAM_DATE;
256
-		}
257
-
258
-		return IQueryBuilder::PARAM_STR;
259
-	}
260
-
261
-	/**
262
-	 * Returns an db result and throws exceptions when there are more or less
263
-	 * results
264
-	 *
265
-	 * @param IQueryBuilder $query
266
-	 * @return array the result as row
267
-	 * @throws Exception
268
-	 * @throws MultipleObjectsReturnedException if more than one item exist
269
-	 * @throws DoesNotExistException if the item does not exist
270
-	 * @see findEntity
271
-	 *
272
-	 * @since 14.0.0
273
-	 */
274
-	protected function findOneQuery(IQueryBuilder $query): array {
275
-		$result = $query->executeQuery();
276
-
277
-		$row = $result->fetch();
278
-		if ($row === false) {
279
-			$result->closeCursor();
280
-			$msg = $this->buildDebugMessage(
281
-				'Did expect one result but found none when executing', $query
282
-			);
283
-			throw new DoesNotExistException($msg);
284
-		}
285
-
286
-		$row2 = $result->fetch();
287
-		$result->closeCursor();
288
-		if ($row2 !== false) {
289
-			$msg = $this->buildDebugMessage(
290
-				'Did not expect more than one result when executing', $query
291
-			);
292
-			throw new MultipleObjectsReturnedException($msg);
293
-		}
294
-
295
-		return $row;
296
-	}
297
-
298
-	/**
299
-	 * @param string $msg
300
-	 * @param IQueryBuilder $sql
301
-	 * @return string
302
-	 * @since 14.0.0
303
-	 */
304
-	private function buildDebugMessage(string $msg, IQueryBuilder $sql): string {
305
-		return $msg .
306
-			': query "' . $sql->getSQL() . '"; ';
307
-	}
308
-
309
-
310
-	/**
311
-	 * Creates an entity from a row. Automatically determines the entity class
312
-	 * from the current mapper name (MyEntityMapper -> MyEntity)
313
-	 *
314
-	 * @param array $row the row which should be converted to an entity
315
-	 * @return Entity the entity
316
-	 * @psalm-return T the entity
317
-	 * @since 14.0.0
318
-	 */
319
-	protected function mapRowToEntity(array $row): Entity {
320
-		return \call_user_func($this->entityClass .'::fromRow', $row);
321
-	}
322
-
323
-
324
-	/**
325
-	 * Runs a sql query and returns an array of entities
326
-	 *
327
-	 * @param IQueryBuilder $query
328
-	 * @return Entity[] all fetched entities
329
-	 * @psalm-return T[] all fetched entities
330
-	 * @throws Exception
331
-	 * @since 14.0.0
332
-	 */
333
-	protected function findEntities(IQueryBuilder $query): array {
334
-		$result = $query->executeQuery();
335
-
336
-		$entities = [];
337
-
338
-		while ($row = $result->fetch()) {
339
-			$entities[] = $this->mapRowToEntity($row);
340
-		}
341
-
342
-		$result->closeCursor();
343
-
344
-		return $entities;
345
-	}
346
-
347
-
348
-	/**
349
-	 * Returns an db result and throws exceptions when there are more or less
350
-	 * results
351
-	 *
352
-	 * @param IQueryBuilder $query
353
-	 * @return Entity the entity
354
-	 * @psalm-return T the entity
355
-	 * @throws Exception
356
-	 * @throws MultipleObjectsReturnedException if more than one item exist
357
-	 * @throws DoesNotExistException if the item does not exist
358
-	 * @since 14.0.0
359
-	 */
360
-	protected function findEntity(IQueryBuilder $query): Entity {
361
-		return $this->mapRowToEntity($this->findOneQuery($query));
362
-	}
47
+    /** @var string */
48
+    protected $tableName;
49
+
50
+    /** @var string|class-string<T> */
51
+    protected $entityClass;
52
+
53
+    /** @var IDBConnection */
54
+    protected $db;
55
+
56
+    /**
57
+     * @param IDBConnection $db Instance of the Db abstraction layer
58
+     * @param string $tableName the name of the table. set this to allow entity
59
+     * @param string|null $entityClass the name of the entity that the sql should be
60
+     * @psalm-param class-string<T>|null $entityClass the name of the entity that the sql should be
61
+     * mapped to queries without using sql
62
+     * @since 14.0.0
63
+     */
64
+    public function __construct(IDBConnection $db, string $tableName, string $entityClass = null) {
65
+        $this->db = $db;
66
+        $this->tableName = $tableName;
67
+
68
+        // if not given set the entity name to the class without the mapper part
69
+        // cache it here for later use since reflection is slow
70
+        if ($entityClass === null) {
71
+            $this->entityClass = str_replace('Mapper', '', \get_class($this));
72
+        } else {
73
+            $this->entityClass = $entityClass;
74
+        }
75
+    }
76
+
77
+
78
+    /**
79
+     * @return string the table name
80
+     * @since 14.0.0
81
+     */
82
+    public function getTableName(): string {
83
+        return $this->tableName;
84
+    }
85
+
86
+
87
+    /**
88
+     * Deletes an entity from the table
89
+     *
90
+     * @param Entity $entity the entity that should be deleted
91
+     * @psalm-param T $entity the entity that should be deleted
92
+     * @return Entity the deleted entity
93
+     * @psalm-return T the deleted entity
94
+     * @throws Exception
95
+     * @since 14.0.0
96
+     */
97
+    public function delete(Entity $entity): Entity {
98
+        $qb = $this->db->getQueryBuilder();
99
+
100
+        $idType = $this->getParameterTypeForProperty($entity, 'id');
101
+
102
+        $qb->delete($this->tableName)
103
+            ->where(
104
+                $qb->expr()->eq('id', $qb->createNamedParameter($entity->getId(), $idType))
105
+            );
106
+        $qb->executeStatement();
107
+        return $entity;
108
+    }
109
+
110
+
111
+    /**
112
+     * Creates a new entry in the db from an entity
113
+     *
114
+     * @param Entity $entity the entity that should be created
115
+     * @psalm-param T $entity the entity that should be created
116
+     * @return Entity the saved entity with the set id
117
+     * @psalm-return T the saved entity with the set id
118
+     * @throws Exception
119
+     * @since 14.0.0
120
+     */
121
+    public function insert(Entity $entity): Entity {
122
+        // get updated fields to save, fields have to be set using a setter to
123
+        // be saved
124
+        $properties = $entity->getUpdatedFields();
125
+
126
+        $qb = $this->db->getQueryBuilder();
127
+        $qb->insert($this->tableName);
128
+
129
+        // build the fields
130
+        foreach ($properties as $property => $updated) {
131
+            $column = $entity->propertyToColumn($property);
132
+            $getter = 'get' . ucfirst($property);
133
+            $value = $entity->$getter();
134
+
135
+            $type = $this->getParameterTypeForProperty($entity, $property);
136
+            $qb->setValue($column, $qb->createNamedParameter($value, $type));
137
+        }
138
+
139
+        $qb->executeStatement();
140
+
141
+        if ($entity->id === null) {
142
+            // When autoincrement is used id is always an int
143
+            $entity->setId($qb->getLastInsertId());
144
+        }
145
+
146
+        return $entity;
147
+    }
148
+
149
+    /**
150
+     * Tries to creates a new entry in the db from an entity and
151
+     * updates an existing entry if duplicate keys are detected
152
+     * by the database
153
+     *
154
+     * @param Entity $entity the entity that should be created/updated
155
+     * @psalm-param T $entity the entity that should be created/updated
156
+     * @return Entity the saved entity with the (new) id
157
+     * @psalm-return T the saved entity with the (new) id
158
+     * @throws Exception
159
+     * @throws \InvalidArgumentException if entity has no id
160
+     * @since 15.0.0
161
+     */
162
+    public function insertOrUpdate(Entity $entity): Entity {
163
+        try {
164
+            return $this->insert($entity);
165
+        } catch (Exception $ex) {
166
+            if ($ex->getReason() === Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) {
167
+                return $this->update($entity);
168
+            }
169
+            throw $ex;
170
+        }
171
+    }
172
+
173
+    /**
174
+     * Updates an entry in the db from an entity
175
+     *
176
+     * @param Entity $entity the entity that should be created
177
+     * @psalm-param T $entity the entity that should be created
178
+     * @return Entity the saved entity with the set id
179
+     * @psalm-return T the saved entity with the set id
180
+     * @throws Exception
181
+     * @throws \InvalidArgumentException if entity has no id
182
+     * @since 14.0.0
183
+     */
184
+    public function update(Entity $entity): Entity {
185
+        // if entity wasn't changed it makes no sense to run a db query
186
+        $properties = $entity->getUpdatedFields();
187
+        if (\count($properties) === 0) {
188
+            return $entity;
189
+        }
190
+
191
+        // entity needs an id
192
+        $id = $entity->getId();
193
+        if ($id === null) {
194
+            throw new \InvalidArgumentException(
195
+                'Entity which should be updated has no id');
196
+        }
197
+
198
+        // get updated fields to save, fields have to be set using a setter to
199
+        // be saved
200
+        // do not update the id field
201
+        unset($properties['id']);
202
+
203
+        $qb = $this->db->getQueryBuilder();
204
+        $qb->update($this->tableName);
205
+
206
+        // build the fields
207
+        foreach ($properties as $property => $updated) {
208
+            $column = $entity->propertyToColumn($property);
209
+            $getter = 'get' . ucfirst($property);
210
+            $value = $entity->$getter();
211
+
212
+            $type = $this->getParameterTypeForProperty($entity, $property);
213
+            $qb->set($column, $qb->createNamedParameter($value, $type));
214
+        }
215
+
216
+        $idType = $this->getParameterTypeForProperty($entity, 'id');
217
+
218
+        $qb->where(
219
+            $qb->expr()->eq('id', $qb->createNamedParameter($id, $idType))
220
+        );
221
+        $qb->executeStatement();
222
+
223
+        return $entity;
224
+    }
225
+
226
+    /**
227
+     * Returns the type parameter for the QueryBuilder for a specific property
228
+     * of the $entity
229
+     *
230
+     * @param Entity $entity   The entity to get the types from
231
+     * @psalm-param T $entity
232
+     * @param string $property The property of $entity to get the type for
233
+     * @return int|string
234
+     * @since 16.0.0
235
+     */
236
+    protected function getParameterTypeForProperty(Entity $entity, string $property) {
237
+        $types = $entity->getFieldTypes();
238
+
239
+        if (!isset($types[ $property ])) {
240
+            return IQueryBuilder::PARAM_STR;
241
+        }
242
+
243
+        switch ($types[ $property ]) {
244
+            case 'int':
245
+            case 'integer':
246
+                return IQueryBuilder::PARAM_INT;
247
+            case 'string':
248
+                return IQueryBuilder::PARAM_STR;
249
+            case 'bool':
250
+            case 'boolean':
251
+                return IQueryBuilder::PARAM_BOOL;
252
+            case 'blob':
253
+                return IQueryBuilder::PARAM_LOB;
254
+            case 'datetime':
255
+                return IQueryBuilder::PARAM_DATE;
256
+        }
257
+
258
+        return IQueryBuilder::PARAM_STR;
259
+    }
260
+
261
+    /**
262
+     * Returns an db result and throws exceptions when there are more or less
263
+     * results
264
+     *
265
+     * @param IQueryBuilder $query
266
+     * @return array the result as row
267
+     * @throws Exception
268
+     * @throws MultipleObjectsReturnedException if more than one item exist
269
+     * @throws DoesNotExistException if the item does not exist
270
+     * @see findEntity
271
+     *
272
+     * @since 14.0.0
273
+     */
274
+    protected function findOneQuery(IQueryBuilder $query): array {
275
+        $result = $query->executeQuery();
276
+
277
+        $row = $result->fetch();
278
+        if ($row === false) {
279
+            $result->closeCursor();
280
+            $msg = $this->buildDebugMessage(
281
+                'Did expect one result but found none when executing', $query
282
+            );
283
+            throw new DoesNotExistException($msg);
284
+        }
285
+
286
+        $row2 = $result->fetch();
287
+        $result->closeCursor();
288
+        if ($row2 !== false) {
289
+            $msg = $this->buildDebugMessage(
290
+                'Did not expect more than one result when executing', $query
291
+            );
292
+            throw new MultipleObjectsReturnedException($msg);
293
+        }
294
+
295
+        return $row;
296
+    }
297
+
298
+    /**
299
+     * @param string $msg
300
+     * @param IQueryBuilder $sql
301
+     * @return string
302
+     * @since 14.0.0
303
+     */
304
+    private function buildDebugMessage(string $msg, IQueryBuilder $sql): string {
305
+        return $msg .
306
+            ': query "' . $sql->getSQL() . '"; ';
307
+    }
308
+
309
+
310
+    /**
311
+     * Creates an entity from a row. Automatically determines the entity class
312
+     * from the current mapper name (MyEntityMapper -> MyEntity)
313
+     *
314
+     * @param array $row the row which should be converted to an entity
315
+     * @return Entity the entity
316
+     * @psalm-return T the entity
317
+     * @since 14.0.0
318
+     */
319
+    protected function mapRowToEntity(array $row): Entity {
320
+        return \call_user_func($this->entityClass .'::fromRow', $row);
321
+    }
322
+
323
+
324
+    /**
325
+     * Runs a sql query and returns an array of entities
326
+     *
327
+     * @param IQueryBuilder $query
328
+     * @return Entity[] all fetched entities
329
+     * @psalm-return T[] all fetched entities
330
+     * @throws Exception
331
+     * @since 14.0.0
332
+     */
333
+    protected function findEntities(IQueryBuilder $query): array {
334
+        $result = $query->executeQuery();
335
+
336
+        $entities = [];
337
+
338
+        while ($row = $result->fetch()) {
339
+            $entities[] = $this->mapRowToEntity($row);
340
+        }
341
+
342
+        $result->closeCursor();
343
+
344
+        return $entities;
345
+    }
346
+
347
+
348
+    /**
349
+     * Returns an db result and throws exceptions when there are more or less
350
+     * results
351
+     *
352
+     * @param IQueryBuilder $query
353
+     * @return Entity the entity
354
+     * @psalm-return T the entity
355
+     * @throws Exception
356
+     * @throws MultipleObjectsReturnedException if more than one item exist
357
+     * @throws DoesNotExistException if the item does not exist
358
+     * @since 14.0.0
359
+     */
360
+    protected function findEntity(IQueryBuilder $query): Entity {
361
+        return $this->mapRowToEntity($this->findOneQuery($query));
362
+    }
363 363
 }
Please login to merge, or discard this patch.