Completed
Push — exception_in_tasks ( 7463cd...3899e4 )
by Branko
01:58
created

ImageMapper::find()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12

Duplication

Lines 12
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 12
loc 12
ccs 0
cts 11
cp 0
rs 9.8666
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 2
1
<?php
2
/**
3
 * @copyright Copyright (c) 2017, Matias De lellis <[email protected]>
4
 * @copyright Copyright (c) 2018, 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\Mapper;
30
use OCP\AppFramework\Db\DoesNotExistException;
31
use OCP\DB\QueryBuilder\IQueryBuilder;
32
33
class ImageMapper extends Mapper {
34
35
	public function __construct(IDBConnection $db) {
36
		parent::__construct($db, 'face_recognition_images', '\OCA\FaceRecognition\Db\Image');
37
	}
38
39
	public function imageExists(Image $image) {
40
		$qb = $this->db->getQueryBuilder();
41
		$query = $qb
42
			->select(['id'])
43
			->from('face_recognition_images')
44
			->where($qb->expr()->eq('user', $qb->createParameter('user')))
45
			->andWhere($qb->expr()->eq('file', $qb->createParameter('file')))
46
			->andWhere($qb->expr()->eq('model', $qb->createParameter('model')))
47
			->setParameter('user', $image->getUser())
48
			->setParameter('file', $image->getFile())
49
			->setParameter('model', $image->getModel());
50
		$resultStatement = $query->execute();
51
		$row = $resultStatement->fetch();
52
		$resultStatement->closeCursor();
53
		return $row ? (int)$row['id'] : null;
54
	}
55
56
	public function countUserImages(string $userId, $model): int {
57
		$qb = $this->db->getQueryBuilder();
58
		$query = $qb
59
			->select($qb->createFunction('COUNT(' . $qb->getColumnName('id') . ')'))
60
			->from('face_recognition_images')
61
			->where($qb->expr()->eq('user', $qb->createParameter('user')))
62
			->andWhere($qb->expr()->eq('model', $qb->createParameter('model')))
63
			->setParameter('user', $userId)
64
			->setParameter('model', $model);
65
		$resultStatement = $query->execute();
66
		$data = $resultStatement->fetch(\PDO::FETCH_NUM);
67
		$resultStatement->closeCursor();
68
69
		return (int)$data[0];
70
	}
71
72
	public function countUserProcessedImages(string $userId, $model): int {
73
		$qb = $this->db->getQueryBuilder();
74
		$query = $qb
75
			->select($qb->createFunction('COUNT(' . $qb->getColumnName('id') . ')'))
76
			->from('face_recognition_images')
77
			->where($qb->expr()->eq('user', $qb->createParameter('user')))
78
			->andWhere($qb->expr()->eq('model', $qb->createParameter('model')))
79
			->andWhere($qb->expr()->eq('is_processed', $qb->createParameter('is_processed')))
80
			->setParameter('user', $userId)
81
			->setParameter('model', $model)
82
			->setParameter('is_processed', True);
83
		$resultStatement = $query->execute();
84
		$data = $resultStatement->fetch(\PDO::FETCH_NUM);
85
		$resultStatement->closeCursor();
86
87
		return (int)$data[0];
88
	}
89
90
	/**
91
	 * @param IUser|null $user User for which to get images for. If not given, all images from instance are returned.
92
	 */
93
	public function findImagesWithoutFaces(IUser $user = null) {
94
		$qb = $this->db->getQueryBuilder();
95
		$params = array();
96
97
		$query = $qb
98
			->select(['id', 'user', 'file', 'model'])
99
			->from('face_recognition_images')
100
			->where($qb->expr()->eq('is_processed',  $qb->createParameter('is_processed')));
101
			$params['is_processed'] = False;
102
		if (!is_null($user)) {
103
			$query->andWhere($qb->expr()->eq('user', $qb->createParameter('user')));
104
			$params['user'] = $user->getUID();
105
		}
106
107
		$images = $this->findEntities($qb->getSQL(), $params);
108
		return $images;
109
	}
