Passed
Pull Request — master (#136)
by Branko
01:00
created

FaceMapper::insertFace()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 19
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 2

Importance

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