Completed
Pull Request — master (#43)
by Janis
03:35
created

OcrService::getCorrectPath()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3.3332

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 6
cts 9
cp 0.6667
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 8
nc 4
nop 1
crap 3.3332
1
<?php
2
/**
3
 * nextCloud - ocr
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Janis Koehr <[email protected]>
9
 * @copyright Janis Koehr 2016
10
 */
11
12
namespace OCA\Ocr\Service;
13
14
use Exception;
15
use OC\Files\View;
16
use OCA\Ocr\Db\FileMapper;
17
use OCA\Ocr\Db\File;
18
use OCA\Ocr\Db\OcrStatus;
19
use OCA\Ocr\Db\OcrStatusMapper;
20
use OCA\Ocr\Db\ShareMapper;
21
use OCP\AppFramework\Db\DoesNotExistException;
22
use OCP\IL10N;
23
use OCP\ILogger;
24
use OCP\ITempManager;
25
26
27
/**
28
 * Class OcrService
29
 * @package OCA\Ocr\Service
30
 */
31
class OcrService {
32
33
	/**
34
	 * @var ILogger
35
	 */
36
	private $logger;
37
38
	/**
39
	 * @var ITempManager
40
	 */
41
	private $tempM;
42
43
	/**
44
	 * @var QueueService
45
	 */
46
	private $queueService;
47
48
	/**
49
	 * @var OcrStatusMapper
50
	 */
51
	private $statusMapper;
52
53
	/**
54
	 * @var FileMapper
55
	 */
56
	private $fileMapper;
57
58
	/**
59
	 * @var ShareMapper
60
	 */
61
	private $shareMapper;
62
63
	/**
64
	 * @var View
65
	 */
66
	private $view;
67
68
	/**
69
	 * @var
70
	 */
71
	private $userId;
72
73
	/**
74
	 * @var IL10N
75
	 */
76
	private $l10n;
77
78
	/**
79
	 * Array of allowed mimetypes for ocr processing
80
	 */
81
	const ALLOWED_MIMETYPES = ['application/pdf', 'image/png', 'image/jpeg', 'image/tiff'];
82
83
	/**
84
	 * the correct mimetype for a pdf file
85
	 */
86
	const MIMETYPE_PDF = 'application/pdf';
87
88
	/**
89
	 * the only allowed image mimetypes by tesseract
90
	 */
91
	const MIMETYPES_IMAGE = ['image/png', 'image/jpeg', 'image/tiff'];
92
93
	/**
94
	 * OcrService constructor.
95
	 *
96
	 * @param ITempManager $tempManager
97
	 * @param QueueService $queueService
98
	 * @param OcrStatusMapper $mapper
99
	 * @param View $view
100
	 * @param $userId
101
	 * @param IL10N $l10n
102
	 * @param ILogger $logger
103
	 */
104 15
	public function __construct(ITempManager $tempManager, QueueService $queueService, OcrStatusMapper $mapper, FileMapper $fileMapper, ShareMapper $shareMapper, View $view, $userId, IL10N $l10n, ILogger $logger) {
105 15
		$this->logger = $logger;
106 15
		$this->tempM = $tempManager;
107 15
		$this->queueService = $queueService;
108 15
		$this->statusMapper = $mapper;
109 15
		$this->view = $view;
110 15
		$this->userId = $userId;
111 15
		$this->l10n = $l10n;
112 15
		$this->fileMapper = $fileMapper;
113 15
		$this->shareMapper = $shareMapper;
114 15
	}
115
116
	/**
117
	 * Gets the list of all available tesseract-ocr languages.
118
	 *
119
	 * @return string[] Languages
120
	 */
121 4
	public function listLanguages() {
122
		try {
123 4
			$success = -1;
124 4
			$this->logger->debug('Fetching languages. ', ['app' => 'ocr']);
125 4
			exec('tesseract --list-langs 2>&1', $result, $success);
126 4
			if ($success === 0 && count($result) > 0) {
127 4
				if (is_array($result)) {
128 4
					$traineddata = $result;
129 4
				} else {
130
					throw new NotFoundException($this->l10n->t('No languages found.'));
131
				}
132 4
				$languages = array();
133 4
				array_shift($traineddata); // delete the first element of the array as it is a description of tesseract
134 4
				asort($traineddata); // sort the languages alphabetically
135 4
				foreach ($traineddata as $td) {
136 4
					$tdname = trim($td); // strip whitespaces
137 4
					array_push($languages, $tdname); //add to language list
138 4
				}
139 4
				$this->logger->debug('Fetched languages: ' . json_encode($languages), ['app' => 'ocr']);
140 4
				return $languages;
141
			} else {
142
				throw new NotFoundException($this->l10n->t('No languages found.'));
143
			}
144
		} catch (Exception $e) {
145
			$this->handleException($e);
146
		}
147
	}
148
149
	/**
150
	 * Processes and prepares the files for ocr.
151
	 * Sends the stuff to the client in order to ocr async.
152
	 *
153
	 * @param string $language
154
	 * @param array $files
155
	 * @return string
156
	 */
157 5
	public function process($language, $files) {
158
		try {
159 5
			$this->logger->debug('Will now process files: ' . json_encode($files) . ' with language: ' . json_encode($language), ['app' => 'ocr']);
160
			// Check if files and language not empty
161 5
			if (!empty($files) && !empty($language) && in_array($language, $this->listLanguages())) {
162
163 3
				$fileInfo = $this->buildFileInfo($files);
164
165 2
				foreach ($fileInfo as $fInfo) {
166
					// Check if filelock existing
167
					// TODO: FileLock maybe \OC\Files\View::lockFile()
168
					// Check Shared
169 2
					$source = $fInfo->getPath();
170 2
					if ($this->checkSharedWithInitiator($fInfo)) {
171
						// Shared Item
172 1
						$source = str_replace('home::','',$fInfo->getStoragename()) . '/' . $source;
173 1
						$target = $this->buildTargetForShared($fInfo);
174 1
					} else {
175
						// Not Shared
176 1
						$source = $this->userId . '/' . $source;
177 1
						$target = $this->buildTarget($fInfo);
178
					}
179
180
					// create a temp file for ocr processing purposes
181 2
					$tempFile = $this->tempM->getTemporaryFile();
182
183
					// set the running type
184 2
					if ($fInfo->getMimetype() === $this::MIMETYPE_PDF) {
185
						$ftype = 'mypdf';
186
					} else {
187 2
						$ftype = 'tess';
188
					}
189
					// Create status object
190 2
					$status = new OcrStatus('PENDING', $source, $target, $tempFile, $ftype, $this->userId, false);
191
					// Init client and send task / job
192
					// Feed the worker
193 2
					$this->queueService->clientSend($status, $language, \OC::$SERVERROOT);
194 2
				}
195 2
				return 'PROCESSING';
196
			} else {
197 2
				throw new NotFoundException($this->l10n->t('Empty parameters passed.'));
198
			}
199 3
		} catch (Exception $e) {
200 3
			$this->handleException($e);
201
		}
202
	}
203
204
	/**
205
	 * A function which returns the JSONResponse for all required status checks and tasks.
206
	 * It will check for already processed, pending and failed ocr tasks and return them as needed.
207
	 *
208
	 * @codeCoverageIgnore
209
	 * @return string
210
	 */
211
	public function status() {
212
		try {
213
			// TODO: release lock
214
215
            // returns user specific processed files
216
			$processed = $this->handleProcessed();
217
218
			$pending = $this->statusMapper->findAllPending($this->userId);
219
220
			// return user specific failed state and set up error
221
			$failed = $this->handleFailed();
222
223
			return ['processed' => count($processed), 'failed' => count($failed), 'pending' => count($pending)];
224
		} catch (Exception $e) {
225
			$this->handleException($e);
226
		}
227
	}
228
229
	/**
230
	 * The command ocr:complete for occ will call this function in order to set the status.
231
	 * the worker should call it automatically after each processing step.
232
	 *
233
	 * @param $statusId
234
	 * @param boolean $failed
235
	 */
236 3
	public function complete($statusId, $failed) {
237
		try {
238 3
			$status = $this->statusMapper->find($statusId);
239 2
			if (!$failed) {
240 1
				$status->setStatus('PROCESSED');
241 1
				$this->statusMapper->update($status);
242 1
			} else {
243 1
				$status->setStatus('FAILED');
244 1
				$this->statusMapper->update($status);
245
			}
246 3
		} catch (Exception $e) {
247 1
			$this->handleException($e);
248
		}
249 2
	}
250
251
	/**
252
	 * The PersonalSettingsController will have the opportunity to delete ocr status objects.
253
	 *
254
	 * @param $statusId
255
	 * @return OcrStatus
256
	 */
257 2
	public function deleteStatus($statusId, $userId) {
258
		try {
259 2
			$status = $this->statusMapper->find($statusId);
260 1
			if ($status->getUserId() !== $userId) {
261
				throw new NotFoundException($this->l10n->t('Cannot delete. Wrong owner.'));
262
			} else {
263 1
				$status = $this->statusMapper->delete($status);
264
			}
265 1
			$status->setTarget($this->removeFileExtension($status));
266 1
            $status->setSource(null);
267 1
            $status->setTempFile(null);
268 1
            $status->setType(null);
269 1
            $status->setErrorDisplayed(null);
270 1
			return $status;
271 1
		} catch (Exception $e) {
272 1
		    if ($e instanceof DoesNotExistException) {
0 ignored issues
show
Bug introduced by
The class OCP\AppFramework\Db\DoesNotExistException does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
273 1
		        $ex = new NotFoundException($this->l10n->t('Cannot delete. Wrong id.'));
274 1
                $this->handleException($ex);
275
            } else {
276
		        $this->handleException($e);
277
		    }
278
		}
279
	}
280
281
	/**
282
	 * Gets all status objects for a specific user in order to list them on the personal settings page.
283
	 *
284
	 * @param $userId
285
	 * @return array
286
	 */
287 1
	public function getAllForPersonal($userId) {
288
	    try {
289 1
            $status = $this->statusMapper->findAll($userId);
290 1
            $statusNew = array();
291 1
			for ($x = 0; $x < count($status); $x++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
292 1
				$newName = $this->removeFileExtension($status[$x]);
293 1
				$status[$x]->setTarget($newName);
294 1
				$status[$x]->setSource(null);
295 1
				$status[$x]->setTempFile(null);
296 1
				$status[$x]->setType(null);
297 1
				$status[$x]->setErrorDisplayed(null);
298 1
				array_push($statusNew, $status[$x]);
299 1
			}
300 1
            return $statusNew;
301
        } catch (Exception $e) {
302
	        $this->handleException($e);
303
        }
304
    }
305
306
	/**
307
	 * Returns a not existing file name for pdf or image processing
308
	 * protected as of testing issues with static methods. (Actually
309
	 * it will be mocked partially) FIXME: Change this behaviour as soon as the buidlNotExistingFileName function is not static anymore
310
	 *
311
	 * @param File $fileInfo
312
	 * @return string
313
	 */
314
	protected function buildTargetForShared(File $fileInfo) {
315
		try {
316
			$share = $this->shareMapper->find($fileInfo->getFileid(), $this->userId, str_replace('home::','',$fileInfo->getStoragename()));
317
318
			// get rid of the .png or .pdf and so on
319
			$fileName = substr($share->getFileTarget(), 0, -4); // '/thedom.png' => '/thedom' || '/Test/thedom.png' => '/Test/thedom'
1 ignored issue
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
320
321
			// remove everything in front of and including of the first appearance of a slash from behind
322
			$fileName = substr(strrchr($fileName, "/"), 1); // '/thedom' => 'thedom' || '/Test/thedom' => 'thedom'
1 ignored issue
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
323
324
			// eliminate the file name from the path
325
			$filePath = dirname($share->getFileTarget()); // '/thedom.png' => '/' || '/Test/thedom.png' => '/Test'
1 ignored issue
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
326
327
			// replace the first slash
328
			$pos = strpos($filePath, '/');
329
			if ($pos !== false) {
330
				$filePath = substr_replace($filePath, '', $pos, strlen('/')); // '/' => '' || '/Test/' => 'Test'
1 ignored issue
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
331
			}
332
333 View Code Duplication
			if ($fileInfo->getMimetype() === $this::MIMETYPE_PDF) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
334
				// PDFs:
335
				return \OCP\Files::buildNotExistingFileName($filePath, $fileName . '_OCR.pdf');
336
			} else {
337
				// IMAGES:
338
				return \OCP\Files::buildNotExistingFileName($filePath, $fileName . '_OCR.txt');
339
			}
340
		} catch (Exception $e) {
341
			$this->handleException($e);
342
		}
343
	}
344
345
	/**
346
	 * Returns a not existing file name for pdf or image processing
347
	 * protected as of testing issues with static methods. (Actually
348
	 * it will be mocked partially) FIXME: Change this behaviour as soon as the buidlNotExistingFileName function is not static anymore
349
	 *
350
	 * @param File $fileInfo
351
	 * @return string
352
	 */
353
	protected function buildTarget(File $fileInfo) {
354
		try {
355
			// get rid of the .png or .pdf and so on
356
			$fileName = substr($fileInfo->getName(), 0, -4); // 'thedom.png' => 'thedom'
2 ignored issues
show
Bug introduced by
Consider using $fileInfo->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
357
358
			// eliminate the file name from the path
359
			$filePath = str_replace($fileInfo->getName(), '', $fileInfo->getPath()); // 'files/Test/thedom.png' => 'files/Test/' || 'files/thedom.png' => 'files/'
2 ignored issues
show
Bug introduced by
Consider using $fileInfo->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
360
361
			// and get the path on top of the files/ dir
362
			$filePath = str_replace('files', '', $filePath); // 'files/Test/' => '/Test/' || 'files/' => '/'
1 ignored issue
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
363
364
			// remove the last slash
365
			$filePath = substr_replace($filePath,'',strrpos($filePath,'/'),strlen('/')); // '/Test/' => '/Test' || '/' => ''
1 ignored issue
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
366
367
			// replace the first slash
368
			$pos = strpos($filePath, '/');
369
			if ($pos !== false) {
370
				$filePath = substr_replace($filePath, '', $pos, strlen('/')); // '/Test' => '// 'Test' || '/' => ''
371
			}
372
373 View Code Duplication
			if ($fileInfo->getMimetype() === $this::MIMETYPE_PDF) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
374
				// PDFs:
375
				return \OCP\Files::buildNotExistingFileName($filePath, $fileName . '_OCR.pdf');
376
			} else {
377
				// IMAGES:
378
				return \OCP\Files::buildNotExistingFileName($filePath, $fileName . '_OCR.txt');
379
			}
380
		} catch (Exception $e) {
381
			$this->handleException($e);
382
		}
383
	}