110
111
112
	public function findImagesFromPerson(string $userId, string $name, int $model): array {
113
		$qb = $this->db->getQueryBuilder();
114
		$qb->select('i.id', 'i.file')
115
			->from('face_recognition_images', 'i')
116
			->innerJoin('i', 'face_recognition_faces', 'f', $qb->expr()->eq('f.image', 'i.id'))
117
			->innerJoin('i', 'face_recognition_persons', 'p', $qb->expr()->eq('f.person', 'p.id'))
118
			->where($qb->expr()->eq('p.user', $qb->createParameter('user')))
119
			->andWhere($qb->expr()->eq('model', $qb->createParameter('model')))
120
			->andWhere($qb->expr()->eq('is_processed', $qb->createParameter('is_processed')))
121
			->andWhere($qb->expr()->like($qb->func()->lower('p.name'), $qb->createParameter('query')));
122
			$params['user'] = $userId;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
123
			$params['model'] = $model;
124
			$params['is_processed'] = True;
125
			$params['query'] = '%' . $this->db->escapeLikeParameter(strtolower($name)) . '%';
126
		$images = $this->findEntities($qb->getSQL(), $params);
127
		return $images;
128
	}
129
130
	/**
131
	 * Writes to DB that image has been processed. Previously found faces are deleted and new ones are inserted.
132
	 * If there is exception, its stack trace is also updated.
133
	 *
134
	 * @param Image $image Image to be updated
135
	 * @param FaceNew[] $faces Faces to insert
136
	 * @param int $duration Processing time, in milliseconds
137
	 * @param \Exception|null $e Any exception that happened during image processing
138
	 */
139
	public function imageProcessed(Image $image, array $faces, int $duration, \Exception $e = null) {
140
		$this->db->beginTransaction();
141
		try {
142
			// Update image itself
143
			//
144
			$error = null;
145
			if ($e != null) {
146
				$error = substr($e->getMessage(), 0, 1024);
147
			}
148
149
			$qb = $this->db->getQueryBuilder();
150
			$qb->update('face_recognition_images')
151
				->set("is_processed", $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL))
152
				->set("error", $qb->createNamedParameter($error))
153
				->set("last_processed_time", $qb->createNamedParameter($currentDateTime, IQueryBuilder::PARAM_DATE))
0 ignored issues
show
Bug introduced by
The variable $currentDateTime does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
154
				->set("processing_duration", $qb->createNamedParameter($duration))
155
				->where($qb->expr()->eq('id', $qb->createNamedParameter($image->id)))
156
				->execute();
157
158
			// Delete all previous faces
159
			//
160
			$qb = $this->db->getQueryBuilder();
161
			$qb->delete('face_recognition_faces')
162
				->where($qb->expr()->eq('image', $qb->createNamedParameter($image->id)))
163
				->execute();
164
165
			// Insert all faces
166
			//
167
			foreach ($faces as $face) {
168
				// Simple INSERT will close cursor and we want to be in transaction, so use hard way
169
				// todo: should we move this to FaceNewMapper (don't forget to hand over connection though)
170
				$qb = $this->db->getQueryBuilder();
171
				$qb->insert('face_recognition_faces')
172
					->values([
173
						'image' => $qb->createNamedParameter($image->id),
174
						'person' => $qb->createNamedParameter(null),
175
						'left' => $qb->createNamedParameter($face->left),
176
						'right' => $qb->createNamedParameter($face->right),
177
						'top' => $qb->createNamedParameter($face->top),
178
						'bottom' => $qb->createNamedParameter($face->bottom),
179
						'descriptor' => $qb->createNamedParameter(json_encode($face->descriptor)),
180
						'creation_time' => $qb->createNamedParameter($face->creation_time, IQueryBuilder::PARAM_DATE),
181
					])
182
					->execute();
183
			}
184
185
			$this->db->commit();
186
		} catch (\Exception $e) {
187
			$this->db->rollBack();
188
			throw $e;
189
		}
190
	}
191
192
	/**
193
	 * Resets image by deleting all associated faces and prepares it to be processed again
194
	 *
195
	 * @param Image $image Image to reset
196
	 */
197
	public function resetImage(Image $image) {
198
		$qb = $this->db->getQueryBuilder();
199
		$qb->update($this->getTableName())
200
			->set("is_processed", $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL))
201
			->set("error", $qb->createNamedParameter(null))
202
			->set("last_processed_time", $qb->createNamedParameter(null))
203
			->where($qb->expr()->eq('user', $qb->createNamedParameter($image->getUser())))
204
			->andWhere($qb->expr()->eq('file', $qb->createNamedParameter($image->getFile())))
205
			->andWhere($qb->expr()->eq('model', $qb->createNamedParameter($image->getModel())))
206
			->execute();
207
	}
208
}
209