Completed
Push — master ( 8a51dc...1c7826 )
by
unknown
18:25
created

getPropertiesForTable()   D

Complexity

Conditions 20
Paths 49

Size

Total Lines 101
Code Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 20
eloc 56
nc 49
nop 0
dl 0
loc 101
rs 4.1666
c 0
b 0
f 0

How to fix   Long Method    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
declare(strict_types = 1);
3
namespace TYPO3\CMS\Backend\Controller\ContentElement;
4
5
/*
6
 * This file is part of the TYPO3 CMS project.
7
 *
8
 * It is free software; you can redistribute it and/or modify it under
9
 * the terms of the GNU General Public License, either version 2
10
 * of the License, or any later version.
11
 *
12
 * For the full copyright and license information, please read the
13
 * LICENSE.txt file that was distributed with this source code.
14
 *
15
 * The TYPO3 project - inspiring people to share!
16
 */
17
18
use Doctrine\DBAL\Connection;
19
use Exception;
20
use Psr\Http\Message\ResponseInterface;
21
use Psr\Http\Message\ServerRequestInterface;
22
use TYPO3\CMS\Backend\Backend\Avatar\Avatar;
23
use TYPO3\CMS\Backend\Form\FormDataCompiler;
24
use TYPO3\CMS\Backend\Form\FormDataGroup\TcaDatabaseRecord;
25
use TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException;
26
use TYPO3\CMS\Backend\Routing\UriBuilder;
27
use TYPO3\CMS\Backend\Template\ModuleTemplate;
28
use TYPO3\CMS\Backend\Utility\BackendUtility;
29
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
30
use TYPO3\CMS\Core\Database\ConnectionPool;
31
use TYPO3\CMS\Core\Http\HtmlResponse;
32
use TYPO3\CMS\Core\Imaging\Icon;
33
use TYPO3\CMS\Core\Imaging\IconFactory;
34
use TYPO3\CMS\Core\Localization\LanguageService;
35
use TYPO3\CMS\Core\Resource\AbstractFile;
36
use TYPO3\CMS\Core\Resource\File;
37
use TYPO3\CMS\Core\Resource\Folder;
38
use TYPO3\CMS\Core\Resource\Index\MetaDataRepository;
39
use TYPO3\CMS\Core\Resource\Rendering\RendererRegistry;
40
use TYPO3\CMS\Core\Resource\ResourceFactory;
41
use TYPO3\CMS\Core\Type\Bitmask\Permission;
42
use TYPO3\CMS\Core\Utility\GeneralUtility;
43
use TYPO3\CMS\Fluid\View\StandaloneView;
44
45
/**
46
 * Script Class for showing information about an item.
47
 * @internal This class is a specific Backend controller implementation and is not considered part of the Public TYPO3 API.
48
 */
49
class ElementInformationController
50
{
51
    /**
52
     * Record table name
53
     *
54
     * @var string
55
     */
56
    protected $table;
57
58
    /**
59
     * Record uid
60
     *
61
     * @var int
62
     */
63
    protected $uid;
64
65
    /**
66
     * @var string
67
     */
68
    protected $permsClause;
69
70
    /**
71
     * @var bool
72
     */
73
    protected $access = false;
74
75
    /**
76
     * Which type of element:
77
     * - "file"
78
     * - "db"
79
     *
80
     * @var string
81
     */
82
    protected $type = '';
83
84
    /**
85
     * @var ModuleTemplate
86
     */
87
    protected $moduleTemplate;
88
89
    /**
90
     * For type "db": Set to page record of the parent page of the item set
91
     * (if type="db")
92
     *
93
     * @var array
94
     */
95
    protected $pageInfo;
96
97
    /**
98
     * Database records identified by table/uid
99
     *
100
     * @var array
101
     */
102
    protected $row;
103
104
    /**
105
     * @var \TYPO3\CMS\Core\Resource\File
106
     */
107
    protected $fileObject;
108
109
    /**
110
     * @var Folder
111
     */
112
    protected $folderObject;
113
114
    /**
115
     * @var IconFactory
116
     */
117
    protected $iconFactory;
118
119
    /**
120
     * Constructor
121
     */
122
    public function __construct()
123
    {
124
        $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
125
        $GLOBALS['SOBE'] = $this;
126
    }
127
128
    /**
129
     * Injects the request object for the current request or subrequest
130
     * As this controller goes only through the main() method, it is rather simple for now
131
     *
132
     * @param ServerRequestInterface $request the current request
133
     * @return ResponseInterface the response with the content
134
     */
135
    public function mainAction(ServerRequestInterface $request): ResponseInterface
136
    {
137
        $this->init($request);
138
        $this->main($request);
139
        return new HtmlResponse($this->moduleTemplate->renderContent());
140
    }
141
142
    /**
143
     * Determines if table/uid point to database record or file and
144
     * if user has access to view information
145
     *
146
     * @param ServerRequestInterface $request
147
     */
148
    protected function init(ServerRequestInterface $request): void
149
    {
150
        $queryParams = $request->getQueryParams();
151
152
        $this->table = $queryParams['table'] ?? null;
153
        $this->uid = $queryParams['uid'] ?? null;
154
155
        $this->permsClause = $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW);
156
        $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
157
        $this->moduleTemplate->getDocHeaderComponent()->disable();
158
159
        if (isset($GLOBALS['TCA'][$this->table])) {
160
            $this->initDatabaseRecord();
161
        } elseif ($this->table === '_FILE' || $this->table === '_FOLDER' || $this->table === 'sys_file') {
162
            $this->initFileOrFolderRecord();
163
        }
164
    }