384
385
386
	/**
387
	 * Returns the fileInfo for each file in files and checks
388
	 * if it has a allowed mimetype and some other conditions.
389
	 *
390
	 * @param array $files
391
	 * @return File[]
392
	 * @throws NotFoundException
393
	 */
394 3
	private function buildFileInfo($files) {
395
		try {
396 3
			$fileArray = array();
397 3
			foreach ($files as $file) {
398
				// Check if anything is missing and file type is correct
399 3
				if (!empty($file['id'])) {
400
401 3
					$fileInfo = $this->fileMapper->find($file['id']);
402 3
					$this->checkMimeType($fileInfo);
403
404 2
					array_push($fileArray, $fileInfo);
405 2
				} else {
406
					throw new NotFoundException($this->l10n->t('Wrong parameter.'));
407
				}
408 2
			}
409 2
			return $fileArray;
410 1
		} catch (Exception $e) {
411 1
			$this->handleException($e);
412
		}
413
	}
414
415
	/**
416
	 * Checks a Mimetype for a specific given FileInfo.
417
	 * @param File $fileInfo
418
	 */
419 3
	private function checkMimeType(File $fileInfo) {
420
		try {
421 3
			if (!$fileInfo || !in_array($fileInfo->getMimetype(), $this::ALLOWED_MIMETYPES)) {
422 1
				$this->logger->debug('Getting FileInfo did not work or not included in the ALLOWED_MIMETYPES array.', ['app' => 'ocr']);
423 1
				throw new NotFoundException($this->l10n->t('Wrong mimetype.'));
424
			}
425 3
		} catch (Exception $e) {
426 1
			$this->handleException($e);
427
		}
428 2
	}
