Passed
Push — test-scrutinizer-new-analyser ( 748b29 )
by Branko
05:41
created

Watcher::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 8
dl 0
loc 16
ccs 0
cts 16
cp 0
crap 2
rs 10
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, Roeland Jago Douma <[email protected]>
4
 * @copyright Copyright (c) 2017, Matias De lellis <[email protected]>
5
 *
6
 * @author Roeland Jago Douma <[email protected]>
7
 * @author Matias De lellis <[email protected]>
8
 *
9
 * @license GNU AGPL version 3 or any later version
10
 *
11
 * This program is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU Affero General Public License as
13
 * published by the Free Software Foundation, either version 3 of the
14
 * License, or (at your option) any later version.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23
 *
24
 */
25
namespace OCA\FaceRecognition;
26
27
use OCP\Files\Folder;
28
use OCP\Files\IHomeStorage;
29
use OCP\Files\Node;
30
use OCP\IConfig;
31
use OCP\IDBConnection;
32
use OCP\ILogger;
33
use OCP\IUserManager;
34
35
use OCA\FaceRecognition\BackgroundJob\Tasks\AddMissingImagesTask;
36
use OCA\FaceRecognition\Db\Face;
37
use OCA\FaceRecognition\Db\Image;
38
use OCA\FaceRecognition\Db\FaceMapper;
39
use OCA\FaceRecognition\Db\FaceNewMapper;
40
use OCA\FaceRecognition\Db\ImageMapper;
41
use OCA\FaceRecognition\Db\PersonMapper;
42
use OCA\FaceRecognition\Helper\Requirements;
43
use OCA\FaceRecognition\Migration\AddDefaultFaceModel;
44
45
class Watcher {
46
47
	/** @var IConfig Config */
48
	private $config;
49
50
	/** @var ILogger Logger */
51
	private $logger;
52
53
	/** @var IDBConnection */
54
	private $connection;
55
56
	/** @var IUserManager */
57
	private $userManager;
58
59
	/** @var FaceMapper */
60
	private $faceMapper;
61
62
	/** @var FaceNewMapper */
63
	private $faceNewMapper;
64
65
	/** @var ImageMapper */
66
	private $imageMapper;
67
68
	/** @var PersonMapper */
69
	private $personMapper;
70
71
	/**
72
	 * Watcher constructor.
73
	 *
74
	 * @param IConfig $config
75
	 * @param ILogger $logger
76
	 * @param IDBConnection $connection
77
	 * @param IUserManager $userManager
78
	 * @param FaceMapper $faceMapper
79
	 * @param FaceNewMapper $faceNewMapper
80
	 * @param ImageMapper $imageMapper
81
	 * @param PersonMapper $personMapper
82
	 */
83
	public function __construct(IConfig       $config,
84
								ILogger       $logger,
85
								IDBConnection $connection,
86
								IUserManager  $userManager,
87
								FaceMapper    $faceMapper,
88
								FaceNewMapper $faceNewMapper,
89
								ImageMapper   $imageMapper,
90
								PersonMapper  $personMapper) {
91
		$this->config = $config;
92
		$this->logger = $logger;
93
		$this->connection = $connection;
94
		$this->userManager = $userManager;
95
		$this->faceMapper = $faceMapper;
96
		$this->faceNewMapper = $faceNewMapper;
97
		$this->imageMapper = $imageMapper;
98
		$this->personMapper = $personMapper;
99
	}
100
101
	/**
102
	 * A node has been updated. We just store the file id
103
	 * with the current user in the DB
104
	 *
105
	 * @param Node $node
106
	 */
107
	public function postWrite(Node $node) {
108
		// v1 code
109
		$absPath = ltrim($node->getPath(), '/');
110
		$owner = explode('/', $absPath)[0];
111
112
		if (!$this->userManager->userExists($owner) || $node instanceof Folder) {
113
			return;
114
		}
115
116
117
		if (!Requirements::isImageTypeSupported($node->getMimeType())) {
118
			return;
119
		}
120
121
//		if ($this->faceMapper->fileExists($node->getId())) {
122
//			return;
123
//		}
124
125
		$face = new Face();
126
		$face->setUid($owner);
0 ignored issues
show
Bug introduced by
The method setUid() does not exist on OCA\FaceRecognition\Db\Face. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

126
		$face->/** @scrutinizer ignore-call */ 
127
         setUid($owner);
Loading history...
127
		$face->setFile($node->getId());
0 ignored issues
show
Bug introduced by
The method setFile() does not exist on OCA\FaceRecognition\Db\Face. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

127
		$face->/** @scrutinizer ignore-call */ 
128
         setFile($node->getId());
Loading history...
128
		$face->setName('unknown');
0 ignored issues
show
Bug introduced by
The method setName() does not exist on OCA\FaceRecognition\Db\Face. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

128
		$face->/** @scrutinizer ignore-call */ 
129
         setName('unknown');
Loading history...
129
		$face->setDistance(-1.0);
0 ignored issues
show
Bug introduced by
The method setDistance() does not exist on OCA\FaceRecognition\Db\Face. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

129
		$face->/** @scrutinizer ignore-call */ 
130
         setDistance(-1.0);
Loading history...
130
		$face->setTop(-1.0);
0 ignored issues
show
Bug introduced by
The method setTop() does not exist on OCA\FaceRecognition\Db\Face. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

130
		$face->/** @scrutinizer ignore-call */ 
131
         setTop(-1.0);
Loading history...
131
		$face->setRight(-1.0);
0 ignored issues
show
Bug introduced by
The method setRight() does not exist on OCA\FaceRecognition\Db\Face. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

131
		$face->/** @scrutinizer ignore-call */ 
132
         setRight(-1.0);
Loading history...
132
		$face->setBottom(-1.0);
0 ignored issues
show
Bug introduced by
The method setBottom() does not exist on OCA\FaceRecognition\Db\Face. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

132
		$face->/** @scrutinizer ignore-call */ 
133
         setBottom(-1.0);
Loading history...
133
		$face->setLeft(-1.0);
0 ignored issues
show
Bug introduced by
The method setLeft() does not exist on OCA\FaceRecognition\Db\Face. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

133
		$face->/** @scrutinizer ignore-call */ 
134
         setLeft(-1.0);
Loading history...
134
		$this->faceMapper->insert($face);
135
136
	}
137
138
	/**
139
	 * @param Node $node
140
	 */
141
	public function postWritev2(Node $node) {
142
		$model = intval($this->config->getAppValue('facerecognition', 'model', AddDefaultFaceModel::DEFAULT_FACE_MODEL_ID));
143
144
		// todo: should we also care about this too: instanceOfStorage(ISharedStorage::class);
145
		if ($node->getStorage()->instanceOfStorage(IHomeStorage::class) == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
146
			return;
147
		}
148
149
		if ($node instanceof Folder) {
150
			return;
151
		}
152
153
		// todo: issue #37 - if we detect .nomedia written, reset some global flag such that RemoveMissingImagesTask is triggered.
154
155
		if (!Requirements::isImageTypeSupported($node->getMimeType())) {
156
			return;
157
		}
158
159
		// If we detect .nomedia file anywhere on the path to root folder (id==null), bail out
160
		$parentNode = $node->getParent();
161
		while (($parentNode instanceof Folder) && ($parentNode->getId() != null)) {
162
			if ($parentNode->nodeExists('.nomedia')) {
163
				$this->logger->debug(
164
					"Skipping inserting image " . $node->getName() . " because directory " . $parentNode->getName() . " contains .nomedia file");
165
				return;
166
			}
167
168
			$parentNode = $parentNode->getParent();
169
		}
170
171
		$owner = $node->getOwner()->getUid();
172
173
		if (!$this->userManager->userExists($owner)) {
174
			$this->logger->debug(
175
				"Skipping inserting image " . $node->getName() . " because it seems that user  " . $owner . " doesn't exist");
176
			return;
177
		}
178
179
		$this->logger->debug("Inserting/updating image " . $node->getName() . " for face recognition");
180
181
		$image = new Image();
182
		$image->setUser($owner);
183
		$image->setFile($node->getId());
184
		$image->setModel($model);
185
186
		$imageId = $this->imageMapper->imageExists($image);
187
		if ($imageId === null) {
188
			// todo: can we have larger transaction with bulk insert?
189
			$this->imageMapper->insert($image);
190
		} else {
191
			$this->imageMapper->resetImage($image);
192
			// note that invalidatePersons depends on existence of faces for a given image,
193
			// and we must invalidate before we delete faces!
194
			$this->personMapper->invalidatePersons($imageId);
195
			$this->faceNewMapper->removeFaces($imageId);
196
		}
197
	}
198
199
	/**
200
	 * A node has been delete. Remove faces with file id
201
	 * with the current user in the DB
202
	 *
203
	 * @param Node $node
204
	 */
205
	public function preDelete(Node $node) {
206
		$absPath = ltrim($node->getPath(), '/');
207
		$owner = explode('/', $absPath)[0];
208
209
		if (!$this->userManager->userExists($owner) || $node instanceof Folder) {
210
			return;
211
		}
212
213
		if (!Requirements::isImageTypeSupported($node->getMimeType())) {
214
			return;
215
		}
216
217
		try {
218
			$faces = $this->faceMapper->findFile($owner, $node->getId());
219
		} catch(\Exception $e) {
220
			return;
221
		}
222
223
		foreach ($faces as $face) {
224
			$this->faceMapper->delete($face);
225
		}
226
	}
227
228
	public function postDeletev2(Node $node) {
229
		$model = intval($this->config->getAppValue('facerecognition', 'model', AddDefaultFaceModel::DEFAULT_FACE_MODEL_ID));
230
231
		// todo: should we also care about this too: instanceOfStorage(ISharedStorage::class);
232
		if ($node->getStorage()->instanceOfStorage(IHomeStorage::class) == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
233
			return;
234
		}
235
236
		if ($node instanceof Folder) {
237
			return;
238
		}
239
240
		if ($node->getName() == '.nomedia') {
241
			// If user deleted file named .nomedia, that means all images in this and all child directories should be added.
242
			// But, instead of doing that here, better option seem to be to just reset global flag that image scan is not done.
243
			// This will trigger another round of image crawling in AddMissingImagesTask and those images will be added.
244
			$this->config->setAppValue('facerecognition', AddMissingImagesTask::FULL_IMAGE_SCAN_DONE_KEY, 'false');
245
			return;
246
		}
247
248
		if (!Requirements::isImageTypeSupported($node->getMimeType())) {
249
			return;
250
		}
251
252
		$owner = $node->getOwner()->getUid();
253
254
		$this->logger->debug("Deleting image " . $node->getName() . " from face recognition");
255
256
		$image = new Image();
257
		$image->setUser($owner);
258
		$image->setFile($node->getId());
259
		$image->setModel($model);
260
261
		$imageId = $this->imageMapper->imageExists($image);
262
		if ($imageId !== null) {
263
			// note that invalidatePersons depends on existence of faces for a given image,
264
			// and we must invalidate before we delete faces!
265
			$this->personMapper->invalidatePersons($imageId);
266
			$this->faceNewMapper->removeFaces($imageId);
267
268
			$image->setId($imageId);
269
			$this->imageMapper->delete($image);
270
		}
271
	}
272
}
273