165
166
    /**
167
     * Init database records (table)
168
     */
169
    protected function initDatabaseRecord(): void
170
    {
171
        $this->type = 'db';
172
        $this->uid = (int)$this->uid;
173
174
        // Check permissions and uid value:
175
        if ($this->uid && $this->getBackendUser()->check('tables_select', $this->table)) {
176
            if ((string)$this->table === 'pages') {
177
                $this->pageInfo = BackendUtility::readPageAccess($this->uid, $this->permsClause);
178
                $this->access = is_array($this->pageInfo);
179
                $this->row = $this->pageInfo;
180
            } else {
181
                $this->row = BackendUtility::getRecordWSOL($this->table, $this->uid);
182
                if ($this->row) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->row of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
183
                    // Find the correct "pid" when a versionized record is given, otherwise "pid = -1" always fails
184
                    if (!empty($this->row['t3ver_oid'])) {
185
                        $t3OrigRow = BackendUtility::getRecord($this->table, (int)$this->row['t3ver_oid']);
186
                        $this->pageInfo = BackendUtility::readPageAccess((int)$t3OrigRow['pid'], $this->permsClause);
187
                    } else {
188
                        $this->pageInfo = BackendUtility::readPageAccess($this->row['pid'], $this->permsClause);
189
                    }
190
                    $this->access = is_array($this->pageInfo);
191
                }
192
            }
193
        }
194
    }
195
196
    /**
197
     * Init file/folder parameters
198
     */
199
    protected function initFileOrFolderRecord(): void
200
    {
201
        $fileOrFolderObject = GeneralUtility::makeInstance(ResourceFactory::class)->retrieveFileOrFolderObject($this->uid);
202
203
        if ($fileOrFolderObject instanceof Folder) {
204
            $this->folderObject = $fileOrFolderObject;
205
            $this->access = $this->folderObject->checkActionPermission('read');
206
            $this->type = 'folder';
207
        } elseif ($fileOrFolderObject instanceof File) {
208
            $this->fileObject = $fileOrFolderObject;
209
            $this->access = $this->fileObject->checkActionPermission('read');
210
            $this->type = 'file';
211
            $this->table = 'sys_file';
212
213
            try {
214
                $this->row = BackendUtility::getRecordWSOL($this->table, $fileOrFolderObject->getUid());
215
            } catch (Exception $e) {
216
                $this->row = [];
217
            }
218
        }
219
    }
220
221
    /**
222
     * Compiles the whole content to be outputted, which is then set as content to the moduleTemplate
223
     * There is a hook to do a custom rendering of a record.
224
     *
225
     * @param ServerRequestInterface $request
226
     */
227
    protected function main(ServerRequestInterface $request): void
228
    {
229
        $content = '';
230
231
        // Rendering of the output via fluid
232
        $view = GeneralUtility::makeInstance(StandaloneView::class);
233
        $view->setTemplateRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates')]);
234
        $view->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Partials')]);
235
        $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName(
236
            'EXT:backend/Resources/Private/Templates/ContentElement/ElementInformation.html'
237
        ));