429
430
	/**
431
	 * @param File $fileInfo
432
	 * @return bool
433
	 */
434 2
	private function checkSharedWithInitiator($fileInfo) {
435
		try {
436 2
			$owner = str_replace('home::','',$fileInfo->getStoragename());
437 2
			if ($this->userId === $owner){
438
				// user is owner (no shared file)
439 1
				return false;
440
			} else {
441
				// user is not owner (shared file)
442 1
				return true;
443
			}
444
		} catch (Exception $e) {
445
			$this->handleException($e);
446
		}
447
448
	}
449
450
	/**
451
	 * Finishes all Processed files by copying them to the right path and deleteing the temp files.
452
	 * Returns the number of processed files.
453
	 *
454
	 * @codeCoverageIgnore
455
	 * @return array
456
	 */
457
	private function handleProcessed() {
458
		try {
459
			$this->logger->debug('Check if files were processed by ocr and if so, put them to the right dirs.', ['app' => 'ocr']);
460
			$processed = $this->statusMapper->findAllProcessed($this->userId);
461
			foreach ($processed as $status) {
462
				if ($status->getType() === 'tess' && file_exists($status->getTempFile() . '.txt')) {
463
					//Save the tmp file with newname
464
					$this->view->file_put_contents($status->getTarget(), file_get_contents($status->getTempFile() . '.txt')); // need .txt because tesseract saves it like this
465
					// Cleaning temp files
466
					$this->statusMapper->delete($status);
467
					exec('rm ' . $status->getTempFile() . '.txt');
468
				} elseif ($status->getType() === 'mypdf' && file_exists($status->getTempFile())) {
469
					//Save the tmp file with newname
470
					$this->view->file_put_contents($status->getTarget(), file_get_contents($status->getTempFile())); // don't need to extend with .pdf / it uses the tmp file to save
471
					$this->statusMapper->delete($status);
472
					exec('rm ' . $status->getTempFile());
473
				} else {
474
					throw new NotFoundException($this->l10n->t('Temp file does not exist.'));
475
				}
476
			}
477
			return $processed;
478
		} catch (Exception $e) {
479
			$this->handleException($e);
480
		}
481
	}
