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