Passed
Pull Request — master (#123)
by
unknown
06:40
created

ToolboxController::renderTools()   D

Complexity

Conditions 20
Paths 20

Size

Total Lines 45
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 20
eloc 41
c 1
b 0
f 0
nc 20
nop 0
dl 0
loc 45
rs 4.1666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * (c) Kitodo. Key to digital objects e.V. <[email protected]>
4
 *
5
 * This file is part of the Kitodo and TYPO3 projects.
6
 *
7
 * @license GNU General Public License version 3 or later.
8
 * For the full copyright and license information, please read the
9
 * LICENSE.txt file that was distributed with this source code.
10
 */
11
12
namespace Kitodo\Dlf\Controller;
13
14
use Kitodo\Dlf\Common\AbstractDocument;
15
use Kitodo\Dlf\Common\Helper;
16
use TYPO3\CMS\Core\Utility\GeneralUtility;
17
use TYPO3\CMS\Core\Utility\MathUtility;
18
19
/**
20
 * Controller class for plugin 'Toolbox'.
21
 *
22
 * @package TYPO3
23
 * @subpackage dlf
24
 *
25
 * @access public
26
 */
27
class ToolboxController extends AbstractController
28
{
29
30
    /**
31
     * @access private
32
     * @var AbstractDocument This holds the current document
33
     */
34
    private AbstractDocument $currentDocument;
35
36
    /**
37
     * The main method of the plugin
38
     *
39
     * @access public
40
     *
41
     * @return void
42
     */
43
    public function mainAction(): void
44
    {
45
        // Load current document.
46
        $this->loadDocument();
47
48
        $this->view->assign('double', $this->requestData['double']);
49
50
        if (!$this->isDocMissingOrEmpty()) {
51
            $this->currentDocument = $this->document->getCurrentDocument();
52
        }
53
54
        $this->renderTools();
55
        $this->view->assign('viewData', $this->viewData);
56
    }
57
58
    /**
59
     * Renders tool in the toolbox.
60
     *
61
     * @access private
62
     *
63
     * @return void
64
     */
65
    private function renderTools(): void
66
    {
67
        if (!empty($this->settings['tools'])) {
68
69
            $tools = explode(',', $this->settings['tools']);
70
71
            foreach ($tools as $tool) {
72
                switch ($tool) {
73
                    case 'tx_dlf_annotationtool':
74
                    case 'annotationtool':
75
                        $this->renderToolByName('renderAnnotationTool');
76
                        break;
77
                    case 'tx_dlf_fulltextdownloadtool':
78
                    case 'fulltextdownloadtool':
79
                        $this->renderToolByName('renderFulltextDownloadTool');
80
                        break;
81
                    case 'tx_dlf_fulltexttool':
82
                    case 'fulltexttool':
83
                        $this->renderToolByName('renderFulltextTool');
84
                        break;
85
                    case 'tx_dlf_imagedownloadtool':
86
                    case 'imagedownloadtool':
87
                        $this->renderToolByName('renderImageDownloadTool');
88
                        break;
89
                    case 'tx_dlf_imagemanipulationtool':
90
                    case 'imagemanipulationtool':
91
                        $this->renderToolByName('renderImageManipulationTool');
92
                        break;
93
                    case 'tx_dlf_modeldownloadtool':
94
                    case 'modeldownloadtool':
95
                        $this->renderToolByName('renderModelDownloadTool');
96
                        break;
97
                    case 'tx_dlf_pdfdownloadtool':
98
                    case 'pdfdownloadtool':
99
                        $this->renderToolByName('renderPdfDownloadTool');
100
                        break;
101
                    case 'tx_dlf_searchindocumenttool':
102
                    case 'searchindocumenttool':
103
                        $this->renderToolByName('renderSearchInDocumentTool');
104
                        break;
105
                    case 'scoretool':
106
                        $this->renderToolByName('renderScoreTool');
107
                        break;
108
                    default:
109
                        $this->logger->warning('Incorrect tool configuration: "' . $this->settings['tools'] . '". Tool "' . $tool . '" does not exist.');
0 ignored issues
show
Bug introduced by
The method warning() does not exist on null. ( Ignorable by Annotation )

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

109
                        $this->logger->/** @scrutinizer ignore-call */ 
110
                                       warning('Incorrect tool configuration: "' . $this->settings['tools'] . '". Tool "' . $tool . '" does not exist.');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
110
                }
111
            }
112
        }
113
    }
114
115
    /**
116
     * Renders tool by the name in the toolbox.
117
     *
118
     * @access private
119
     *
120
     * @param string $tool name
121
     *
122
     * @return void
123
     */
124
    private function renderToolByName(string $tool): void
125
    {
126
        $this->$tool();
127
        $this->view->assign($tool, true);
128
    }
129
130
    /**
131
     * Get image's URL and MIME type information's.
132
     *
133
     * @access private
134
     *
135
     * @param int $page Page number
136
     *
137
     * @return array Array of image information's.
138
     */
139
    public function getImage(int $page): array
140
    {
141
        // Get @USE value of METS fileGroup.
142
        $image = $this->getFile($page, GeneralUtility::trimExplode(',', $this->settings['fileGrpsImageDownload']));
143
        switch ($image['mimetype']) {
144
            case 'image/jpeg':
145
                $image['mimetypeLabel'] = ' (JPG)';
146
                break;
147
            case 'image/tiff':
148
                $image['mimetypeLabel'] = ' (TIFF)';
149
                break;
150
            default:
151
                $image['mimetypeLabel'] = '';
152
        }
153
        return $image;
154
    }
155
156
    /**
157
     * Renders the annotation tool (used in template)
158
     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
159
     *
160
     * @access private
161
     *
162
     * @return void
163
     */
164
    private function renderAnnotationTool(): void
165
    {
166
        if ($this->isDocMissingOrEmpty()) {
167
            // Quit without doing anything if required variables are not set.
168
            return;
169
        }
170
171
        $this->setPage();
172
173
        $annotationContainers = $this->currentDocument->physicalStructureInfo[$this->currentDocument->physicalStructure[$this->requestData['page']]]['annotationContainers'];
174
        if (
175
            $annotationContainers != null
176
            && count($annotationContainers) > 0
177
        ) {
178
            $this->view->assign('annotationTool', true);
179
        } else {
180
            $this->view->assign('annotationTool', false);
181
        }
182
    }
183
184
    /**
185
     * Renders the fulltext download tool (used in template)
186
     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
187
     *
188
     * @access private
189
     *
190
     * @return void
191
     */
192
    private function renderFulltextDownloadTool(): void
193
    {
194
        if (
195
            $this->isDocMissingOrEmpty()
196
            || empty($this->extConf['files']['fileGrpFulltext'])
197
        ) {
198
            // Quit without doing anything if required variables are not set.
199
            return;
200
        }
201
202
        $this->setPage();
203
204
        // Get text download.
205
        $this->view->assign('fulltextDownload', !$this->isFullTextEmpty());
206
    }
207
208
    /**
209
     * Renders the fulltext tool (used in template)
210
     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
211
     *
212
     * @access private
213
     *
214
     * @return void
215
     */
216
    private function renderFulltextTool(): void
217
    {
218
        if (
219
            $this->isDocMissingOrEmpty()
220
            || empty($this->extConf['files']['fileGrpFulltext'])
221
        ) {
222
            // Quit without doing anything if required variables are not set.
223
            return;
224
        }
225
226
        $this->setPage();
227
228
        if (!$this->isFullTextEmpty()) {
229
            $this->view->assign('fulltext', true);
230
            $this->view->assign('activateFullTextInitially', MathUtility::forceIntegerInRange($this->settings['activateFullTextInitially'], 0, 1, 0));
231
        } else {
232
            $this->view->assign('fulltext', false);
233
        }
234
    }
235
236
    /**
237
     * Renders the score tool
238
     *
239
     * @return void
240
     */
241
    public function renderScoreTool()
242
    {
243
        if (
244
            $this->isDocMissingOrEmpty()
245
            || empty($this->extConf['files']['fileGrpScore'])
246
        ) {
247
            // Quit without doing anything if required variables are not set.
248
            return;
249
        }
250
251
        if ($this->requestData['page']) {
252
            $currentPhysPage = $this->document->getCurrentDocument()->physicalStructure[$this->requestData['page']];
253
        } else {
254
            $currentPhysPage = $this->document->getCurrentDocument()->physicalStructure[1];
255
        }
256
257
        $fileGrpsScores = GeneralUtility::trimExplode(',', $this->extConf['files']['fileGrpScore']);
258
        foreach ($fileGrpsScores as $fileGrpScore) {
259
            if ($this->document->getCurrentDocument()->physicalStructureInfo[$currentPhysPage]['files'][$fileGrpScore]) {
260
                $scoreFile = $this->document->getCurrentDocument()->physicalStructureInfo[$currentPhysPage]['files'][$fileGrpScore];
261
            }
262
        }
263
        if (!empty($scoreFile)) {
264
            $this->view->assign('score', true);
265
            $this->view->assign('activateScoreInitially', MathUtility::forceIntegerInRange($this->settings['activateScoreInitially'], 0, 1, 0));
266
        } else {
267
            $this->view->assign('score', false);
268
        }
269
    }
270
271
    /**
272
     * List of common web image mimetypes
273
     * The MIMETYPE attribute must specify the media type of the digital representation. All web-compatible formats as per RFC2046 are allowed.
274
     */
275
    private const IMAGE_MIMETYPES = [
276
        "image/jpeg",
277
        "image/jpg",
278
        "image/png",
279
        "image/gif",
280
        "image/bmp",
281
        "image/tiff",
282
        "image/x-tiff",
283
        "image/webp",
284
        "image/svg+xml",
285
        "image/vnd.microsoft.icon",
286
        "image/x-icon",
287
        "image/heif",
288
        "image/heic",
289
        "image/vnd.adobe.photoshop",
290
        "image/x-xbitmap",
291
        "image/x-xpixmap",
292
        "image/jp2",
293
        "image/jpx",
294
        "image/jpm",
295
        "image/mj2",
296
        "image/x-portable-anymap",
297
        "image/x-portable-bitmap",
298
        "image/x-portable-graymap",
299
        "image/x-portable-pixmap"
300
    ];
301
302
    /**
303
     * Renders the image download tool
304
     * Renders the image download tool (used in template)
305
     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
306
     *
307
     * @access private
308
     *
309
     * @return void
310
     */
311
    private function renderImageDownloadTool(): void
312
    {
313
        if (
314
            $this->isDocMissingOrEmpty()
315
            || empty($this->settings['fileGrpsImageDownload'])
316
        ) {
317
            // Quit without doing anything if required variables are not set.
318
            return;
319
        }
320
321
        $this->setPage();
322
323
        $imageArray = [];
324
        // Get left or single page download.
325
        $image = $this->getImage($this->requestData['page']);
326
        if ($this->filterImageFiles($image)) {
327
            $imageArray[0] = $image;
328
        }
329
330
        if ($this->requestData['double'] == 1) {
331
            $image = $this->getImage($this->requestData['page'] + 1);
332
            if ($this->filterImageFiles($image)) {
333
                $imageArray[1] = $image;
334
            }
335
        }
336
337
        $this->view->assign('imageDownload', $imageArray);
338
    }
339
340
    /**
341
     * Filters an image file based on its mimetype.
342
     *
343
     * This method checks if the provided image array contains a 'mimetype' key and
344
     * verifies if the mimetype is one of the supported image types defined in the class constant IMAGE_MIMETYPES.
345
     *
346
     * @param mixed $image The image array to filter
347
     *
348
     * @return bool True if the image mimetype is supported, false otherwise
349
     */
350
    private function filterImageFiles($image): bool
351
    {
352
        if (is_array($image) && isset($image['mimetype'])) {
353
            return in_array($image['mimetype'], self::IMAGE_MIMETYPES);
354
        }
355
        return false;
356
    }
357
358
    /**
359
     * Get file's URL and MIME type
360
     *
361
     * @access private
362
     *
363
     * @param int $page Page number
364
     *
365
     * @return array Array of file information
366
     */
367
    private function getFile(int $page, array $fileGrps): array
368
    {
369
        $file = [];
370
        while ($fileGrp = @array_pop($fileGrps)) {
371
            $physicalStructureInfo = $this->currentDocument->physicalStructureInfo[$this->currentDocument->physicalStructure[$page]];
372
            $fileId = $physicalStructureInfo['files'][$fileGrp];
373
            if (!empty($fileId)) {
374
                $file['url'] = $this->currentDocument->getDownloadLocation($fileId);
375
                $file['mimetype'] = $this->currentDocument->getFileMimeType($fileId);
376
            } else {
377
                $this->logger->warning('File not found in fileGrp "' . $fileGrp . '"');
378
            }
379
        }
380
        return $file;
381
    }
382
383
    /**
384
     * Renders the image manipulation tool (used in template)
385
     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
386
     *
387
     * @access private
388
     *
389
     * @return void
390
     */
391
    private function renderImageManipulationTool(): void
392
    {
393
        // Set parent element for initialization.
394
        $parentContainer = !empty($this->settings['parentContainer']) ? $this->settings['parentContainer'] : '.tx-dlf-imagemanipulationtool';
395
396
        $this->view->assign('imageManipulation', true);
397
        $this->view->assign('parentContainer', $parentContainer);
398
    }
399
400
    /**
401
     * Renders the model download tool
402
     * Renders the model download tool (used in template)
403
     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
404
     *
405
     * @access private
406
     *
407
     * @return void
408
     */
409
    private function renderModelDownloadTool(): void
410
    {
411
        if (
412
            $this->isDocMissingOrEmpty()
413
            || empty($this->settings['fileGrpsModelDownload'])
414
        ) {
415
            // Quit without doing anything if required variables are not set.
416
            return;
417
        }
418
419
        $this->setPage();
420
421
        $this->view->assign('modelDownload', $this->getFile($this->requestData['page'], GeneralUtility::trimExplode(',', $this->settings['fileGrpsModelDownload'])));
422
    }
423
424
    /**
425
     * Renders the PDF download tool (used in template)
426
     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
427
     *
428
     * @access private
429
     *
430
     * @return void
431
     */
432
    private function renderPdfDownloadTool(): void
433
    {
434
        if (
435
            $this->isDocMissingOrEmpty()
436
            || empty($this->extConf['files']['fileGrpDownload'])
437
        ) {
438
            // Quit without doing anything if required variables are not set.
439
            return;
440
        }
441
442
        $this->setPage();
443
444
        // Get single page downloads.
445
        $this->view->assign('pageLinks', $this->getPageLink());
446
        // Get work download.
447
        $this->view->assign('workLink', $this->getWorkLink());
448
    }
449
450
    /**
451
     * Get page's download link
452
     *
453
     * @access private
454
     *
455
     * @return array Link to downloadable page
456
     */
457
    private function getPageLink(): array
458
    {
459
        $firstPageLink = '';
460
        $secondPageLink = '';
461
        $pageLinkArray = [];
462
        $pageNumber = $this->requestData['page'];
463
        $fileGrpsDownload = GeneralUtility::trimExplode(',', $this->extConf['files']['fileGrpDownload']);
464
        // Get image link.
465
        while ($fileGrpDownload = array_shift($fileGrpsDownload)) {
466
            $firstFileGroupDownload = $this->currentDocument->physicalStructureInfo[$this->currentDocument->physicalStructure[$pageNumber]]['files'][$fileGrpDownload];
467
            if (!empty($firstFileGroupDownload)) {
468
                $firstPageLink = $this->currentDocument->getFileLocation($firstFileGroupDownload);
469
                // Get second page, too, if double page view is activated.
470
                $secondFileGroupDownload = $this->currentDocument->physicalStructureInfo[$this->currentDocument->physicalStructure[$pageNumber + 1]]['files'][$fileGrpDownload];
471
                if (
472
                    $this->requestData['double']
473
                    && $pageNumber < $this->currentDocument->numPages
474
                    && !empty($secondFileGroupDownload)
475
                ) {
476
                    $secondPageLink = $this->currentDocument->getFileLocation($secondFileGroupDownload);
477
                }
478
                break;
479
            }
480
        }
481
        if (
482
            empty($firstPageLink)
483
            && empty($secondPageLink)
484
        ) {
485
            $this->logger->warning('File not found in fileGrps "' . $this->extConf['files']['fileGrpDownload'] . '"');
486
        }
487
488
        if (!empty($firstPageLink)) {
489
            $pageLinkArray[0] = $firstPageLink;
490
        }
491
        if (!empty($secondPageLink)) {
492
            $pageLinkArray[1] = $secondPageLink;
493
        }
494
        return $pageLinkArray;
495
    }
496
497
    /**
498
     * Get work's download link
499
     *
500
     * @access private
501
     *
502
     * @return string Link to downloadable work
503
     */
504
    private function getWorkLink(): string
505
    {
506
        $workLink = '';
507
        $fileGrpsDownload = GeneralUtility::trimExplode(',', $this->extConf['files']['fileGrpDownload']);
508
        // Get work link.
509
        while ($fileGrpDownload = array_shift($fileGrpsDownload)) {
510
            $fileGroupDownload = $this->currentDocument->physicalStructureInfo[$this->currentDocument->physicalStructure[0]]['files'][$fileGrpDownload];
511
            if (!empty($fileGroupDownload)) {
512
                $workLink = $this->currentDocument->getFileLocation($fileGroupDownload);
513
                break;
514
            } else {
515
                $details = $this->currentDocument->getLogicalStructure($this->currentDocument->toplevelId);
516
                if (!empty($details['files'][$fileGrpDownload])) {
517
                    $workLink = $this->currentDocument->getFileLocation($details['files'][$fileGrpDownload]);
518
                    break;
519
                }
520
            }
521
        }
522
        if (empty($workLink)) {
523
            $this->logger->warning('File not found in fileGrps "' . $this->extConf['files']['fileGrpDownload'] . '"');
524
        }
525
        return $workLink;
526
    }
527
528
    /**
529
     * Renders the searchInDocument tool (used in template)
530
     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
531
     *
532
     * @access private
533
     *
534
     * @return void
535
     */
536
    private function renderSearchInDocumentTool(): void
537
    {
538
        if (
539
            $this->isDocMissingOrEmpty()
540
            || empty($this->extConf['files']['fileGrpFulltext'])
541
            || empty($this->settings['solrcore'])
542
        ) {
543
            // Quit without doing anything if required variables are not set.
544
            return;
545
        }
546
547
        $this->setPage();
548
549
        // Quit if no fulltext file is present
550
        if ($this->isFullTextEmpty()) {
551
            return;
552
        }
553
554
        $viewArray = [
555
            'labelQueryUrl' => $this->settings['queryInputName'],
556
            'labelStart' => $this->settings['startInputName'],
557
            'labelId' => $this->settings['idInputName'],
558
            'labelPid' => $this->settings['pidInputName'],
559
            'labelPageUrl' => $this->settings['pageInputName'],
560
            'labelHighlightWord' => $this->settings['highlightWordInputName'],
561
            'labelEncrypted' => $this->settings['encryptedInputName'],
562
            'documentId' => $this->getCurrentDocumentId(),
563
            'documentPageId' => $this->document->getPid(),
564
            'solrEncrypted' => $this->getEncryptedCoreName() ? : ''
565
        ];
566
567
        $this->view->assign('searchInDocument', $viewArray);
568
    }
569
570
    /**
571
     * Get current document id. As default the uid will be used.
572
     * In case there is defined documentIdUrlSchema then the id will
573
     * extracted from this URL.
574
     *
575
     * @access private
576
     *
577
     * @return string with current document id
578
     */
579
    private function getCurrentDocumentId(): string
580
    {
581
        $id = $this->document->getUid();
0 ignored issues
show
Bug introduced by
The method getUid() does not exist on null. ( Ignorable by Annotation )

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

581
        /** @scrutinizer ignore-call */ 
582
        $id = $this->document->getUid();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
582
583
        if ($id !== null && $id > 0) {
584
            // we found the document uid
585
            return (string) $id;
586
        } else {
587
            $id = $this->requestData['id'];
588
            if (!GeneralUtility::isValidUrl($id)) {
589
                // we found no valid URI --> something unexpected we cannot search within.
590
                return '';
591
            }
592
        }
593
594
        // example: https://host.de/items/*id*/record
595
        if (!empty($this->settings['documentIdUrlSchema'])) {
596
            $arr = explode('*', $this->settings['documentIdUrlSchema']);
597
598
            if (count($arr) == 2) {
599
                $id = explode($arr[0], $id)[0];
600
            } else if (count($arr) == 3) {
601
                $sub = substr($id, strpos($id, $arr[0]) + strlen($arr[0]), strlen($id));
602
                $id = substr($sub, 0, strpos($sub, $arr[2]));
603
            }
604
        }
605
        return $id;
606
    }
607
608
    /**
609
     * Get the encrypted Solr core name
610
     *
611
     * @access private
612
     *
613
     * @return string with encrypted core name
614
     */
615
    private function getEncryptedCoreName(): string
616
    {
617
        // Get core name.
618
        $name = Helper::getIndexNameFromUid($this->settings['solrcore'], 'tx_dlf_solrcores');
619
        // Encrypt core name.
620
        if (!empty($name)) {
621
            $name = Helper::encrypt($name);
622
        }
623
        return $name;
624
    }
625
626
    /**
627
     * Check if the full text is empty.
628
     *
629
     * @access private
630
     *
631
     * @return bool true if empty, false otherwise
632
     */
633
    private function isFullTextEmpty(): bool
634
    {
635
        $fileGrpsFulltext = GeneralUtility::trimExplode(',', $this->extConf['files']['fileGrpFulltext']);
636
        while ($fileGrpFulltext = array_shift($fileGrpsFulltext)) {
637
            $files = $this->currentDocument->physicalStructureInfo[$this->currentDocument->physicalStructure[$this->requestData['page']]]['files'];
638
            if (!empty($files[$fileGrpFulltext])) {
639
                return false;
640
            }
641
        }
642
        return true;
643
    }
644
}
645