Passed
Push — settings-service ( 566350...50862f )
by Matias
03:49
created

FaceMapper::find()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 1
eloc 6
c 3
b 0
f 0
nc 1
nop 1
dl 0
loc 7
ccs 0
cts 7
cp 0
crap 2
rs 10
1
<?php
2
namespace OCA\FaceRecognition\Db;
3
4
use OC\DB\QueryBuilder\Literal;
0 ignored issues
show
Bug introduced by
The type OC\DB\QueryBuilder\Literal was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
5
6
use OCP\IDBConnection;
7
use OCP\AppFramework\Db\QBMapper;
8
use OCP\AppFramework\Db\DoesNotExistException;
9
use OCP\DB\QueryBuilder\IQueryBuilder;
10
11
class FaceMapper extends QBMapper {
12
	public function __construct(IDBConnection $db) {
13
		parent::__construct($db, 'facerecog_faces', '\OCA\FaceRecognition\Db\Face');
14
	}
15
16
	public function find (int $faceId): Face {
17
		$qb = $this->db->getQueryBuilder();
18
		$qb->select('id', 'image', 'person', 'left', 'right', 'top', 'bottom', 'descriptor')
19
			->from($this->getTableName(), 'f')
20
			->andWhere($qb->expr()->eq('id', $qb->createNamedParameter($faceId)));
21
		$faces = $this->findEntity($qb);
22
		return $faces;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $faces returns the type OCP\AppFramework\Db\Entity which includes types incompatible with the type-hinted return OCA\FaceRecognition\Db\Face.
Loading history...
23
	}
24
25
	/**
26
	 * Counts all the faces that belong to images of a given user, created using given model
27
	 *
28
	 * @param string $userId User to which faces and associated images belongs to
29
	 * @param int $model Model ID
30
	 * @param bool $onlyWithoutPersons True if we need to count only faces which are not having person associated for it.
31
	 * If false, all faces are counted.
32
	 */
33 13
	public function countFaces(string $userId, int $model, bool $onlyWithoutPersons=false): int {
34 13
		$qb = $this->db->getQueryBuilder();
35
		$qb = $qb
36 13
			->select($qb->createFunction('COUNT(' . $qb->getColumnName('f.id') . ')'))
37 13
			->from($this->getTableName(), 'f')
38 13
			->innerJoin('f', 'facerecog_images' ,'i', $qb->expr()->eq('f.image', 'i.id'))
39 13
			->where($qb->expr()->eq('user', $qb->createParameter('user')))
40 13
			->andWhere($qb->expr()->eq('model', $qb->createParameter('model')));
41 13
		if ($onlyWithoutPersons) {
42
			$qb = $qb->andWhere($qb->expr()->isNull('person'));
43
		}
44
		$query = $qb
45 13
			->setParameter('user', $userId)
46 13
			->setParameter('model', $model);
47 13
		$resultStatement = $query->execute();
48 13
		$data = $resultStatement->fetch(\PDO::FETCH_NUM);
49 13
		$resultStatement->closeCursor();
50
51 13
		return (int)$data[0];
52
	}
53
54
	/**
55
	 * Gets oldest created face from database, for a given user and model, that is not associated with a person.
56
	 *
57
	 * @param string $userId User to which faces and associated images belongs to
58
	 * @param int $model Model ID
59
	 *
60
	 * @return Face Oldest face, if any is found
61
	 * @throws DoesNotExistException If there is no faces in database without person for a given user and model.
62
	 */
63
	public function getOldestCreatedFaceWithoutPerson(string $userId, int $model): Face {
64
		$qb = $this->db->getQueryBuilder();
65
		$qb
66
			->select('f.id', 'f.creation_time')
67
			->from($this->getTableName(), 'f')
68
			->innerJoin('f', 'facerecog_images' ,'i', $qb->expr()->eq('f.image', 'i.id'))
69
			->where($qb->expr()->eq('user', $qb->createNamedParameter($userId)))
70
			->andWhere($qb->expr()->eq('model', $qb->createNamedParameter($model)))
71
			->andWhere($qb->expr()->isNull('person'))
72
			->orderBy('f.creation_time', 'ASC');
73
		$cursor = $qb->execute();
74
		$row = $cursor->fetch();
75
		if($row === false) {
76
			$cursor->closeCursor();
77
			throw new DoesNotExistException("No faces found and we should have at least one");
78
		}
79
		$face = $this->mapRowToEntity($row);
80
		$cursor->closeCursor();
81
		return $face;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $face returns the type OCP\AppFramework\Db\Entity which includes types incompatible with the type-hinted return OCA\FaceRecognition\Db\Face.
Loading history...
82
	}
83
84 12
	public function getFaces(string $userId, $model): array {
85 12
		$qb = $this->db->getQueryBuilder();
86
		$query = $qb
0 ignored issues
show
Unused Code introduced by
The assignment to $query is dead and can be removed.
Loading history...
87 12
			->select('f.id', 'f.person', 'f.confidence', 'f.descriptor')
88 12
			->from($this->getTableName(), 'f')
89 12
			->innerJoin('f', 'facerecog_images' ,'i', $qb->expr()->eq('f.image', 'i.id'))
90 12
			->where($qb->expr()->eq('user', $qb->createParameter('user')))
91 12
			->andWhere($qb->expr()->eq('model', $qb->createParameter('model')))
92 12
			->setParameter('user', $userId)
93 12
			->setParameter('model', $model);
94 12
		$faces = $this->findEntities($qb);
95 12
		return $faces;
96
	}
97
98 12
	public function findFacesFromPerson(string $userId, int $personId, int $model, $limit = null, $offset = null): array {
99 12
		$qb = $this->db->getQueryBuilder();
100 12
		$qb->select('f.id', 'f.image', 'f.person')
101 12
			->from($this->getTableName(), 'f')
102 12
			->innerJoin('f', 'facerecog_images' ,'i', $qb->expr()->eq('f.image', 'i.id'))
103 12
			->where($qb->expr()->eq('user', $qb->createNamedParameter($userId)))
104 12
			->andWhere($qb->expr()->eq('person', $qb->createNamedParameter($personId)))
105 12
			->andWhere($qb->expr()->eq('model', $qb->createNamedParameter($model)));
106
107 12
		$qb->setMaxResults($limit);
108 12
		$qb->setFirstResult($offset);
109
110 12
		$faces = $this->findEntities($qb);
111 12
		return $faces;
112
	}
113
114
	public function getPersonOnFile(string $userId, int $personId, int $fileId, int $model): array {
115
		$qb = $this->db->getQueryBuilder();
116
		$qb->select('f.id', 'left', 'right', 'top', 'bottom')
117
			->from($this->getTableName(), 'f')
118
			->innerJoin('f', 'facerecog_persons' ,'p', $qb->expr()->eq('f.person', 'p.id'))
119
			->innerJoin('f', 'facerecog_images' ,'i', $qb->expr()->eq('f.image', 'i.id'))
120
			->where($qb->expr()->eq('p.user', $qb->createParameter('user')))
121
			->andWhere($qb->expr()->eq('person', $qb->createParameter('person')))
122
			->andWhere($qb->expr()->eq('file', $qb->createParameter('file_id')))
123
			->andWhere($qb->expr()->eq('model', $qb->createParameter('model')))
124
			->andWhere($qb->expr()->eq('p.is_valid', $qb->createParameter('is_valid')))
125
			->setParameter('user', $userId)
126
			->setParameter('person', $personId)
127
			->setParameter('file_id', $fileId)
128
			->setParameter('model', $model)
129
			->setParameter('is_valid', true)
130
			->orderBy('confidence', 'DESC');
131
		$faces = $this->findEntities($qb);
132
		return $faces;
133
	}
134
135
	/**
136
	 * Finds all faces contained in one image
137
	 *
138
	 * @param int $imageId Image for which to find all faces for
139
	 */
140
	public function findByImage(int $imageId) {
141
		$qb = $this->db->getQueryBuilder();
142
		$qb->select('id', 'image', 'person')
143
			->from($this->getTableName())
144
			->where($qb->expr()->eq('image', $qb->createNamedParameter($imageId)));
145
		$faces = $this->findEntities($qb);
146
		return $faces;
147
	}
148
149
	/**
150
	 * @param int $imageId Image for which to delete faces for
151
	 */
152
	public function removeFaces(int $imageId) {
153
		$qb = $this->db->getQueryBuilder();
154
		$qb->delete($this->getTableName())
155
			->where($qb->expr()->eq('image', $qb->createNamedParameter($imageId)))
156
			->execute();
157
	}
158
159
	/**
160
	 * Deletes all faces from that user.
161
	 *
162
	 * @param string $userId User to drop faces from table.
163
	 */
164
	public function deleteUserFaces(string $userId) {
165
		$sub = $this->db->getQueryBuilder();
166
		$sub->select(new Literal('1'));
167
		$sub->from('facerecog_images', 'i')
168
			->where($sub->expr()->eq('i.id', '*PREFIX*' . $this->getTableName() .'.image'))
169
			->andWhere($sub->expr()->eq('i.user', $sub->createParameter('user')));
170
171
		$qb = $this->db->getQueryBuilder();
172
		$qb->delete($this->getTableName())
173
			->where('EXISTS (' . $sub->getSQL() . ')')
174
			->setParameter('user', $userId)
175
			->execute();
176
	}
177
178
	/**
179
	 * Insert one face to database.
180
	 * Note: only reason we are not using (idiomatic) QBMapper method is
181
	 * because "QueryBuilder::PARAM_DATE" cannot be set there
182
	 *
183
	 * @param Face $face Face to insert
184
	 * @param IDBConnection $db Existing connection, if we need to reuse it. Null if we commit immediatelly.
185
	 */
186 13
	public function insertFace(Face $face, IDBConnection $db = null) {
187 13
		if ($db !== null) {
188
			$qb = $db->getQueryBuilder();
189
		} else {
190 13
			$qb = $this->db->getQueryBuilder();
191
		}
192
193 13
		$qb->insert($this->getTableName())
194 13
			->values([
195 13
				'image' => $qb->createNamedParameter($face->image),
196 13
				'person' => $qb->createNamedParameter($face->person),
197 13
				'left' => $qb->createNamedParameter($face->left),
198 13
				'right' => $qb->createNamedParameter($face->right),
199 13
				'top' => $qb->createNamedParameter($face->top),
200 13
				'bottom' => $qb->createNamedParameter($face->bottom),
201 13
				'confidence' => $qb->createNamedParameter($face->confidence),
202 13
				'landmarks' => $qb->createNamedParameter(json_encode($face->landmarks)),
203 13
				'descriptor' => $qb->createNamedParameter(json_encode($face->descriptor)),
204 13
				'creation_time' => $qb->createNamedParameter($face->creationTime, IQueryBuilder::PARAM_DATE),
205
			])
206 13
			->execute();
207 13
		$face->setId((int) $qb->getLastInsertId());
208
	}
209
}