Passed
Push — enconde-from-orig ( 790c98...221cfe )
by Matias
05:02
created

MigrateCommand   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 183
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 99
dl 0
loc 183
ccs 0
cts 124
cp 0
rs 10
c 3
b 0
f 0
wmc 19

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getFaceRect() 0 8 1
A migrateFace() 0 13 1
C execute() 0 70 12
A configure() 0 18 1
A __construct() 0 15 1
A migrateImage() 0 11 1
A getImageFilePath() 0 6 2
1
<?php
2
/**
3
 * @copyright Copyright (c) 2020, Matias De lellis <[email protected]>
4
 * @copyright Copyright (c) 2019, 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\Command;
25
26
use OCP\IUserManager;
27
28
use Symfony\Component\Console\Command\Command;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Command\Command 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...
29
use Symfony\Component\Console\Input\InputOption;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Input\InputOption 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...
30
use Symfony\Component\Console\Input\InputInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Input\InputInterface 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...
31
use Symfony\Component\Console\Output\OutputInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Output\OutputInterface 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...
32
33
use Symfony\Component\Console\Helper\ProgressBar;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Helper\ProgressBar 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...
34
35
use OCA\FaceRecognition\Db\Face;
36
use OCA\FaceRecognition\Db\FaceMapper;
37
38
use OCA\FaceRecognition\Db\Image;
39
use OCA\FaceRecognition\Db\ImageMapper;
40
41
use OCA\FaceRecognition\Model\ModelManager;
42
43
use OCA\FaceRecognition\Service\FaceManagementService;
44
use OCA\FaceRecognition\Service\FileService;
45
46
class MigrateCommand extends Command {
47
48
	/** @var FaceManagementService */
49
	protected $faceManagementService;
50
51
	/** @var FileService */
52
	protected $fileService;
53
54
	/** @var IUserManager */
55
	protected $userManager;
56
57
	/** @var ModelManager */
58
	protected $modelManager;
59
60
	/** @var FaceMapper */
61
	protected $faceMapper;
62
63
	/** @var ImageMapper Image mapper*/
64
	protected $imageMapper;
65
66
	/**
67
	 * @param FaceManagementService $faceManagementService
68
	 * @param IUserManager $userManager
69
	 */
70
	public function __construct(FaceManagementService $faceManagementService,
71
	                            FileService           $fileService,
72
	                            IUserManager          $userManager,
73
	                            ModelManager          $modelManager,
74
	                            FaceMapper            $faceMapper,
75
	                            ImageMapper           $imageMapper)
76
	{
77
		parent::__construct();
78
79
		$this->faceManagementService = $faceManagementService;
80
		$this->fileService           = $fileService;
81
		$this->userManager           = $userManager;
82
		$this->modelManager          = $modelManager;
83
		$this->faceMapper            = $faceMapper;
84
		$this->imageMapper           = $imageMapper;
85
	}
86
87
	protected function configure() {
88
		$this
89
			->setName('face:migrate')
90
			->setDescription(
91
				'Migrate the faces found in a model and analyze with the current model.')
92
			->addOption(
93
				'model',
94
				'm',
95
				InputOption::VALUE_REQUIRED,
96
				'The identifier number of the model to migrate',
97
				null,
98
			)
99
			->addOption(
100
				'user_id',
101
				'u',
102
				InputOption::VALUE_REQUIRED,
103
				'Migrate data for a given user only. If not given, migrate everything for all users.',
104
				null,
105
			);
106
	}
107
108
	/**
109
	 * @param InputInterface $input
110
	 * @param OutputInterface $output
111
	 * @return int
112
	 */