238
239
        if ($this->access) {
240
            // render type by user func
241
            $typeRendered = false;
242
            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/show_item.php']['typeRendering'] ?? [] as $className) {
243
                $typeRenderObj = GeneralUtility::makeInstance($className);
244
                if (is_object($typeRenderObj) && method_exists($typeRenderObj, 'isValid') && method_exists($typeRenderObj, 'render')) {
245
                    if ($typeRenderObj->isValid($this->type, $this)) {
246
                        $content .= $typeRenderObj->render($this->type, $this);
247
                        $typeRendered = true;
248
                        break;
249
                    }
250
                }
251
            }
252
253
            if (!$typeRendered) {
254
                $view->assign('accessAllowed', true);
255
                $view->assignMultiple($this->getPageTitle());
256
                $view->assignMultiple($this->getPreview());
257
                $view->assignMultiple($this->getPropertiesForTable());
258
                $view->assignMultiple($this->getReferences($request));
259
                $view->assign('returnUrl', GeneralUtility::sanitizeLocalUrl($request->getQueryParams()['returnUrl']));
260
                $view->assign('maxTitleLength', $this->getBackendUser()->uc['titleLen'] ?? 20);
261
                $content .= $view->render();
262
            }
263
        } else {
264
            $content .= $view->render();
265
        }
266
267
        $this->moduleTemplate->setContent($content);
268
    }
269
270
    /**
271
     * Get page title with icon, table title and record title
272
     *
273
     * @return array
274
     */
275
    protected function getPageTitle(): array
276
    {
277
        $pageTitle = [
278
            'title' => BackendUtility::getRecordTitle($this->table, $this->row)
279
        ];
280
        if ($this->type === 'folder') {
281
            $pageTitle['table'] = $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:folder');
282
            $pageTitle['icon'] = $this->iconFactory->getIconForResource($this->folderObject, Icon::SIZE_SMALL)->render();
283
        } elseif ($this->type === 'file') {
284
            $pageTitle['table'] = $this->getLanguageService()->sL($GLOBALS['TCA'][$this->table]['ctrl']['title']);
285
            $pageTitle['icon'] = $this->iconFactory->getIconForResource($this->fileObject, Icon::SIZE_SMALL)->render();
286
        } else {
287
            $pageTitle['table'] = $this->getLanguageService()->sL($GLOBALS['TCA'][$this->table]['ctrl']['title']);
288
            $pageTitle['icon'] = $this->iconFactory->getIconForRecord($this->table, $this->row, Icon::SIZE_SMALL);
289
        }
290
        $this->moduleTemplate->setTitle($pageTitle['table'] . ': ' . $pageTitle['title']);
291
        return $pageTitle;
292
    }
293
294
    /**
295
     * Get preview for current record
296
     *
297
     * @return array
298
     */
299
    protected function getPreview(): array
300
    {
301
        $preview = [];
302
        // Perhaps @todo in future: Also display preview for records - without fileObject
303
        if (!$this->fileObject) {
304
            return $preview;
305
        }
306
307
        // check if file is marked as missing
308
        if ($this->fileObject->isMissing()) {
309
            $preview['missingFile'] = $this->fileObject->getName();
310
        } else {
311
            $rendererRegistry = GeneralUtility::makeInstance(RendererRegistry::class);
312
            $fileRenderer = $rendererRegistry->getRenderer($this->fileObject);
313
            $fileExtension = $this->fileObject->getExtension();
314
            $preview['url'] = $this->fileObject->getPublicUrl(true);
315
316
            $width = '590m';
317
            $heigth = '400m';
318
319
            // Check if there is a FileRenderer
320
            if ($fileRenderer !== null) {
321
                $preview['fileRenderer'] = $fileRenderer->render(
322
                    $this->fileObject,
323
                    $width,
324
                    $heigth,
325
                    [],
326
                    true
327
                );
328
329
            // else check if we can create an Image preview
330
            } elseif (GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileExtension)) {
331
                $preview['fileObject'] = $this->fileObject;
332
                $preview['width'] = $width;
333
                $preview['heigth'] = $heigth;
334
            }
335
        }
336
        return $preview;
337
    }
338
339
    /**
340
     * Get property array for html table
341
     *
342
     * @return array
343
     */
344
    protected function getPropertiesForTable(): array
