Passed
Pull Request — master (#123)
by
unknown
04:16
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 Psr\Http\Message\ResponseInterface;
17
use TYPO3\CMS\Core\Utility\GeneralUtility;
18
use TYPO3\CMS\Core\Utility\MathUtility;
19
20
/**
21
 * Controller class for plugin 'Toolbox'.
22
 *
23
 * @package TYPO3
24
 * @subpackage dlf
25
 *
26
 * @access public
27
 */
28
class ToolboxController extends AbstractController
29
{
30
31
    /**
32
     * @access private
33
     * @var AbstractDocument This holds the current document
34
     */
35
    private AbstractDocument $currentDocument;
36
37
    /**
38
     * The main method of the plugin
39
     *
40
     * @access public
41
     *
42
     * @return ResponseInterface the response
43
     */
44
    public function mainAction(): ResponseInterface
45
    {
46
        // Load current document.
47
        $this->loadDocument();
48
49
        $this->view->assign('double', $this->requestData['double']);
50
51
        if (!$this->isDocMissingOrEmpty()) {
52
            $this->currentDocument = $this->document->getCurrentDocument();
53
        }
54
55
        $this->renderTools();
56
        $this->view->assign('viewData', $this->viewData);
57
58
        return $this->htmlResponse();
59
    }
60
61
    /**
62
     * Renders tool in the toolbox.
63
     *
64
     * @access private
65
     *
66
     * @return void
67
     */
68
    private function renderTools(): void
69
    {
70
        if (!empty($this->settings['tools'])) {
71
72
            $tools = explode(',', $this->settings['tools']);
73
74
            foreach ($tools as $tool) {
75
                switch ($tool) {
76
                    case 'tx_dlf_annotationtool':
77
                    case 'annotationtool':
78
                        $this->renderToolByName('renderAnnotationTool');
79
                        break;
80
                    case 'tx_dlf_fulltextdownloadtool':
81
                    case 'fulltextdownloadtool':
82
                        $this->renderToolByName('renderFulltextDownloadTool');
83
                        break;
84
                    case 'tx_dlf_fulltexttool':
85
                    case 'fulltexttool':
86
                        $this->renderToolByName('renderFulltextTool');
87
                        break;
88
                    case 'tx_dlf_imagedownloadtool':
89
                    case 'imagedownloadtool':
90
                        $this->renderToolByName('renderImageDownloadTool');
91
                        break;
92
                    case 'tx_dlf_imagemanipulationtool':
93
                    case 'imagemanipulationtool':
94
                        $this->renderToolByName('renderImageManipulationTool');
95
                        break;
96
                    case 'tx_dlf_modeldownloadtool':
97
                    case 'modeldownloadtool':
98
                        $this->renderToolByName('renderModelDownloadTool');
99
                        break;
100
                    case 'tx_dlf_pdfdownloadtool':
101
                    case 'pdfdownloadtool':
102
                        $this->renderToolByName('renderPdfDownloadTool');
103
                        break;
104
                    case 'tx_dlf_searchindocumenttool':
105
                    case 'searchindocumenttool':
106
                        $this->renderToolByName('renderSearchInDocumentTool');
107
                        break;
108
                    case 'scoretool':
109
                        $this->renderToolByName('renderScoreTool');
110
                        break;
111
                    default:
112
                        $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

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

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