Issues (125)

lib/Db/ImageMapper.php (14 issues)

1
<?php
2
/**
3
 * @copyright Copyright (c) 2017-2020, Matias De lellis <[email protected]>
4
 * @copyright Copyright (c) 2018-2019, Branko Kokanovic <[email protected]>
5
 *
6
 * @author Branko Kokanovic <[email protected]>
7
 *
8
 * @license GNU AGPL version 3 or any later version
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License as
12
 * published by the Free Software Foundation, either version 3 of the
13
 * License, or (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU Affero General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Affero General Public License
21
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 *
23
 */
24
namespace OCA\FaceRecognition\Db;
25
26
use OCP\IDBConnection;
27
use OCP\IUser;
28
29
use OCP\AppFramework\Db\QBMapper;
30
use OCP\AppFramework\Db\DoesNotExistException;
31
use OCP\DB\QueryBuilder\IQueryBuilder;
32
33
class ImageMapper extends QBMapper {
34
	/** @var FaceMapper Face mapper*/
35
	private $faceMapper;
36
37 1
	public function __construct(IDBConnection $db, FaceMapper $faceMapper) {
38 1
		parent::__construct($db, 'facerecog_images', '\OCA\FaceRecognition\Db\Image');
39 1
		$this->faceMapper = $faceMapper;
40
	}
41
42
	/**
43
	 * @param string $userId Id of user
44
	 * @param int $imageId Id of Image to get
45
	 *
46
	 */
47 4
	public function find(string $userId, int $imageId): ?Image {
48 4
		$qb = $this->db->getQueryBuilder();
49 4
		$qb->select('id', 'file', 'is_processed', 'error', 'last_processed_time', 'processing_duration')
50 4
			->from($this->getTableName(), 'i')
51 4
			->where($qb->expr()->eq('user', $qb->createNamedParameter($userId)))
52 4
			->andWhere($qb->expr()->eq('id', $qb->createNamedParameter($imageId)));
53
		try {
54 4
			return $this->findEntity($qb);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->findEntity($qb) returns the type OCP\AppFramework\Db\Entity which includes types incompatible with the type-hinted return OCA\FaceRecognition\Db\Image|null.
Loading history...
55
		} catch (DoesNotExistException $e) {
56
			return null;
57
		}
58
	}
59
60
	/**
61
	 * @param string $userId Id of user
62
	 * @param int $modelId Id of model to get
63
	 *
64
	 */
65
	public function findAll(string $userId, int $modelId): array {
66
		$qb = $this->db->getQueryBuilder();
67
		$qb->select('id', 'file', 'is_processed', 'error', 'last_processed_time', 'processing_duration')
68
			->from($this->getTableName())
69
			->where($qb->expr()->eq('user', $qb->createNamedParameter($userId)))
70
			->andWhere($qb->expr()->eq('model', $qb->createNamedParameter($modelId)));
71
		return $this->findEntities($qb);
72
	}
73
74
	/**
75
	 * @param string $userId Id of user
76
	 * @param int $modelId Id of model
77
	 * @param int $fileId Id of file to get Image
78
	 *
79
	 */
80
	public function findFromFile(string $userId, int $modelId, int $fileId): ?Image {
81
		$qb = $this->db->getQueryBuilder();
82
		$qb->select('id', 'is_processed', 'error')
83
			->from($this->getTableName(), 'i')
84
			->where($qb->expr()->eq('user', $qb->createNamedParameter($userId)))
85
			->andwhere($qb->expr()->eq('model', $qb->createNamedParameter($modelId)))
86
			->andWhere($qb->expr()->eq('file', $qb->createNamedParameter($fileId)));
87
88
		try {
89
			return $this->findEntity($qb);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->findEntity($qb) returns the type OCP\AppFramework\Db\Entity which includes types incompatible with the type-hinted return OCA\FaceRecognition\Db\Image|null.
Loading history...
90
		} catch (DoesNotExistException $e) {
91
			return null;
92
		}
93
	}
94
95 7
	public function imageExists(Image $image): ?int {
96 7
		$qb = $this->db->getQueryBuilder();
97 7
		$query = $qb
98 7
			->select(['id'])
99 7
			->from($this->getTableName())
100 7
			->where($qb->expr()->eq('user', $qb->createParameter('user')))
101 7
			->andWhere($qb->expr()->eq('file', $qb->createParameter('file')))
102 7
			->andWhere($qb->expr()->eq('model', $qb->createParameter('model')))
103 7
			->setParameter('user', $image->getUser())
104 7
			->setParameter('file', $image->getFile())
105 7
			->setParameter('model', $image->getModel());
106 7
		$resultStatement = $query->execute();
0 ignored issues
show
Deprecated Code introduced by
The function OCP\DB\QueryBuilder\IQueryBuilder::execute() has been deprecated: 22.0.0 Use executeQuery or executeStatement ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

106
		$resultStatement = /** @scrutinizer ignore-deprecated */ $query->execute();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
107 7
		$row = $resultStatement->fetch();
108 7
		$resultStatement->closeCursor();
109 7
		return $row ? (int)$row['id'] : null;
110
	}
111
112
	public function countImages(int $model): int {
113
		$qb = $this->db->getQueryBuilder();
114
		$query = $qb
115
			->select($qb->createFunction('COUNT(' . $qb->getColumnName('id') . ')'))
116
			->from($this->getTableName())
117
			->where($qb->expr()->eq('model', $qb->createParameter('model')))
118
			->setParameter('model', $model);
119
		$resultStatement = $query->execute();
0 ignored issues
show
Deprecated Code introduced by
The function OCP\DB\QueryBuilder\IQueryBuilder::execute() has been deprecated: 22.0.0 Use executeQuery or executeStatement ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

119
		$resultStatement = /** @scrutinizer ignore-deprecated */ $query->execute();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
120
		$data = $resultStatement->fetch(\PDO::FETCH_NUM);
121
		$resultStatement->closeCursor();
122
123
		return (int)$data[0];
124
	}
125
126
	public function countProcessedImages(int $model): int {
127
		$qb = $this->db->getQueryBuilder();
128
		$query = $qb
129
			->select($qb->createFunction('COUNT(' . $qb->getColumnName('id') . ')'))
130
			->from($this->getTableName())
131
			->where($qb->expr()->eq('model', $qb->createParameter('model')))
132
			->andWhere($qb->expr()->eq('is_processed', $qb->createParameter('is_processed')))
133
			->setParameter('model', $model)
134
			->setParameter('is_processed', True);
135
		$resultStatement = $query->execute();
0 ignored issues
show
Deprecated Code introduced by
The function OCP\DB\QueryBuilder\IQueryBuilder::execute() has been deprecated: 22.0.0 Use executeQuery or executeStatement ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

135
		$resultStatement = /** @scrutinizer ignore-deprecated */ $query->execute();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
136
		$data = $resultStatement->fetch(\PDO::FETCH_NUM);
137
		$resultStatement->closeCursor();
138
139
		return (int)$data[0];
140
	}
141
142
	public function avgProcessingDuration(int $model): int {
143
		$qb = $this->db->getQueryBuilder();
144
		$query = $qb
145
			->select($qb->createFunction('AVG(' . $qb->getColumnName('processing_duration') . ')'))
146
			->from($this->getTableName())
147
			->where($qb->expr()->eq('model', $qb->createParameter('model')))
148
			->andWhere($qb->expr()->eq('is_processed', $qb->createParameter('is_processed')))
149
			->setParameter('model', $model)
150
			->setParameter('is_processed', True);
151
		$resultStatement = $query->execute();
0 ignored issues
show
Deprecated Code introduced by
The function OCP\DB\QueryBuilder\IQueryBuilder::execute() has been deprecated: 22.0.0 Use executeQuery or executeStatement ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

151
		$resultStatement = /** @scrutinizer ignore-deprecated */ $query->execute();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
152
		$data = $resultStatement->fetch(\PDO::FETCH_NUM);
153
		$resultStatement->closeCursor();
154
155
		return (int)$data[0];
156
	}
157
158 3
	public function countUserImages(string $userId, int $model, bool $processed = false): int {
159 3
		$qb = $this->db->getQueryBuilder();
160 3
		$query = $qb
161 3
			->select($qb->createFunction('COUNT(' . $qb->getColumnName('id') . ')'))
162 3
			->from($this->getTableName())
163 3
			->where($qb->expr()->eq('user', $qb->createParameter('user')))
164 3
			->andWhere($qb->expr()->eq('model', $qb->createParameter('model')))
165 3
			->setParameter('user', $userId)
166 3
			->setParameter('model', $model);
167
168 3
		if ($processed) {
169 1
			$query->andWhere($qb->expr()->eq('is_processed', $qb->createParameter('is_processed')))
170 1
			      ->setParameter('is_processed', true);
171
		}
172
173 3
		$resultStatement = $query->execute();
0 ignored issues
show
Deprecated Code introduced by
The function OCP\DB\QueryBuilder\IQueryBuilder::execute() has been deprecated: 22.0.0 Use executeQuery or executeStatement ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

173
		$resultStatement = /** @scrutinizer ignore-deprecated */ $query->execute();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
174 3
		$data = $resultStatement->fetch(\PDO::FETCH_NUM);
175 3
		$resultStatement->closeCursor();
176
177 3
		return (int)$data[0];
178
	}
179
180
	/**
181
	 * @param IUser|null $user User for which to get images for. If not given, all images from instance are returned.
182
	 * @param int $modelId Model Id to get images for.
183
	 */
184 9
	public function findImagesWithoutFaces(IUser $user = null, int $modelId): array {
185 9
		$qb = $this->db->getQueryBuilder();
186 9
		$qb
187 9
			->select(['id', 'user', 'file', 'model'])
188 9
			->from($this->getTableName())
189 9
			->where($qb->expr()->eq('is_processed',  $qb->createParameter('is_processed')))
190 9
			->andWhere($qb->expr()->eq('model', $qb->createNamedParameter($modelId)))
191 9
			->setParameter('is_processed', false, IQueryBuilder::PARAM_BOOL);
192 9
		if (!is_null($user)) {
193 9
			$qb->andWhere($qb->expr()->eq('user', $qb->createNamedParameter($user->getUID())));
194
		}
195 9
		return $this->findEntities($qb);
196
	}
197
198 6
	public function findImages(string $userId, int $model): array {
199 6
		$qb = $this->db->getQueryBuilder();
200 6
		$qb->select('i.id', 'i.file')
201 6
			->from($this->getTableName(), 'i')
202 6
			->where($qb->expr()->eq('user', $qb->createNamedParameter($userId)))
203 6
			->andWhere($qb->expr()->eq('model', $qb->createNamedParameter($model)));
204
205 6
		$images = $this->findEntities($qb);
206 6
		return $images;
207
	}
208
209
	public function findFromPersonLike(string $userId, int $model, string $name, $offset = null, $limit = null): array {
210
		$qb = $this->db->getQueryBuilder();
211
		$qb->select('i.id', 'i.file')
212
			->from($this->getTableName(), 'i')
213
			->innerJoin('i', 'facerecog_faces', 'f', $qb->expr()->eq('f.image', 'i.id'))
214
			->innerJoin('i', 'facerecog_persons', 'p', $qb->expr()->eq('f.person', 'p.id'))
215
			->where($qb->expr()->eq('p.user', $qb->createNamedParameter($userId)))
216
			->andWhere($qb->expr()->eq('model', $qb->createNamedParameter($model)))
217
			->andWhere($qb->expr()->eq('is_processed', $qb->createNamedParameter(True)))
218
			->andWhere($qb->expr()->like($qb->func()->lower('p.name'), $qb->createParameter('query')));
219
220
		$query = '%' . $this->db->escapeLikeParameter(strtolower($name)) . '%';
221
		$qb->setParameter('query', $query);
222
223
		$qb->setFirstResult($offset);
224
		$qb->setMaxResults($limit);
225
226
		return $this->findEntities($qb);
227
	}
228
229
	public function findFromPerson(string $userId, int $modelId, string $name, $offset = null, $limit = null): array {
230
		$qb = $this->db->getQueryBuilder();
231
		$qb->select('i.file')
232
			->from($this->getTableName(), 'i')
233
			->innerJoin('i', 'facerecog_faces', 'f', $qb->expr()->eq('f.image', 'i.id'))
234
			->innerJoin('f', 'facerecog_persons', 'p', $qb->expr()->eq('f.person', 'p.id'))
235
			->where($qb->expr()->eq('p.user', $qb->createNamedParameter($userId)))
236
			->andWhere($qb->expr()->eq('model', $qb->createNamedParameter($modelId)))
237
			->andWhere($qb->expr()->eq('is_processed', $qb->createNamedParameter(True)))
238
			->andWhere($qb->expr()->eq('p.name', $qb->createNamedParameter($name)))
239
			->orderBy('i.file', 'DESC');
240
241
		$qb->setFirstResult($offset);
242
		$qb->setMaxResults($limit);
243
244
		return $this->findEntities($qb);
245
	}
246
247
	public function countFromPerson(string $userId, int $modelId, string $name): int {
248
		$qb = $this->db->getQueryBuilder();
249
		$qb->select($qb->func()->count('*'))
250
			->from($this->getTableName(), 'i')
251
			->innerJoin('i', 'facerecog_faces', 'f', $qb->expr()->eq('f.image', 'i.id'))
252
			->innerJoin('f', 'facerecog_persons', 'p', $qb->expr()->eq('f.person', 'p.id'))
253
			->where($qb->expr()->eq('p.user', $qb->createNamedParameter($userId)))
254
			->andWhere($qb->expr()->eq('model', $qb->createNamedParameter($modelId)))
255
			->andWhere($qb->expr()->eq('is_processed', $qb->createNamedParameter(True)))
256
			->andWhere($qb->expr()->eq('p.name', $qb->createNamedParameter($name)));
257
258
		$result = $qb->executeQuery();
259
		$column = (int)$result->fetchOne();
260
		$result->closeCursor();
261
262
		return $column;
263
	}
264
265
	/**
266
	 * Writes to DB that image has been processed. Previously found faces are deleted and new ones are inserted.
267
	 * If there is exception, its stack trace is also updated.
268
	 *
269
	 * @param Image $image Image to be updated
270
	 * @param Face[] $faces Faces to insert
271
	 * @param int $duration Processing time, in milliseconds
272
	 * @param \Exception|null $e Any exception that happened during image processing
273
	 *
274
	 * @return void
275
	 */
276 4
	public function imageProcessed(Image $image, array $faces, int $duration, \Exception $e = null): void {
277 4
		$this->db->beginTransaction();
278
		try {
279
			// Update image itself
280
			//
281 4
			$error = null;
282 4
			if ($e !== null) {
283 1
				$error = substr($e->getMessage(), 0, 1024);
284
			}
285
286 4
			$qb = $this->db->getQueryBuilder();
287 4
			$qb->update($this->getTableName())
0 ignored issues
show
Deprecated Code introduced by
The function OCP\DB\QueryBuilder\IQueryBuilder::execute() has been deprecated: 22.0.0 Use executeQuery or executeStatement ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

287
			/** @scrutinizer ignore-deprecated */ $qb->update($this->getTableName())

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
288 4
				->set("is_processed", $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL))
289 4
				->set("error", $qb->createNamedParameter($error))
290 4
				->set("last_processed_time", $qb->createNamedParameter(new \DateTime(), IQueryBuilder::PARAM_DATE))
0 ignored issues
show
OCP\DB\QueryBuilder\IQueryBuilder::PARAM_DATE of type string is incompatible with the type OCP\DB\QueryBuilder\IQueryBuilder expected by parameter $type of OCP\DB\QueryBuilder\IQue...:createNamedParameter(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

290
				->set("last_processed_time", $qb->createNamedParameter(new \DateTime(), /** @scrutinizer ignore-type */ IQueryBuilder::PARAM_DATE))
Loading history...
291 4
				->set("processing_duration", $qb->createNamedParameter($duration))
292 4
				->where($qb->expr()->eq('id', $qb->createNamedParameter($image->id)))
293 4
				->execute();
294
295
			// Delete all previous faces
296
			//
297 4
			$qb = $this->db->getQueryBuilder();
298 4
			$qb->delete('facerecog_faces')
0 ignored issues
show
Deprecated Code introduced by
The function OCP\DB\QueryBuilder\IQueryBuilder::execute() has been deprecated: 22.0.0 Use executeQuery or executeStatement ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

298
			/** @scrutinizer ignore-deprecated */ $qb->delete('facerecog_faces')

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
299 4
				->where($qb->expr()->eq('image', $qb->createNamedParameter($image->id)))
300 4
				->execute();
301
302
			// Insert all faces
303
			//
304 4
			foreach ($faces as $face) {
305 1
				$this->faceMapper->insertFace($face, $this->db);
306
			}
307
308 4
			$this->db->commit();
309
		} catch (\Exception $e) {
310
			$this->db->rollBack();
311
			throw $e;
312
		}
313
	}
314
315
	/**
316
	 * Resets image by deleting all associated faces and prepares it to be processed again
317
	 *
318
	 * @param Image $image Image to reset
319
	 *
320
	 * @return void
321
	 */
322
	public function resetImage(Image $image): void {
323
		$qb = $this->db->getQueryBuilder();
324
		$qb->update($this->getTableName())
0 ignored issues
show
Deprecated Code introduced by
The function OCP\DB\QueryBuilder\IQueryBuilder::execute() has been deprecated: 22.0.0 Use executeQuery or executeStatement ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

324
		/** @scrutinizer ignore-deprecated */ $qb->update($this->getTableName())

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
325
			->set("is_processed", $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL))
326
			->set("error", $qb->createNamedParameter(null))
327
			->set("last_processed_time", $qb->createNamedParameter(null))
328
			->where($qb->expr()->eq('user', $qb->createNamedParameter($image->getUser())))
329
			->andWhere($qb->expr()->eq('file', $qb->createNamedParameter($image->getFile())))
330
			->andWhere($qb->expr()->eq('model', $qb->createNamedParameter($image->getModel())))
331
			->execute();
332
	}
