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