Passed
Push — find-similar ( 776de5...0b22b7 )
by Matias
04:43
created

RelationMapper::findByUserAsMatrix()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 9
c 1
b 0
f 0
nc 3
nop 2
dl 0
loc 12
ccs 0
cts 10
cp 0
crap 12
rs 9.9666
1
<?php
2
/**
3
 * @copyright Copyright (c) 2020, Matias De lellis <[email protected]>
4
 *
5
 * @author Matias De lellis <[email protected]>
6
 *
7
 * @license GNU AGPL version 3 or any later version
8
 *
9
 * This program is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License as
11
 * published by the Free Software Foundation, either version 3 of the
12
 * License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 *
22
 */
23
24
namespace OCA\FaceRecognition\Db;
25
26
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...
27
28
use OCP\IDBConnection;
29
use OCP\AppFramework\Db\QBMapper;
30
use OCP\AppFramework\Db\DoesNotExistException;
31
use OCP\DB\QueryBuilder\IQueryBuilder;
32
33
class RelationMapper extends QBMapper {
34
35 1
	public function __construct(IDBConnection $db) {
36 1
		parent::__construct($db, 'facerecog_relations', '\OCA\FaceRecognition\Db\Relation');
37 1
	}
38
39
	/**
40
	 * Find all relation from that user.
41
	 *
42
	 * @param string $userId User user to search
43
	 * @param int $modelId
44
	 * @return array
45
	 */
46
	public function findByUser(string $userId, int $modelId): array {
47
		$qb = $this->db->getQueryBuilder();
48
		$qb->select('r.id', 'r.face1', 'r.face2', 'r.state')
49
		    ->from($this->getTableName(), 'r')
50
		    ->innerJoin('r', 'facerecog_faces', 'f', $qb->expr()->eq('r.face1', 'f.id'))
51
		    ->innerJoin('f', 'facerecog_images', 'i', $qb->expr()->eq('f.image', 'i.id'))
52
		    ->where($qb->expr()->eq('i.user', $qb->createParameter('user_id')))
53
		    ->andWhere($qb->expr()->eq('i.model', $qb->createParameter('model_id')))
54
		    ->setParameter('user_id', $userId)
55
		    ->setParameter('model_id', $modelId);
56
57
		return $this->findEntities($qb);
58
	}
59
60
	public function findFromPerson(string $userId, int $personId, int $state): array {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed. ( Ignorable by Annotation )

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

60
	public function findFromPerson(string $userId, int $personId, /** @scrutinizer ignore-unused */ int $state): array {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $userId is not used and could be removed. ( Ignorable by Annotation )

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

60
	public function findFromPerson(/** @scrutinizer ignore-unused */ string $userId, int $personId, int $state): array {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
61
		$sub = $this->db->getQueryBuilder();
62
		$sub->select('f.id')
63
		    ->from('facerecog_faces', 'f')
64
		    ->where($sub->expr()->eq('f.person', $sub->createParameter('person_id')));
65
66
		$qb = $this->db->getQueryBuilder();
67
		$qb->select('r.id', 'r.face1', 'r.face2', 'r.state')
68
		   ->from($this->getTableName(), 'r')
69
		   ->where('(r.face1 IN (' . $sub->getSQL() . '))')
70
		   ->orWhere('(r.face2 IN (' . $sub->getSQL() . '))')
71
		   ->setParameter('person_id', $personId);
72
73
		return $this->findEntities($qb);
74
	}
75
76
	public function findFromPersons(int $personId1, int $personId2) {
77
		$sub1 = $this->db->getQueryBuilder();
78
		$sub1->select('f.id')
79
		      ->from('facerecog_faces', 'f')
80
		      ->where($sub1->expr()->eq('f.person', $sub1->createParameter('person1')));
81
82
		$sub2 = $this->db->getQueryBuilder();
83
		$sub2->select('f.id')
84
		      ->from('facerecog_faces', 'f')
85
		      ->where($sub2->expr()->eq('f.person', $sub2->createParameter('person2')));
86
87
		$qb = $this->db->getQueryBuilder();
88
		$qb->select('r.id', 'r.face1', 'r.face2', 'r.state')
89
		   ->from($this->getTableName(), 'r')
90
		   ->where('((r.face1 IN (' . $sub1->getSQL() . ')) AND (r.face2 IN (' . $sub2->getSQL() . ')))')
91
		   ->orWhere('((r.face2 IN (' . $sub1->getSQL() . ')) AND (r.face1 IN (' . $sub2->getSQL() . ')))')
92
		   ->setParameter('person1', $personId1)
93
		   ->setParameter('person2', $personId2);
94
95
		return $this->findEntities($qb);
96
	}
97
98
	/**
99
	 * Deletes all relations from that user.
100
	 *
101
	 * @param string $userId User to drop persons from a table.
102
	 */
103
	public function deleteUser(string $userId) {
104
		$sub = $this->db->getQueryBuilder();
105
		$sub->select(new Literal('1'))
106
		     ->from('facerecog_faces', 'f')
107
		     ->innerJoin('f', 'facerecog_images', 'i', $sub->expr()->eq('f.image', 'i.id'))
108
		     ->andWhere($sub->expr()->eq('i.user', $sub->createParameter('user_id')));
109
110
		$qb = $this->db->getQueryBuilder();
111
		$qb->delete($this->getTableName())
112
		    ->where('EXISTS (' . $sub->getSQL() . ')')
113
		    ->setParameter('user_id', $userId)
114
		    ->execute();
115
	}
116
117
	/**
118
	 * Find all the relations of a user as an matrix array, which is faster to access.
119
	 * @param string $userId
120
	 * @param int $modelId
121
	 * return array
122
	 */
123
	public function findByUserAsMatrix(string $userId, int $modelId): array {
124
		$matrix = array();
125
		$relations = $this->findByUser($userId, $modelId);
126
		foreach ($relations as $relation) {
127
			$row = array();
128
			if (isset($matrix[$relation->face1])) {
129
				$row = $matrix[$relation->face1];
130
			}
131
			$row[$relation->face2] = $relation->state;
132
			$matrix[$relation->face1] = $row;
133
		}
134
		return $matrix;
135
	}
136
137
	public function getStateOnMatrix(int $face1, int $face2, array $matrix): int {
138
		if (isset($matrix[$face1])) {
139
			$row = $matrix[$face1];
140
			if (isset($row[$face2])) {
141
				return $matrix[$face1][$face2];
142
			}
143
		}
144
		if (isset($matrix[$face2])) {
145
			$row = $matrix[$face2];
146
			if (isset($row[$face1])) {
147
				return $matrix[$face2][$face1];
148
			}
149
		}
150
		return Relation::PROPOSED;
151
	}
152
153
	public function existsOnMatrix(int $face1, int $face2, array $matrix): bool {
154
		if (isset($matrix[$face1])) {
155
			$row = $matrix[$face1];
156
			if (isset($row[$face2])) {
157
				return true;
158
			}
159
		}
160
		if (isset($matrix[$face2])) {
161
			$row = $matrix[$face2];
162
			if (isset($row[$face1])) {
163
				return true;
164
			}
165
		}
166
		return false;
167
	}
168
169
	public function merge(string $userId, int $modelId, array $relations): int {
170
		$added = 0;
171
		$this->db->beginTransaction();
172
		try {
173
			$oldMatrix = $this->findByUserAsMatrix($userId, $modelId);
174
			foreach ($relations as $relation) {
175
				if ($this->existsOnMatrix($relation->face1, $relation->face2, $oldMatrix))
176
					continue;
177
				$this->insert($relation);
178
				$added++;
179
			}
180
			$this->db->commit();
181
		} catch (\Exception $e) {
182
			$this->db->rollBack();
183
			throw $e;
184
		}
185
		return $added;
186
	}
187
188
}