333
334
	/**
335
	 * Resets all image with error from that user and prepares it to be processed again
336
	 *
337
	 * @param string $userId User to reset errors
338
	 *
339
	 * @return void
340
	 */
341
	public function resetErrors(string $userId): void {
342
		$qb = $this->db->getQueryBuilder();
343
		$qb->update($this->getTableName())
0 ignored issues
show
Deprecated Code introduced by
The function OCP\DB\QueryBuilder\IQueryBuilder::execute() has been deprecated: 22.0.0 Use executeQuery or executeStatement ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

343
		/** @scrutinizer ignore-deprecated */ $qb->update($this->getTableName())

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
344
			->set("is_processed", $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL))
345
			->set("error", $qb->createNamedParameter(null))
346
			->set("last_processed_time", $qb->createNamedParameter(null))
347
			->where($qb->expr()->eq('user', $qb->createNamedParameter($userId)))
348
			->andWhere($qb->expr()->isNotNull('error'))
349
			->execute();
350
	}
351
352
	/**
353
	 * Deletes all images from that user.
354
	 *
355
	 * @param string $userId User to drop images from table.
356
	 *
357
	 * @return void
358
	 */
359 28
	public function deleteUserImages(string $userId): void {
360 28
		$qb = $this->db->getQueryBuilder();
361 28
		$qb->delete($this->getTableName())
0 ignored issues
show
Deprecated Code introduced by
The function OCP\DB\QueryBuilder\IQueryBuilder::execute() has been deprecated: 22.0.0 Use executeQuery or executeStatement ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

361
		/** @scrutinizer ignore-deprecated */ $qb->delete($this->getTableName())

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
362 28
			->where($qb->expr()->eq('user', $qb->createNamedParameter($userId)))
363 28
			->execute();
364
	}
365
366
	/**
367
	 * Deletes all images from that user and Model
368
	 *
369
	 * @param string $userId User to drop images from table.
370
	 * @param int $modelId model to drop images from table.
371
	 *
372
	 * @return void
373
	 */
374
	public function deleteUserModel(string $userId, $modelId): void {
375
		$qb = $this->db->getQueryBuilder();
376
		$qb->delete($this->getTableName())
0 ignored issues
show
Deprecated Code introduced by
The function OCP\DB\QueryBuilder\IQueryBuilder::execute() has been deprecated: 22.0.0 Use executeQuery or executeStatement ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

376
		/** @scrutinizer ignore-deprecated */ $qb->delete($this->getTableName())

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
377
			->where($qb->expr()->eq('user', $qb->createNamedParameter($userId)))
378
			->andWhere($qb->expr()->eq('model', $qb->createNamedParameter($modelId)))
379
			->execute();
380
	}
381
382
}
383