482
483
	/**
484
	 * Removes ".txt" from the newName of a ocr status
485
	 *
486
	 * @param $status OcrStatus
487
	 * @return string
488
	 */
489 2
	private function removeFileExtension($status) {
490
		try {
491 2
			return substr($status->getTarget(), 0, strrpos($status->getTarget(),'_OCR'));
492
		} catch (Exception $e) {
493
			$this->handleException($e);
494
		}
495
	}
496
497
	/**
498
	 * Handles all failed orders of ocr processing queue and returns the status objects.
499
	 *
500
	 * @codeCoverageIgnore
501
	 * @return array
502
	 */
503
	private function handleFailed() {
504
		try {
505
			$failed = $this->statusMapper->findAllFailed($this->userId);
506
			foreach ($failed as $status) {
507
				// clean the tempfile
508
				exec('rm ' . $status->getTempFile());
509
				// set error displayed
510
				$status->setErrorDisplayed(true);
511
				$this->statusMapper->update($status);
512
			}
513
			$this->logger->debug('Following status objects failed: ' . json_encode($failed), ['app' => 'ocr']);
514
			return $failed;
515
		} catch (Exception $e) {
516
			$this->handleException($e);
517
		}
518
	}
519
520
	/**
521
	 * Handle the possible thrown Exceptions from all methods of this class.
522
	 *
523
	 * @param Exception $e
524
	 * @throws Exception
525
	 * @throws NotFoundException
526
	 */
527 5 View Code Duplication
	private function handleException($e) {
528 5
		$this->logger->logException($e, ['app' => 'ocr', 'message' => 'Exception during ocr service function processing']);
529 5
		if ($e instanceof NotFoundException) {
530 5
			throw new NotFoundException($e->getMessage());
531
		} else {
532
			throw $e;
533
		}
534
	}
535
}
536