113
	protected function execute(InputInterface $input, OutputInterface $output) {
114
		// Extract user, if any
115
		//
116
		$userId = $input->getOption('user_id');
117
		if ($userId === null) {
118
			$output->writeln("You must specify the user to migrate");
119
			return 1;
120
		}
121
122
		$user = $this->userManager->get($userId);
123
		if ($user === null) {
124
			$output->writeln("User with id <$userId> is unknown.");
125
			return 1;
126
		}
127
128
		$modelId = $input->getOption('model');
129
		if (is_null($modelId)) {
130
			$output->writeln("You must indicate the ID of the model to migrate");
131
			return 1;
132
		}
133
134
		$model = $this->modelManager->getModel($modelId);
135
		if (is_null($model)) {
136
			$output->writeln("Invalid model Id");
137
			return 1;
138
		}
139
140
		if (!$model->isInstalled()) {
141
			$output->writeln("The model <$modelId> is not installed");
142
			return 1;
143
		}
144
145
		$currentModel = $this->modelManager->getCurrentModel();
146
		$currentModelId = (!is_null($currentModel)) ? $currentModel->getId() : -1;
147
148
		if ($currentModelId === $modelId) {
149
			$output->writeln("The proposed model <$modelId> to migrate must be other than the current one <$currentModelId>");
150
			return 1;
151
		}
152
153
		if (!$this->faceManagementService->hasDataForUser($userId, $modelId)) {
154
			$output->writeln("The proposed model <$modelId> to migrate is empty");
155
			return 1;
156
		}
157
158
		if ($this->faceManagementService->hasDataForUser($userId, $currentModelId)) {
159
			$output->writeln("The current model <$currentModelId> already has data. You cannot migrate to a used model.");
160
			return 1;
161
		}
162
163
		/**
164
		 * MIgrate
165
		 */
166
		$currentModel->open();
167
168
		$oldImages = $this->imageMapper->findAll($userId, $modelId);
169
170
		$progressBar = new ProgressBar($output, count($oldImages));
171
		$progressBar->start();
172
173
		foreach ($oldImages as $oldImage) {
174
			$newImage = $this->migrateImage($oldImage, $userId, $currentModelId);
175
			$oldFaces = $this->faceMapper->findFromFile($userId, $modelId, $newImage->getFile());
176
			foreach ($oldFaces as $oldFace) {
177
				$this->migrateFace($currentModel, $oldFace, $newImage);
178
			}
179
			$progressBar->advance(1);
180
		}
181
182
		$progressBar->finish();
183
	}
184
185
	private function migrateImage($oldImage, $userId, $modelId): Image {
186
		$image = new Image();
187
		$image->setUser($userId);
188
		$image->setFile($oldImage->getFile());
189
		$image->setModel($modelId);
190
		$image->setIsProcessed($oldImage->getIsProcessed());
191
		$image->setError($oldImage->getError());
0 ignored issues
show
Bug introduced by
The method setError() does not exist on OCA\FaceRecognition\Db\Image. 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

191
		$image->/** @scrutinizer ignore-call */ 
192
          setError($oldImage->getError());
Loading history...
192
		$image->setLastProcessedTime($oldImage->getLastProcessedTime());
0 ignored issues
show
Bug introduced by
The method setLastProcessedTime() does not exist on OCA\FaceRecognition\Db\Image. 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

192
		$image->/** @scrutinizer ignore-call */ 
193
          setLastProcessedTime($oldImage->getLastProcessedTime());
Loading history...
193
		$image->setProcessingDuration($oldImage->getProcessingDuration());
0 ignored issues
show
Bug introduced by
The method setProcessingDuration() does not exist on OCA\FaceRecognition\Db\Image. 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

193
		$image->/** @scrutinizer ignore-call */ 
194
          setProcessingDuration($oldImage->getProcessingDuration());
Loading history...
194
195
		return $this->imageMapper->insert($image);
196
	}
197
198
	private function migrateFace($model, $oldFace, $image) {
199
		$filePath = $this->getImageFilePath($image);
200
		$faceRect = $this->getFaceRect($oldFace);
201
202
		$face = Face::fromModel($image->getId(), $faceRect);
203
204
		$landmarks = $model->detectLandmarks($filePath, $faceRect);
205
		$descriptor = $model->computeDescriptor($filePath, $landmarks);
206
207
		$face->landmarks = $landmarks['parts'];
208
		$face->descriptor = $descriptor;
209
210
		$this->faceMapper->insertFace($face);
211
	}
212
213
	private function getImageFilePath(Image $image): ?string {
214
		$file = $this->fileService->getFileById($image->getFile(), $image->getUser());
215
		if (empty($file)) {
216
			return null;
217
		}
218
		return $this->fileService->getLocalFile($file);
219
	}
220
221
	private function getFaceRect(Face $face): array {
222
		$rect = [];
223
		$rect['left'] = (int)$face->getLeft();
224
		$rect['right'] = (int)$face->getRight();
225
		$rect['top'] =  (int)$face->getTop();
226
		$rect['bottom'] = (int)$face->getBottom();
227
		$rect['detection_confidence'] = $face->getConfidence();
228
		return $rect;
229
	}
230
231
}
232