345
    {
346
        $lang = $this->getLanguageService();
347
        $propertiesForTable = [];
348
        $propertiesForTable['extraFields'] = $this->getExtraFields();
349
350
        // Traverse the list of fields to display for the record:
351
        $fieldList = $this->getFieldList($this->table, (int)$this->row['uid']);
352
353
        foreach ($fieldList as $name) {
354
            $name = trim($name);
355
            $uid = $this->row['uid'];
356
357
            if (!isset($GLOBALS['TCA'][$this->table]['columns'][$name])) {
358
                continue;
359
            }
360
361
            // not a real field -> skip
362
            if ($this->type === 'file' && $name === 'fileinfo') {
363
                continue;
364
            }
365
366
            $isExcluded = !(!$GLOBALS['TCA'][$this->table]['columns'][$name]['exclude'] || $this->getBackendUser()->check('non_exclude_fields', $this->table . ':' . $name));
367
            if ($isExcluded) {
368
                continue;
369
            }
370
            $label = $lang->sL(BackendUtility::getItemLabel($this->table, $name));
371
            $label = $label ?: $name;
372
373
            $propertiesForTable['fields'][] = [
374
                'fieldValue' => BackendUtility::getProcessedValue($this->table, $name, $this->row[$name], 0, 0, false, $uid),
375
                'fieldLabel' => htmlspecialchars($label)
376
            ];
377
        }
378
379
        // additional information for folders and files
380
        if ($this->folderObject instanceof Folder || $this->fileObject instanceof File) {
0 ignored issues
show
introduced by
$this->folderObject is always a sub-type of TYPO3\CMS\Core\Resource\Folder.
Loading history...
381
            // storage
382
            if ($this->folderObject instanceof Folder) {
383
                $propertiesForTable['fields']['storage'] = [
384
                    'fieldValue' => $this->folderObject->getStorage()->getName(),
385
                    'fieldLabel' => htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_file.storage'))
386
                ];
387
            }
388
389
            // folder
390
            $resourceObject = $this->fileObject ?: $this->folderObject;
391
            $propertiesForTable['fields']['folder'] = [
392
                'fieldValue' => $resourceObject->getParentFolder()->getReadablePath(),
393
                'fieldLabel' => htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:folder'))
394
            ];
395
396
            if ($this->fileObject instanceof File) {
0 ignored issues
show
introduced by
$this->fileObject is always a sub-type of TYPO3\CMS\Core\Resource\File.
Loading history...
397
                // show file dimensions for images
398
                if ($this->fileObject->getType() === AbstractFile::FILETYPE_IMAGE) {
399
                    $propertiesForTable['fields']['width'] = [
400
                        'fieldValue' => $this->fileObject->getProperty('width') . 'px',
401
                        'fieldLabel' => htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.width'))
402
                    ];
403
                    $propertiesForTable['fields']['height'] = [
404
                        'fieldValue' => $this->fileObject->getProperty('height') . 'px',
405
                        'fieldLabel' => htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.height'))
406
                    ];
407
                }
408
409
                // file size
410
                $propertiesForTable['fields']['size'] = [
411
                    'fieldValue' => GeneralUtility::formatSize((int)$this->fileObject->getProperty('size'), htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:byteSizeUnits'))),
412
                    'fieldLabel' => $lang->sL(BackendUtility::getItemLabel($this->table, 'size'))
413
                ];
414
415
                // show the metadata of a file as well
416
                $table = 'sys_file_metadata';
417
                $metaDataRepository = GeneralUtility::makeInstance(MetaDataRepository::class);
418
                $metaData = $metaDataRepository->findByFileUid($this->row['uid']);
419
                $allowedFields = $this->getFieldList($table, (int)$metaData['uid']);
420
421
                foreach ($metaData as $name => $value) {
422
                    if (in_array($name, $allowedFields, true)) {
423
                        if (!isset($GLOBALS['TCA'][$table]['columns'][$name])) {
424
                            continue;
425
                        }
426
427
                        $isExcluded = !(!$GLOBALS['TCA'][$table]['columns'][$name]['exclude'] || $this->getBackendUser()->check('non_exclude_fields', $table . ':' . $name));
428
                        if ($isExcluded) {
429
                            continue;
430
                        }
431
432
                        $label = $lang->sL(BackendUtility::getItemLabel($table, $name));
433
                        $label = $label ?: $name;
434
435
                        $propertiesForTable['fields'][] = [
436
                            'fieldValue' => BackendUtility::getProcessedValue($table, $name, $metaData[$name], 0, 0, false, $metaData['uid']),
437
                            'fieldLabel' => htmlspecialchars($label)
438
                        ];
439
                    }
440
                }
441
            }
442
        }
443
444
        return $propertiesForTable;
445
    }
446
447
    /**
448
     * Get the list of fields that should be shown for the given table
449
     *
450
     * @param string $table
451
     * @param int $uid
452
     * @return array
453
     */
454
    protected function getFieldList(string $table, int $uid): array
455
    {
456
        $formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
457
        $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
0 ignored issues
show
Bug introduced by
$formDataGroup of type object is incompatible with the type array|array<mixed,mixed> expected by parameter $constructorArguments of TYPO3\CMS\Core\Utility\G...Utility::makeInstance(). ( Ignorable by Annotation )

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

457
        $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, /** @scrutinizer ignore-type */ $formDataGroup);
Loading history...
458
        $formDataCompilerInput = [
459
            'command' => 'edit',
460
            'tableName' => $table,
461
            'vanillaUid' => $uid,
462
        ];
463
        try {
464
            $result = $formDataCompiler->compile($formDataCompilerInput);
465
            $fieldList = array_unique(array_values($result['columnsToProcess']));
466
467
            $ctrlKeysOfUnneededFields = ['origUid', 'transOrigPointerField', 'transOrigDiffSourceField'];
468
            foreach ($ctrlKeysOfUnneededFields as $field) {
469
                if (($key = array_search($GLOBALS['TCA'][$table]['ctrl'][$field], $fieldList, true)) !== false) {
470
                    unset($fieldList[$key]);
471
                }
472
            }
473
        } catch (Exception $exception) {
474
            $fieldList = [];
475
        }
476
477
        $searchFields = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['searchFields']);
