45890b2d11500de9d135b0bab7e11d1e8b92e9a9
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Controller / ContentElement / ElementInformationController.php
1 <?php
2 namespace TYPO3\CMS\Backend\Controller\ContentElement;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\Backend\Avatar\Avatar;
20 use TYPO3\CMS\Backend\Template\ModuleTemplate;
21 use TYPO3\CMS\Backend\Utility\BackendUtility;
22 use TYPO3\CMS\Core\Database\ConnectionPool;
23 use TYPO3\CMS\Core\Imaging\Icon;
24 use TYPO3\CMS\Core\Imaging\IconFactory;
25 use TYPO3\CMS\Core\Resource\Folder;
26 use TYPO3\CMS\Core\Resource\ProcessedFile;
27 use TYPO3\CMS\Core\Resource\ResourceFactory;
28 use TYPO3\CMS\Core\Utility\GeneralUtility;
29
30 /**
31 * Script Class for showing information about an item.
32 */
33 class ElementInformationController
34 {
35 /**
36 * Record table name
37 *
38 * @var string
39 */
40 public $table;
41
42 /**
43 * Record uid
44 *
45 * @var int
46 */
47 public $uid;
48
49 /**
50 * @var string
51 */
52 protected $permsClause;
53
54 /**
55 * @var bool
56 */
57 public $access = false;
58
59 /**
60 * Which type of element:
61 * - "file"
62 * - "db"
63 *
64 * @var string
65 */
66 public $type = '';
67
68 /**
69 * @var ModuleTemplate
70 */
71 protected $moduleTemplate;
72
73 /**
74 * For type "db": Set to page record of the parent page of the item set
75 * (if type="db")
76 *
77 * @var array
78 */
79 public $pageInfo;
80
81 /**
82 * Database records identified by table/uid
83 *
84 * @var array
85 */
86 protected $row;
87
88 /**
89 * @var \TYPO3\CMS\Core\Resource\File
90 */
91 protected $fileObject;
92
93 /**
94 * @var Folder
95 */
96 protected $folderObject;
97
98 /**
99 * @var IconFactory
100 */
101 protected $iconFactory;
102
103 /**
104 * Constructor
105 */
106 public function __construct()
107 {
108 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
109 $GLOBALS['SOBE'] = $this;
110
111 $this->init();
112 }
113
114 /**
115 * Determines if table/uid point to database record or file and
116 * if user has access to view information
117 *
118 * @return void
119 */
120 public function init()
121 {
122 $this->table = GeneralUtility::_GET('table');
123 $this->uid = GeneralUtility::_GET('uid');
124
125 $this->permsClause = $this->getBackendUser()->getPagePermsClause(1);
126 $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
127 $this->moduleTemplate->getDocHeaderComponent()->disable();
128
129 if (isset($GLOBALS['TCA'][$this->table])) {
130 $this->initDatabaseRecord();
131 } elseif ($this->table === '_FILE' || $this->table === '_FOLDER' || $this->table === 'sys_file') {
132 $this->initFileOrFolderRecord();
133 }
134 }
135
136 /**
137 * Init database records (table)
138 */
139 protected function initDatabaseRecord()
140 {
141 $this->type = 'db';
142 $this->uid = (int)$this->uid;
143
144 // Check permissions and uid value:
145 if ($this->uid && $this->getBackendUser()->check('tables_select', $this->table)) {
146 if ((string)$this->table == 'pages') {
147 $this->pageInfo = BackendUtility::readPageAccess($this->uid, $this->permsClause);
148 $this->access = is_array($this->pageInfo) ? 1 : 0;
149 $this->row = $this->pageInfo;
150 } else {
151 $this->row = BackendUtility::getRecordWSOL($this->table, $this->uid);
152 if ($this->row) {
153 $this->pageInfo = BackendUtility::readPageAccess($this->row['pid'], $this->permsClause);
154 $this->access = is_array($this->pageInfo) ? 1 : 0;
155 }
156 }
157 }
158 }
159
160 /**
161 * Init file/folder parameters
162 */
163 protected function initFileOrFolderRecord()
164 {
165 $fileOrFolderObject = ResourceFactory::getInstance()->retrieveFileOrFolderObject($this->uid);
166
167 if ($fileOrFolderObject instanceof Folder) {
168 $this->folderObject = $fileOrFolderObject;
169 $this->access = $this->folderObject->checkActionPermission('read');
170 $this->type = 'folder';
171 } else {
172 $this->fileObject = $fileOrFolderObject;
173 $this->access = $this->fileObject->checkActionPermission('read');
174 $this->type = 'file';
175 $this->table = 'sys_file';
176
177 try {
178 $this->row = BackendUtility::getRecordWSOL($this->table, $fileOrFolderObject->getUid());
179 } catch (\Exception $e) {
180 $this->row = [];
181 }
182 }
183 }
184
185 /**
186 * Injects the request object for the current request or subrequest
187 * As this controller goes only through the main() method, it is rather simple for now
188 *
189 * @param ServerRequestInterface $request the current request
190 * @param ResponseInterface $response
191 * @return ResponseInterface the response with the content
192 */
193 public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
194 {
195 $this->main();
196
197 $response->getBody()->write($this->moduleTemplate->renderContent());
198 return $response;
199 }
200
201 /**
202 * @return void
203 */
204 public function main()
205 {
206 if (!$this->access) {
207 return;
208 }
209
210 $content = '';
211
212 // render type by user func
213 $typeRendered = false;
214 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/show_item.php']['typeRendering'])) {
215 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/show_item.php']['typeRendering'] as $classRef) {
216 $typeRenderObj = GeneralUtility::getUserObj($classRef);
217 if (is_object($typeRenderObj) && method_exists($typeRenderObj, 'isValid') && method_exists($typeRenderObj, 'render')) {
218 if ($typeRenderObj->isValid($this->type, $this)) {
219 $content .= $typeRenderObj->render($this->type, $this);
220 $typeRendered = true;
221 break;
222 }
223 }
224 }
225 }
226
227 if (!$typeRendered) {
228 $content .= $this->renderPageTitle();
229 $content .= $this->renderPreview();
230 $content .= $this->renderPropertiesAsTable();
231 $content .= $this->renderReferences();
232 $content.= $this->renderBackButton();
233 }
234 $this->moduleTemplate->setContent($content);
235 }
236
237 /**
238 * Render page title with icon, table title and record title
239 *
240 * @return string
241 */
242 protected function renderPageTitle()
243 {
244 $title = strip_tags(BackendUtility::getRecordTitle($this->table, $this->row));
245 if ($this->type === 'folder') {
246 $table = $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_common.xlf:folder');
247 $icon = $this->iconFactory->getIconForResource($this->folderObject, Icon::SIZE_SMALL)->render();
248 } elseif ($this->type === 'file') {
249 $table = $this->getLanguageService()->sL($GLOBALS['TCA'][$this->table]['ctrl']['title']);
250 $icon = $this->iconFactory->getIconForResource($this->fileObject, Icon::SIZE_SMALL)->render();
251 } else {
252 $table = $this->getLanguageService()->sL($GLOBALS['TCA'][$this->table]['ctrl']['title']);
253 $icon = $this->iconFactory->getIconForRecord($this->table, $this->row, Icon::SIZE_SMALL);
254 }
255 // Set HTML title tag
256 $this->moduleTemplate->setTitle($table . ': ' . $title);
257 return '<h1>' .
258 ($table ? '<small>' . $table . '</small><br />' : '') .
259 $icon . $title .
260 '</h1>';
261 }
262
263 /**
264 * Render preview for current record
265 *
266 * @return string
267 */
268 protected function renderPreview()
269 {
270 // Perhaps @todo in future: Also display preview for records - without fileObject
271 if (!$this->fileObject) {
272 return '';
273 }
274
275 $previewTag = '';
276 $showLink = '';
277
278 // check if file is marked as missing
279 if ($this->fileObject->isMissing()) {
280 $previewTag .= '<span class="label label-danger">'
281 . htmlspecialchars(static::getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:warning.file_missing'))
282 . '</span>&nbsp;' . htmlspecialchars($this->fileObject->getName()) . '<br />';
283 } else {
284
285 /** @var \TYPO3\CMS\Core\Resource\Rendering\RendererRegistry $rendererRegistry */
286 $rendererRegistry = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\Rendering\RendererRegistry::class);
287 $fileRenderer = $rendererRegistry->getRenderer($this->fileObject);
288 $fileExtension = $this->fileObject->getExtension();
289 $url = $this->fileObject->getPublicUrl(true);
290
291 // Check if there is a FileRenderer
292 if ($fileRenderer !== null) {
293 $previewTag = $fileRenderer->render(
294 $this->fileObject,
295 '590m',
296 '400m',
297 [],
298 true
299 );
300
301 // else check if we can create an Image preview
302 } elseif (GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileExtension)) {
303 $processedFile = $this->fileObject->process(
304 ProcessedFile::CONTEXT_IMAGEPREVIEW,
305 [
306 'width' => '590m',
307 'height' => '400m'
308 ]
309 );
310 // Create thumbnail image?
311 if ($processedFile) {
312 $thumbUrl = $processedFile->getPublicUrl(true);
313 $previewTag .= '<img class="img-responsive img-thumbnail" src="' . $thumbUrl . '" ' .
314 'width="' . $processedFile->getProperty('width') . '" ' .
315 'height="' . $processedFile->getProperty('height') . '" ' .
316 'alt="' . htmlspecialchars(trim($this->fileObject->getName())) . '" ' .
317 'title="' . htmlspecialchars(trim($this->fileObject->getName())) . '" />';
318 }
319 }
320
321 // Show
322 if ($url) {
323 $showLink .= '
324 <a class="btn btn-primary" href="' . htmlspecialchars($url) . '" target="_blank">
325 ' . $this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL)->render('inline') . '
326 ' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.show')) . '
327 </a>';
328 }
329 }
330
331 return ($previewTag ? '<p>' . $previewTag . '</p>' : '') .
332 ($showLink ? '<p>' . $showLink . '</p>' : '');
333 }
334
335 /**
336 * Render property array as html table
337 *
338 * @return string
339 */
340 protected function renderPropertiesAsTable()
341 {
342 $tableRows = [];
343 $extraFields = [];
344
345 $lang = $this->getLanguageService();
346 if (in_array($this->type, ['folder', 'file'], true)) {
347 if ($this->type === 'file') {
348 $extraFields['creation_date'] = htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.creationDate'));
349 $extraFields['modification_date'] = htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.timestamp'));
350 }
351 $extraFields['storage'] = htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_tca.xlf:sys_file.storage'));
352 $extraFields['folder'] = htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_common.xlf:folder'));
353 } else {
354 $extraFields['crdate'] = htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.creationDate'));
355 $extraFields['cruser_id'] = htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.creationUserId'));
356 $extraFields['tstamp'] = htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.timestamp'));
357
358 // check if the special fields are defined in the TCA ctrl section of the table
359 foreach ($extraFields as $fieldName => $fieldLabel) {
360 if (isset($GLOBALS['TCA'][$this->table]['ctrl'][$fieldName])) {
361 $extraFields[$GLOBALS['TCA'][$this->table]['ctrl'][$fieldName]] = $fieldLabel;
362 } else {
363 unset($extraFields[$fieldName]);
364 }
365 }
366 }
367
368 foreach ($extraFields as $name => $fieldLabel) {
369 $rowValue = '';
370 if (!isset($this->row[$name])) {
371 $resourceObject = $this->fileObject ?: $this->folderObject;
372 if ($name === 'storage') {
373 $rowValue = $resourceObject->getStorage()->getName();
374 } elseif ($name === 'folder') {
375 $rowValue = $resourceObject->getParentFolder()->getReadablePath();
376 }
377 } elseif (in_array($name, ['creation_date', 'modification_date'], true)) {
378 $rowValue = BackendUtility::datetime($this->row[$name]);
379 } else {
380 $rowValue = BackendUtility::getProcessedValueExtra($this->table, $name, $this->row[$name]);
381 }
382 // show the backend username who created the issue
383 if ($name === 'cruser_id' && $rowValue) {
384 $creatorRecord = BackendUtility::getRecord('be_users', $rowValue);
385 if ($creatorRecord) {
386 /** @var Avatar $avatar */
387 $avatar = GeneralUtility::makeInstance(Avatar::class);
388 $icon = $avatar->render($creatorRecord);
389 $rowValue = '
390 <div class="media">
391 <div class="media-left">
392 ' . $icon . '
393 </div>
394 <div class="media-body">
395 <strong>' . htmlspecialchars($creatorRecord['username']) . '</strong><br>
396 ' . ($creatorRecord['realName'] ? htmlspecialchars($creatorRecord['realName']) : '') . '
397 </div>
398 </div>';
399 }
400 }
401
402 $tableRows[] = '
403 <tr>
404 <th class="col-nowrap">' . rtrim($fieldLabel, ':') . '</th>
405 <td>' . ($name === 'cruser_id' ? $rowValue : htmlspecialchars($rowValue)) . '</td>
406 </tr>';
407 }
408
409 // Traverse the list of fields to display for the record:
410 $fieldList = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$this->table]['interface']['showRecordFieldList'], true);
411 foreach ($fieldList as $name) {
412 $name = trim($name);
413 $uid = $this->row['uid'];
414
415 if (!isset($GLOBALS['TCA'][$this->table]['columns'][$name])) {
416 continue;
417 }
418
419 // Storage is already handled above
420 if ($this->type === 'file' && $name === 'storage') {
421 continue;
422 }
423
424 // format file size as bytes/kilobytes/megabytes
425 if ($this->type === 'file' && $name === 'size') {
426 $this->row[$name] = GeneralUtility::formatSize($this->row[$name], htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_common.xlf:byteSizeUnits')));
427 }
428
429 $isExcluded = !(!$GLOBALS['TCA'][$this->table]['columns'][$name]['exclude'] || $this->getBackendUser()->check('non_exclude_fields', $this->table . ':' . $name));
430 if ($isExcluded) {
431 continue;
432 }
433
434 $itemValue = BackendUtility::getProcessedValue($this->table, $name, $this->row[$name], 0, 0, false, $uid);
435 $itemLabel = htmlspecialchars($lang->sL(BackendUtility::getItemLabel($this->table, $name)));
436 $tableRows[] = '
437 <tr>
438 <th class="col-nowrap">' . $itemLabel . '</th>
439 <td>' . htmlspecialchars($itemValue) . '</td>
440 </tr>';
441 }
442
443 return '
444 <div class="table-fit table-fit-wrap">
445 <table class="table table-striped table-hover">
446 ' . implode('', $tableRows) . '
447 </table>
448 </div>';
449 }
450
451 /**
452 * Render references section (references from and references to current record)
453 *
454 * @return string
455 */
456 protected function renderReferences()
457 {
458 $content = '';
459
460 switch ($this->type) {
461 case 'db': {
462 $references = $this->makeRef($this->table, $this->row['uid']);
463 if (!empty($references)) {
464 $content .= '<h3>' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.referencesToThisItem')) . '</h3>';
465 $content .= $references;
466 }
467
468 $referencesFrom = $this->makeRefFrom($this->table, $this->row['uid']);
469 if (!empty($referencesFrom)) {
470 $content .= '<h3>' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.referencesFromThisItem')) . '</h3>';
471 $content .= $referencesFrom;
472 }
473 break;
474 }
475
476 case 'file': {
477 if ($this->fileObject && $this->fileObject->isIndexed()) {
478 $references = $this->makeRef('_FILE', $this->fileObject);
479
480 if (!empty($references)) {
481 $content .= '<h3>' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.referencesToThisItem')) . '</h3>';
482 $content .= $references;
483 }
484 }
485 break;
486 }
487 }
488
489 return $content;
490 }
491
492 /**
493 * Render a back button, if a returnUrl was provided
494 *
495 * @return string
496 */
497 protected function renderBackButton()
498 {
499 $backLink = '';
500 $returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GET('returnUrl'));
501 if ($returnUrl) {
502 $backLink .= '
503 <a class="btn btn-primary" href="' . htmlspecialchars($returnUrl) . '">
504 ' . $this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL)->render() . '
505 ' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_common.xlf:back')) . '
506 </a>';
507 }
508 return $backLink;
509 }
510
511 /**
512 * Renders file properties as html table
513 *
514 * @param array $fieldList
515 * @return string
516 */
517 protected function renderFileInformationAsTable($fieldList)
518 {
519 $tableRows = [];
520 foreach ($fieldList as $name) {
521 if (!isset($GLOBALS['TCA'][$this->table]['columns'][$name])) {
522 continue;
523 }
524 $isExcluded = !(!$GLOBALS['TCA'][$this->table]['columns'][$name]['exclude'] || $this->getBackendUser()->check('non_exclude_fields', $this->table . ':' . $name));
525 if ($isExcluded) {
526 continue;
527 }
528 $uid = $this->row['uid'];
529 $itemValue = BackendUtility::getProcessedValue($this->table, $name, $this->row[$name], 0, 0, false, $uid);
530 $itemLabel = htmlspecialchars($this->getLanguageService()->sL(BackendUtility::getItemLabel($this->table, $name)));
531 $tableRows[] = '
532 <tr>
533 <th>' . $itemLabel . '</th>
534 <td>' . htmlspecialchars($itemValue) . '</td>
535 </tr>';
536 }
537
538 if (!$tableRows) {
539 return '';
540 }
541
542 return '
543 <div class="table-fit table-fit-wrap">
544 <table class="table table-striped table-hover">
545 ' . implode('', $tableRows) . '
546 </table>
547 </div>';
548 }
549
550 /**
551 * Get field name for specified table/column name
552 *
553 * @param string $tableName Table name
554 * @param string $fieldName Column name
555 * @return string label
556 */
557 public function getLabelForTableColumn($tableName, $fieldName)
558 {
559 if ($GLOBALS['TCA'][$tableName]['columns'][$fieldName]['label'] !== null) {
560 $field = $this->getLanguageService()->sL($GLOBALS['TCA'][$tableName]['columns'][$fieldName]['label']);
561 if (trim($field) === '') {
562 $field = $fieldName;
563 }
564 } else {
565 $field = $fieldName;
566 }
567 return $field;
568 }
569
570 /**
571 * Returns the rendered record actions
572 *
573 * @param string $table
574 * @param int $uid
575 * @return string
576 */
577 protected function getRecordActions($table, $uid)
578 {
579 if ($table === '' || $uid < 0) {
580 return '';
581 }
582
583 // Edit button
584 $urlParameters = [
585 'edit' => [
586 $table => [
587 $uid => 'edit'
588 ]
589 ],
590 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
591 ];
592 $url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
593 $pageActionIcons = '
594 <a class="btn btn-default btn-sm" href="' . htmlspecialchars($url) . '">
595 ' . $this->iconFactory->getIcon('actions-open', Icon::SIZE_SMALL)->render() . '
596 </a>';
597
598 // History button
599 $urlParameters = [
600 'element' => $table . ':' . $uid,
601 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
602 ];
603 $url = BackendUtility::getModuleUrl('record_history', $urlParameters);
604 $pageActionIcons .= '
605 <a class="btn btn-default btn-sm" href="' . htmlspecialchars($url) . '">
606 ' . $this->iconFactory->getIcon('actions-document-history-open', Icon::SIZE_SMALL)->render() . '
607 </a>';
608
609 if ($table === 'pages') {
610 // Recordlist button
611 $url = BackendUtility::getModuleUrl('web_list', ['id' => $uid, 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')]);
612 $pageActionIcons .= '
613 <a class="btn btn-default btn-sm" href="' . htmlspecialchars($url) . '" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.showList') . '">
614 ' . $this->iconFactory->getIcon('actions-system-list-open', Icon::SIZE_SMALL)->render() . '
615 </a>';
616
617 // View page button
618 $viewOnClick = BackendUtility::viewOnClick($uid, '', BackendUtility::BEgetRootLine($uid));
619 $pageActionIcons .= '
620 <a class="btn btn-default btn-sm" href="#" onclick="' . htmlspecialchars($viewOnClick) . '" title="' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.showPage')) . '">
621 ' . $this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL)->render() . '
622 </a>';
623 }
624
625 return '
626 <div class="btn-group" role="group">
627 ' . $pageActionIcons . '
628 </div>';
629 }
630
631 /**
632 * Make reference display
633 *
634 * @param string $table Table name
635 * @param string|\TYPO3\CMS\Core\Resource\File $ref Filename or uid
636 * @return string HTML
637 */
638 protected function makeRef($table, $ref)
639 {
640 $lang = $this->getLanguageService();
641 // Files reside in sys_file table
642 if ($table === '_FILE') {
643 $selectTable = 'sys_file';
644 $selectUid = $ref->getUid();
645 } else {
646 $selectTable = $table;
647 $selectUid = $ref;
648 }
649 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
650 ->getQueryBuilderForTable('sys_refindex');
651 $rows = $queryBuilder
652 ->select('*')
653 ->from('sys_refindex')
654 ->where(
655 $queryBuilder->expr()->eq(
656 'ref_table',
657 $queryBuilder->createNamedParameter($selectTable, \PDO::PARAM_STR)
658 ),
659 $queryBuilder->expr()->eq(
660 'ref_uid',
661 $queryBuilder->createNamedParameter($selectUid, \PDO::PARAM_INT)
662 ),
663 $queryBuilder->expr()->eq(
664 'deleted',
665 $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
666 )
667 )
668 ->execute()
669 ->fetchAll();
670
671 // Compile information for title tag:
672 $infoData = [];
673 $infoDataHeader = '';
674 if (!empty($rows)) {
675 $infoDataHeader = '
676 <tr>
677 <th class="col-icon"></th>
678 <th class="col-title">' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.title') . '</th>
679 <th>' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.table') . '</th>
680 <th>' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.uid') . '</th>
681 <th>' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.field') . '</th>
682 <th>' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.flexpointer') . '</th>
683 <th>' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.softrefKey') . '</th>
684 <th>' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.sorting') . '</th>
685 <th class="col-control"></th>
686 </tr>';
687 }
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 $record = BackendUtility::getRecord($row['tablename'], $row['recuid']);
696 if ($record) {
697 $parentRecord = BackendUtility::getRecord('pages', $record['pid']);
698 $parentRecordTitle = is_array($parentRecord)
699 ? BackendUtility::getRecordTitle('pages', $parentRecord)
700 : '';
701 $icon = $this->iconFactory->getIconForRecord($row['tablename'], $record, Icon::SIZE_SMALL)->render();
702 $actions = $this->getRecordActions($row['tablename'], $row['recuid']);
703 $urlParameters = [
704 'edit' => [
705 $row['tablename'] => [
706 $row['recuid'] => 'edit'
707 ]
708 ],
709 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
710 ];
711 $url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
712 $infoData[] = '
713 <tr>
714 <td class="col-icon">
715 <a href="' . htmlspecialchars($url) . '" title="id=' . $record['uid'] . '">
716 ' . $icon . '
717 </a>
718 </td>
719 <td class="col-title">
720 <a href="' . htmlspecialchars($url) . '" title="id=' . $record['uid'] . '" >
721 ' . BackendUtility::getRecordTitle($row['tablename'], $record, true) . '
722 </a>
723 </td>
724 <td>' . htmlspecialchars($lang->sL($GLOBALS['TCA'][$row['tablename']]['ctrl']['title'])) . '</td>
725 <td>
726 <span title="' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_common.xlf:page') . ': '
727 . htmlspecialchars($parentRecordTitle) . ' (uid=' . $record['pid'] . ')">
728 ' . $record['uid'] . '
729 </span>
730 </td>
731 <td>' . htmlspecialchars($this->getLabelForTableColumn($row['tablename'], $row['field'])) . '</td>
732 <td>' . htmlspecialchars($row['flexpointer']) . '</td>
733 <td>' . htmlspecialchars($row['softref_key']) . '</td>
734 <td>' . htmlspecialchars($row['sorting']) . '</td>
735 <td class="col-control">' . $actions . '</td>
736 </tr>';
737 } else {
738 $infoData[] = '
739 <tr>
740 <td class="col-icon"></td>
741 <td class="col-title">' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.missing_record') . ' (uid=' . (int)$row['recuid'] . ')</td>
742 <td>' . htmlspecialchars($lang->sL($GLOBALS['TCA'][$row['tablename']]['ctrl']['title']) ?: $row['tablename']) . '</td>
743 <td></td>
744 <td>' . htmlspecialchars($this->getLabelForTableColumn($row['tablename'], $row['field'])) . '</td>
745 <td>' . htmlspecialchars($row['flexpointer']) . '</td>
746 <td>' . htmlspecialchars($row['softref_key']) . '</td>
747 <td>' . htmlspecialchars($row['sorting']) . '</td>
748 <td class="col-control"></td>
749 </tr>';
750 }
751 }
752 $referenceLine = '';
753 if (!empty($infoData)) {
754 $referenceLine = '
755 <div class="table-fit">
756 <table class="table table-striped table-hover">
757 <thead>' . $infoDataHeader . '</thead>
758 <tbody>' . implode('', $infoData) . '</tbody>
759 </table>
760 </div>';
761 }
762 return $referenceLine;
763 }
764
765 /**
766 * Make reference display (what this elements points to)
767 *
768 * @param string $table Table name
769 * @param string $ref Filename or uid
770 * @return string HTML
771 */
772 protected function makeRefFrom($table, $ref)
773 {
774 $lang = $this->getLanguageService();
775
776 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
777 ->getQueryBuilderForTable('sys_refindex');
778 $rows = $queryBuilder
779 ->select('*')
780 ->from('sys_refindex')
781 ->where(
782 $queryBuilder->expr()->eq(
783 'tablename',
784 $queryBuilder->createNamedParameter($table, \PDO::PARAM_STR)
785 ),
786 $queryBuilder->expr()->eq(
787 'recuid',
788 $queryBuilder->createNamedParameter($ref, \PDO::PARAM_INT)
789 )
790 )
791 ->execute()
792 ->fetchAll();
793
794 // Compile information for title tag:
795 $infoData = [];
796 $infoDataHeader = '';
797 if (!empty($rows)) {
798 $infoDataHeader = '
799 <tr>
800 <th class="col-icon"></th>
801 <th class="col-title">' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.title') . '</th>
802 <th>' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.table') . '</th>
803 <th>' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.uid') . '</th>
804 <th>' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.field') . '</th>
805 <th>' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.flexpointer') . '</th>
806 <th>' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.softrefKey') . '</th>
807 <th>' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.sorting') . '</th>
808 <th>' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.refString') . '</th>
809 <th class="col-control"></th>
810 </tr>';
811 }
812 foreach ($rows as $row) {
813 $record = BackendUtility::getRecord($row['ref_table'], $row['ref_uid']);
814 if ($record) {
815 $icon = $this->iconFactory->getIconForRecord($row['tablename'], $record, Icon::SIZE_SMALL)->render();
816 $actions = $this->getRecordActions($row['ref_table'], $row['ref_uid']);
817
818 $urlParameters = [
819 'edit' => [
820 $row['ref_table'] => [
821 $row['ref_uid'] => 'edit'
822 ]
823 ],
824 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
825 ];
826 $url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
827 $infoData[] = '
828 <tr>
829 <td class="col-icon">
830 <a href="' . htmlspecialchars($url) . '" title="id=' . $record['uid'] . '">
831 ' . $icon . '
832 </a>
833 </td>
834 <td class="col-title">
835 <a href="' . htmlspecialchars($url) . '" title="id=' . $record['uid'] . '" >
836 ' . BackendUtility::getRecordTitle($row['ref_table'], $record, true) . '
837 </a>
838 </td>
839 <td>' . htmlspecialchars($lang->sL($GLOBALS['TCA'][$row['ref_table']]['ctrl']['title'])) . '</td>
840 <td>' . htmlspecialchars($row['ref_uid']) . '</td>
841 <td>' . htmlspecialchars($this->getLabelForTableColumn($table, $row['field'])) . '</td>
842 <td>' . htmlspecialchars($row['flexpointer']) . '</td>
843 <td>' . htmlspecialchars($row['softref_key']) . '</td>
844 <td>' . htmlspecialchars($row['sorting']) . '</td>
845 <td>' . htmlspecialchars($row['ref_string']) . '</td>
846 <td class="col-control">' . $actions . '</td>
847 </tr>';
848 } else {
849 $infoData[] = '
850 <tr>
851 <td class="col-icon"></td>
852 <td class="col-title">' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:show_item.php.missing_record') . ' (uid=' . (int)$row['recuid'] . ')</td>
853 <td>' . htmlspecialchars($lang->sL($GLOBALS['TCA'][$row['ref_table']]['ctrl']['title'])) . '</td>
854 <td></td>
855 <td>' . htmlspecialchars($this->getLabelForTableColumn($table, $row['field'])) . '</td>
856 <td>' . htmlspecialchars($row['flexpointer']) . '</td>
857 <td>' . htmlspecialchars($row['softref_key']) . '</td>
858 <td>' . htmlspecialchars($row['sorting']) . '</td>
859 <td>' . htmlspecialchars($row['ref_string']) . '</td>
860 <td class="col-control"></td>
861 </tr>';
862 }
863 }
864
865 if (empty($infoData)) {
866 return '';
867 }
868
869 return '
870 <div class="table-fit">
871 <table class="table table-striped table-hover">
872 <thead>' . $infoDataHeader . '</thead>
873 <tbody>' . implode('', $infoData) . '</tbody>
874 </table>
875 </div>';
876 }
877
878 /**
879 * Convert FAL file reference (sys_file_reference) to reference index (sys_refindex) table format
880 *
881 * @param array $referenceRecord
882 * @return array
883 */
884 protected function transformFileReferenceToRecordReference(array $referenceRecord)
885 {
886 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
887 ->getQueryBuilderForTable('sys_file_reference');
888 $queryBuilder->getRestrictions()->removeAll();
889 $fileReference = $queryBuilder
890 ->select('*')
891 ->from('sys_file_reference')
892 ->where(
893 $queryBuilder->expr()->eq(
894 'uid',
895 $queryBuilder->createNamedParameter($referenceRecord['recuid'], \PDO::PARAM_INT)
896 )
897 )
898 ->execute()
899 ->fetch();
900
901 return [
902 'recuid' => $fileReference['uid_foreign'],
903 'tablename' => $fileReference['tablenames'],
904 'field' => $fileReference['fieldname'],
905 'flexpointer' => '',
906 'softref_key' => '',
907 'sorting' => $fileReference['sorting_foreign']
908 ];
909 }
910
911 /**
912 * Returns LanguageService
913 *
914 * @return \TYPO3\CMS\Lang\LanguageService
915 */
916 protected function getLanguageService()
917 {
918 return $GLOBALS['LANG'];
919 }
920
921 /**
922 * Returns the current BE user.
923 *
924 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
925 */
926 protected function getBackendUser()
927 {
928 return $GLOBALS['BE_USER'];
929 }
930 }