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