478
479
        return array_unique(array_merge($fieldList, $searchFields));
480
    }
481
482
    /**
483
     * Get the extra fields (uid, timestamps, creator) for the table
484
     *
485
     * @return array
486
     */
487
    protected function getExtraFields(): array
488
    {
489
        $lang = $this->getLanguageService();
490
        $keyLabelPair = [];
491
        $extraFields = [
492
            'uid' => htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:show_item.php.uid'))
493
        ];
494
495
        if (in_array($this->type, ['folder', 'file'], true)) {
496
            if ($this->type === 'file') {
497
                $extraFields['creation_date'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.creationDate'));
498
                $extraFields['modification_date'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.timestamp'));
499
            }
500
        } else {
501
            foreach (['crdate' => 'creationDate', 'tstamp' => 'timestamp', 'cruser_id' => 'creationUserId'] as $field => $label) {
502
                if (isset($GLOBALS['TCA'][$this->table]['ctrl'][$field])) {
503
                    $extraFields[$GLOBALS['TCA'][$this->table]['ctrl'][$field]] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.' . $label));
504
                }
505
            }
506
        }
507
508
        foreach ($extraFields as $name => $fieldLabel) {
509
            if (in_array($name, ['creation_date', 'modification_date', 'tstamp', 'crdate'], true)) {
510
                $rowValue = BackendUtility::datetime($this->row[$name]);
511
                $keyLabelPair[$name] = [
512
                    'value' => $rowValue,
513
                    'fieldLabel' => rtrim($fieldLabel, ':'),
514
                    'isDatetime' => true,
515
                ];
516
            } else {
517
                $rowValue = BackendUtility::getProcessedValueExtra($this->table, $name, $this->row[$name]);
518
519
                // show the backend username who created the issue
520
                if ($name === 'cruser_id' && $rowValue) {
521
                    $creatorRecord = BackendUtility::getRecord('be_users', $rowValue);
0 ignored issues
show
Bug introduced by
$rowValue of type string is incompatible with the type integer expected by parameter $uid of TYPO3\CMS\Backend\Utilit...endUtility::getRecord(). ( Ignorable by Annotation )

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

521
                    $creatorRecord = BackendUtility::getRecord('be_users', /** @scrutinizer ignore-type */ $rowValue);
Loading history...
522
                    if ($creatorRecord) {
523
                        /** @var Avatar $avatar */
524
                        $avatar = GeneralUtility::makeInstance(Avatar::class);
525
                        $creatorRecord['icon'] = $avatar->render($creatorRecord);
526
                        $name = 'creatorRecord';
527
                        $rowValue = $creatorRecord;
528
                    }
529
                }
530
                $keyLabelPair[$name] = [
531
                    'value' => $rowValue,
532
                    'fieldLabel' => rtrim($fieldLabel, ':'),
533
                ];
534
            }
535
        }
536
537
        return $keyLabelPair;
538
    }
539
540
    /**
541
     * Get references section (references from and references to current record)
542
     *
543
     * @param ServerRequestInterface $request
544
     * @return array
545
     */
546
    protected function getReferences(ServerRequestInterface $request): array
547
    {
548
        $references = [];
549
        switch ($this->type) {
550
            case 'db': {
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
551
                $references['refLines'] = $this->makeRef($this->table, $this->row['uid'], $request);
552
                $references['refFromLines'] = $this->makeRefFrom($this->table, $this->row['uid'], $request);
553
                break;
554
            }
555
556
            case 'file': {
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
557
                if ($this->fileObject && $this->fileObject->isIndexed()) {
558
                    $references['refLines'] = $this->makeRef('_FILE', $this->fileObject, $request);
559
                }
560
                break;
561
            }
562
        }
563
        return $references;
564
    }
565
566
    /**
567
     * Get field name for specified table/column name
568
     *
569
     * @param string $tableName Table name
570
     * @param string $fieldName Column name
571
     * @return string label
572
     */
573
    protected function getLabelForTableColumn($tableName, $fieldName): string
574
    {
575
        if ($GLOBALS['TCA'][$tableName]['columns'][$fieldName]['label'] !== null) {
576
            $field = $this->getLanguageService()->sL($GLOBALS['TCA'][$tableName]['columns'][$fieldName]['label']);
577
            if (trim($field) === '') {
578
                $field = $fieldName;
579
            }
580
        } else {
581
            $field = $fieldName;
582
        }
583
        return $field;
584
    }
585
586
    /**
587
     * Returns the record actions
588
     *
589
     * @param string $table
590
     * @param int $uid
591
     * @param ServerRequestInterface $request
592
     * @return array
593
     * @throws RouteNotFoundException
594
     */
595
    protected function getRecordActions($table, $uid, ServerRequestInterface $request): array
596
    {
597
        if ($table === '' || $uid < 0) {
598
            return [];
599
        }
600
601
        $actions = [];
602
        // Edit button
603
        $urlParameters = [
604
            'edit' => [
605
                $table => [
606
                    $uid => 'edit'
607
                ]
608
            ],
609
            'returnUrl' => $request->getAttribute('normalizedParams')->getRequestUri()
610
        ];
611
        $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
612
        $actions['recordEditUrl'] = (string)$uriBuilder->buildUriFromRoute('record_edit', $urlParameters);
613
614
        // History button
615
        $urlParameters = [
616
            'element' => $table . ':' . $uid,
617
            'returnUrl' => $request->getAttribute('normalizedParams')->getRequestUri()
618
        ];
619
        $actions['recordHistoryUrl'] = (string)$uriBuilder->buildUriFromRoute('record_history', $urlParameters);
620
621
        if ($table === 'pages') {
622
            // Recordlist button
623
            $actions['webListUrl'] = (string)$uriBuilder->buildUriFromRoute('web_list', ['id' => $uid, 'returnUrl' => $request->getAttribute('normalizedParams')->getRequestUri()]);
624
625
            // View page button
626
            $actions['viewOnClick'] = BackendUtility::viewOnClick($uid, '', BackendUtility::BEgetRootLine($uid));
627
        }
628
629
        return $actions;
630
    }
631
632
    /**
633
     * Make reference display
634
     *
635
     * @param string $table Table name
636
     * @param string|\TYPO3\CMS\Core\Resource\File $ref Filename or uid
637
     * @param ServerRequestInterface $request
638
     * @return array
639
     * @throws RouteNotFoundException
640
     */
641
    protected function makeRef($table, $ref, ServerRequestInterface $request): array
642
    {
643
        $refLines = [];
644
        $lang = $this->getLanguageService();
645
        // Files reside in sys_file table
646
        if ($table === '_FILE') {
647
            $selectTable = 'sys_file';
648
            $selectUid = $ref->getUid();
649
        } else {
650
            $selectTable = $table;
651
            $selectUid = $ref;
652
        }
653
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
654
            ->getQueryBuilderForTable('sys_refindex');
655
656
        $predicates = [
657
            $queryBuilder->expr()->eq(
658
                'ref_table',
659
                $queryBuilder->createNamedParameter($selectTable, \PDO::PARAM_STR)
660
            ),
661
            $queryBuilder->expr()->eq(
662
                'ref_uid',
663
                $queryBuilder->createNamedParameter($selectUid, \PDO::PARAM_INT)
664
            ),
665
            $queryBuilder->expr()->eq(
666
                'deleted',
667
                $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
668
            )
669
        ];
670
671
        $backendUser = $this->getBackendUser();
672
        if (!$backendUser->isAdmin()) {
673
            $allowedSelectTables = GeneralUtility::trimExplode(',', $backendUser->groupData['tables_select']);
674
            $predicates[] = $queryBuilder->expr()->in(
675
                'tablename',
676
                $queryBuilder->createNamedParameter($allowedSelectTables, Connection::PARAM_STR_ARRAY)
677
            );
678
        }
679
680
        $rows = $queryBuilder
681
            ->select('*')
682
            ->from('sys_refindex')
683
            ->where(...$predicates)
684
            ->execute()
685
            ->fetchAll();
686
687
        // Compile information for title tag:
688
        foreach ($rows as $row) {
689
            if ($row['tablename'] === 'sys_file_reference') {
690
                $row = $this->transformFileReferenceToRecordReference($row);
691
                if ($row['tablename'] === null || $row['recuid'] === null) {
692
                    return [];
693
                }
694
            }
695
696
            $line = [];
697
            $record = BackendUtility::getRecord($row['tablename'], $row['recuid']);
698
            if ($record) {
699
                BackendUtility::fixVersioningPid($row['tablename'], $record);
700
                if (!$this->canAccessPage($row['tablename'], $record)) {
701
                    continue;
702
                }
703
                $parentRecord = BackendUtility::getRecord('pages', $record['pid']);
704
                $parentRecordTitle = is_array($parentRecord)
705
                    ? BackendUtility::getRecordTitle('pages', $parentRecord)
0 ignored issues
show
Coding Style introduced by
Expected 1 space before "?"; newline found
Loading history...
706
                    : '';
0 ignored issues
show
Coding Style introduced by
Expected 1 space before ":"; newline found
Loading history...
707
                $urlParameters = [
708
                    'edit' => [
709
                        $row['tablename'] => [
710
                            $row['recuid'] => 'edit'
711
                        ]
712
                    ],
713
                    'returnUrl' => $request->getAttribute('normalizedParams')->getRequestUri()
714
                ];
715
                $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
716
                $url = (string)$uriBuilder->buildUriFromRoute('record_edit', $urlParameters);
717
                $line['url'] = $url;
718
                $line['icon'] = $this->iconFactory->getIconForRecord($row['tablename'], $record, Icon::SIZE_SMALL)->render();
719
                $line['row'] = $row;
720
                $line['record'] = $record;
721
                $line['recordTitle'] = BackendUtility::getRecordTitle($row['tablename'], $record, false, true);
722
                $line['parentRecordTitle'] = $parentRecordTitle;
723
                $line['title'] = $lang->sL($GLOBALS['TCA'][$row['tablename']]['ctrl']['title']);
724
                $line['labelForTableColumn'] = $this->getLabelForTableColumn($row['tablename'], $row['field']);
725
                $line['path'] = BackendUtility::getRecordPath($record['pid'], '', 0, 0);
726
                $line['actions'] = $this->getRecordActions($row['tablename'], $row['recuid'], $request);
727
            } else {
728
                $line['row'] = $row;
729
                $line['title'] = $lang->sL($GLOBALS['TCA'][$row['tablename']]['ctrl']['title']) ?: $row['tablename'];
730
                $line['labelForTableColumn'] = $this->getLabelForTableColumn($row['tablename'], $row['field']);
731
            }
732
            $refLines[] = $line;
733
        }
734
        return $refLines;
735
    }
736
737
    /**
738
     * Make reference display (what this elements points to)
739
     *
740
     * @param string $table Table name
741
     * @param string $ref Filename or uid
742
     * @param ServerRequestInterface $request
743
     * @return array
744
     */
745
    protected function makeRefFrom($table, $ref, ServerRequestInterface $request): array
746
    {
747
        $refFromLines = [];
748
        $lang = $this->getLanguageService();
749
750
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
751
            ->getQueryBuilderForTable('sys_refindex');
752
753
        $predicates = [
754
            $queryBuilder->expr()->eq(
755
                'tablename',
756
                $queryBuilder->createNamedParameter($table, \PDO::PARAM_STR)
757
            ),
758
            $queryBuilder->expr()->eq(
759
                'recuid',
760
                $queryBuilder->createNamedParameter($ref, \PDO::PARAM_INT)
761
            )
762
        ];
763
764
        $backendUser = $this->getBackendUser();
765
        if (!$backendUser->isAdmin()) {
766
            $allowedSelectTables = GeneralUtility::trimExplode(',', $backendUser->groupData['tables_select']);
767
            $predicates[] = $queryBuilder->expr()->in(
768
                'ref_table',
769
                $queryBuilder->createNamedParameter($allowedSelectTables, Connection::PARAM_STR_ARRAY)
770
            );
771
        }
772
773
        $rows = $queryBuilder
774
            ->select('*')
775
            ->from('sys_refindex')
776
            ->where(...$predicates)
777
            ->execute()
778
            ->fetchAll();
779
780
        // Compile information for title tag:
781
        foreach ($rows as $row) {
782
            $line = [];
783
            $record = BackendUtility::getRecord($row['ref_table'], $row['ref_uid']);
784
            if ($record) {
785
                BackendUtility::fixVersioningPid($row['ref_table'], $record);
786
                if (!$this->canAccessPage($row['ref_table'], $record)) {
787
                    continue;
788
                }
789
                $urlParameters = [
790
                    'edit' => [
791
                        $row['ref_table'] => [
792
                            $row['ref_uid'] => 'edit'
793
                        ]
794
                    ],
795
                    'returnUrl' => $request->getAttribute('normalizedParams')->getRequestUri()
796
                ];
797
                $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
798
                $url = (string)$uriBuilder->buildUriFromRoute('record_edit', $urlParameters);
799
                $line['url'] = $url;
800
                $line['icon'] = $this->iconFactory->getIconForRecord($row['tablename'], $record, Icon::SIZE_SMALL)->render();
801
                $line['row'] = $row;
802
                $line['record'] = $record;
803
                $line['recordTitle'] = BackendUtility::getRecordTitle($row['ref_table'], $record, false, true);
804
                $line['title'] = $lang->sL($GLOBALS['TCA'][$row['ref_table']]['ctrl']['title']);
805
                $line['labelForTableColumn'] = $this->getLabelForTableColumn($table, $row['field']);
806
                $line['path'] = BackendUtility::getRecordPath($record['pid'], '', 0, 0);
807
                $line['actions'] = $this->getRecordActions($row['ref_table'], $row['ref_uid'], $request);
808
            } else {
809
                $line['row'] = $row;
810
                $line['title'] = $lang->sL($GLOBALS['TCA'][$row['ref_table']]['ctrl']['title']);
811
                $line['labelForTableColumn'] = $this->getLabelForTableColumn($table, $row['field']);
812
            }
813
            $refFromLines[] = $line;
814
        }
815
        return $refFromLines;
816
    }
817
818
    /**
819
     * Convert FAL file reference (sys_file_reference) to reference index (sys_refindex) table format
820
     *
821
     * @param array $referenceRecord
822
     * @return array
823
     */
824
    protected function transformFileReferenceToRecordReference(array $referenceRecord): array
825
    {
826
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
827
            ->getQueryBuilderForTable('sys_file_reference');
828
        $queryBuilder->getRestrictions()->removeAll();
829
        $fileReference = $queryBuilder
830
            ->select('*')
831
            ->from('sys_file_reference')
832
            ->where(
833
                $queryBuilder->expr()->eq(
834
                    'uid',
835
                    $queryBuilder->createNamedParameter($referenceRecord['recuid'], \PDO::PARAM_INT)
836
                )
837
            )
838
            ->execute()
839
            ->fetch();
840
841
        return [
842
            'recuid' => $fileReference['uid_foreign'],
843
            'tablename' => $fileReference['tablenames'],
844
            'field' => $fileReference['fieldname'],
845
            'flexpointer' => '',
846
            'softref_key' => '',
847
            'sorting' => $fileReference['sorting_foreign']
848
        ];
849
    }
850
851
    /**
852
     * @param string $tableName Name of the table
853
     * @param array $record Record to be checked (ensure pid is resolved for workspaces)
854
     * @return bool
855
     */
856
    protected function canAccessPage(string $tableName, array $record): bool
857
    {
858
        $recordPid = (int)($tableName === 'pages' ? $record['uid'] : $record['pid']);
859
        return $this->getBackendUser()->isInWebMount($tableName === 'pages' ? $record : $record['pid'])
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getBackendUser()-...ecord : $record['pid']) of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
860
            || $recordPid === 0 && !empty($GLOBALS['TCA'][$tableName]['ctrl']['security']['ignoreRootLevelRestriction']);
861
    }
862
863
    /**
864
     * @return LanguageService
865
     */
866
    protected function getLanguageService(): LanguageService
867
    {
868
        return $GLOBALS['LANG'];
869
    }
870
871
    /**
872
     * @return BackendUserAuthentication
873
     */
874
    protected function getBackendUser(): BackendUserAuthentication
875
    {
876
        return $GLOBALS['BE_USER'];
877
    }
878
}
879