Completed
Pull Request — master (#43)
by Janis
02:45
created

OcrService::complete()   A

Complexity

Conditions 3
Paths 7

Size

Total Lines 14
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 11
cts 11
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 11
nc 7
nop 2
crap 3
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
	 * @param string $userId
256
	 * @return OcrStatus
257
	 */
258 2
	public function deleteStatus($statusId, $userId) {
259
		try {
260 2
			$status = $this->statusMapper->find($statusId);
261 1
			if ($status->getUserId() !== $userId) {
262
				throw new NotFoundException($this->l10n->t('Cannot delete. Wrong owner.'));
263
			} else {
264 1
				$status = $this->statusMapper->delete($status);
265
			}
266 1
			$status->setTarget($this->removeFileExtension($status));
267 1
			$status->setSource(null);
268 1
			$status->setTempFile(null);
269 1
			$status->setType(null);
270 1
			$status->setErrorDisplayed(null);
271 1
			return $status;
272 1
		} catch (Exception $e) {
273 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...
274 1
				$ex = new NotFoundException($this->l10n->t('Cannot delete. Wrong id.'));
275 1
				$this->handleException($ex);
276
			} else {
277
				$this->handleException($e);
278
			}
279
		}
280
	}
281
282
	/**
283
	 * Gets all status objects for a specific user in order to list them on the personal settings page.
284
	 *
285
	 * @param string $userId
286
	 * @return array
287
	 */
288 1
	public function getAllForPersonal($userId) {
289
		try {
290 1
			$status = $this->statusMapper->findAll($userId);
291 1
			$statusNew = array();
292 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...
293 1
				$newName = $this->removeFileExtension($status[$x]);
294 1
				$status[$x]->setTarget($newName);
295 1
				$status[$x]->setSource(null);
296 1
				$status[$x]->setTempFile(null);
297 1
				$status[$x]->setType(null);
298 1
				$status[$x]->setErrorDisplayed(null);
299 1
				array_push($statusNew, $status[$x]);
300 1
			}
301 1
			return $statusNew;
302
		} catch (Exception $e) {
303
			$this->handleException($e);
304
		}
305
	}
306
307
	/**
308
	 * Returns a not existing file name for pdf or image processing
309
	 * protected as of testing issues with static methods. (Actually
310
	 * it will be mocked partially) FIXME: Change this behaviour as soon as the buidlNotExistingFileName function is not static anymore
311
	 *
312
	 * @param File $fileInfo
313
	 * @return string
314
	 */
315
	protected function buildTargetForShared(File $fileInfo) {
316
		try {
317
			$share = $this->shareMapper->find($fileInfo->getFileid(), $this->userId, str_replace('home::', '', $fileInfo->getStoragename()));
318
319
			// get rid of the .png or .pdf and so on
320
			$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...
321
322
			// remove everything in front of and including of the first appearance of a slash from behind
323
			$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...
324
325
			// eliminate the file name from the path
326
			$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...
327
328
			// replace the first slash
329
			$pos = strpos($filePath, '/');
330
			if ($pos !== false) {
331
				$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...
332
			}
333
334 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...
335
				// PDFs:
336
				return \OCP\Files::buildNotExistingFileName($filePath, $fileName . '_OCR.pdf');
337
			} else {
338
				// IMAGES:
339
				return \OCP\Files::buildNotExistingFileName($filePath, $fileName . '_OCR.txt');
340
			}
341
		} catch (Exception $e) {
342
			$this->handleException($e);
343
		}
344
	}
345
346
	/**
347
	 * Returns a not existing file name for pdf or image processing
348
	 * protected as of testing issues with static methods. (Actually
349
	 * it will be mocked partially) FIXME: Change this behaviour as soon as the buidlNotExistingFileName function is not static anymore
350
	 *
351
	 * @param File $fileInfo
352
	 * @return string
353
	 */
354
	protected function buildTarget(File $fileInfo) {
355
		try {
356
			// get rid of the .png or .pdf and so on
357
			$fileName = substr($fileInfo->getName(), 0, -4); // 'thedom.png' => '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...
358
359
			// eliminate the file name from the path
360
			$filePath = str_replace($fileInfo->getName(), '', $fileInfo->getPath()); // 'files/Test/thedom.png' => 'files/Test/' || 'files/thedom.png' => '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...
361
362
			// and get the path on top of the files/ dir
363
			$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...
364
365
			// remove the last slash
366
			$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...
367
368
			// replace the first slash
369
			$pos = strpos($filePath, '/');
370
			if ($pos !== false) {
371
				$filePath = substr_replace($filePath, '', $pos, strlen('/')); // '/Test' => '// 'Test' || '/' => ''
372
			}
373
374 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...
375
				// PDFs:
376
				return \OCP\Files::buildNotExistingFileName($filePath, $fileName . '_OCR.pdf');
377
			} else {
378
				// IMAGES:
379
				return \OCP\Files::buildNotExistingFileName($filePath, $fileName . '_OCR.txt');
380
			}
381
		} catch (Exception $e) {
382
			$this->handleException($e);
383
		}
384
	}
385
386
387
	/**
388
	 * Returns the fileInfo for each file in files and checks
389
	 * if it has a allowed mimetype and some other conditions.
390
	 *
391
	 * @param array $files
392
	 * @return File[]
393
	 * @throws NotFoundException
394
	 */
