Passed
Push — find-similar ( 0b22b7...8189e1 )
by Matias
05:01
created

RelationMapper::existsOnMatrix()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

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