395 3
	private function buildFileInfo($files) {
396
		try {
397 3
			$fileArray = array();
398 3
			foreach ($files as $file) {
399
				// Check if anything is missing and file type is correct
400 3
				if (!empty($file['id'])) {
401
402 3
					$fileInfo = $this->fileMapper->find($file['id']);
403 3
					$this->checkMimeType($fileInfo);
404
405 2
					array_push($fileArray, $fileInfo);
406 2
				} else {
407
					throw new NotFoundException($this->l10n->t('Wrong parameter.'));
408
				}
409 2
			}
410 2
			return $fileArray;
411 1
		} catch (Exception $e) {
412 1
			$this->handleException($e);
413
		}
414
	}
415
416
	/**
417
	 * Checks a Mimetype for a specific given FileInfo.
418
	 * @param File $fileInfo
419
	 */
420 3
	private function checkMimeType(File $fileInfo) {
421
		try {
422 3
			if (!$fileInfo || !in_array($fileInfo->getMimetype(), $this::ALLOWED_MIMETYPES)) {
423 1
				$this->logger->debug('Getting FileInfo did not work or not included in the ALLOWED_MIMETYPES array.', ['app' => 'ocr']);
424 1
				throw new NotFoundException($this->l10n->t('Wrong mimetype.'));
425
			}
426 3
		} catch (Exception $e) {
427 1
			$this->handleException($e);
428
		}
429 2
	}
430
431
	/**
432
	 * @param File $fileInfo
433
	 * @return boolean|null
434
	 */
435 2
	private function checkSharedWithInitiator($fileInfo) {
436
		try {
437 2
			$owner = str_replace('home::', '', $fileInfo->getStoragename());
438 2
			if ($this->userId === $owner) {
439
				// user is owner (no shared file)
440 1
				return false;
441
			} else {
442
				// user is not owner (shared file)
443 1
				return true;
444
			}
445
		} catch (Exception $e) {
446
			$this->handleException($e);
447
		}
448
449
	}
450
451
	/**
452
	 * Finishes all Processed files by copying them to the right path and deleteing the temp files.
453
	 * Returns the number of processed files.
454
	 *
455
	 * @codeCoverageIgnore
456
	 * @return array
457
	 */
458
	private function handleProcessed() {
459
		try {
460
			$this->logger->debug('Check if files were processed by ocr and if so, put them to the right dirs.', ['app' => 'ocr']);
461
			$processed = $this->statusMapper->findAllProcessed($this->userId);
462
			foreach ($processed as $status) {
463
				if ($status->getType() === 'tess' && file_exists($status->getTempFile() . '.txt')) {
464
					//Save the tmp file with newname
465
					$this->view->file_put_contents($status->getTarget(), file_get_contents($status->getTempFile() . '.txt')); // need .txt because tesseract saves it like this
466
					// Cleaning temp files
467
					$this->statusMapper->delete($status);
468
					exec('rm ' . $status->getTempFile() . '.txt');
469
				} elseif ($status->getType() === 'mypdf' && file_exists($status->getTempFile())) {
470
					//Save the tmp file with newname
471
					$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
472
					$this->statusMapper->delete($status);
473
					exec('rm ' . $status->getTempFile());
474
				} else {
475
					throw new NotFoundException($this->l10n->t('Temp file does not exist.'));
476
				}
477
			}
478
			return $processed;
479
		} catch (Exception $e) {
480
			$this->handleException($e);
481
		}
482
	}
483
484
	/**
485
	 * Removes ".txt" from the newName of a ocr status
486
	 *
487
	 * @param $status OcrStatus
488
	 * @return string
489
	 */
490 2
	private function removeFileExtension($status) {
491
		try {
492 2
			return substr($status->getTarget(), 0, strrpos($status->getTarget(), '_OCR'));
493
		} catch (Exception $e) {
494
			$this->handleException($e);
495
		}
496
	}
497
498
	/**
499
	 * Handles all failed orders of ocr processing queue and returns the status objects.
500
	 *
501
	 * @codeCoverageIgnore
502
	 * @return array
503
	 */
504
	private function handleFailed() {
505
		try {
506
			$failed = $this->statusMapper->findAllFailed($this->userId);
507
			foreach ($failed as $status) {
508
				// clean the tempfile
509
				exec('rm ' . $status->getTempFile());
510
				// set error displayed
511
				$status->setErrorDisplayed(true);
512
				$this->statusMapper->update($status);
513
			}
514
			$this->logger->debug('Following status objects failed: ' . json_encode($failed), ['app' => 'ocr']);
515
			return $failed;
516
		} catch (Exception $e) {
517
			$this->handleException($e);
518
		}
519
	}
520
521
	/**
522
	 * Handle the possible thrown Exceptions from all methods of this class.
523
	 *
524
	 * @param Exception $e
525
	 * @throws Exception
526
	 * @throws NotFoundException
527
	 */
528 5 View Code Duplication
	private function handleException($e) {
529 5
		$this->logger->logException($e, ['app' => 'ocr', 'message' => 'Exception during ocr service function processing']);
530 5
		if ($e instanceof NotFoundException) {
531 5
			throw new NotFoundException($e->getMessage());
532
		} else {
533
			throw $e;
534
		}
535
	}
536
}
537