74be181ea8796e419cca18e0542155adf5f37282
[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
400 $rowValue = '<span class="pull-left">' . $icon . '</span>' .
401 '<strong>' . htmlspecialchars($GLOBALS['BE_USER']->user['username']) . '</strong><br />'
402 . ($GLOBALS['BE_USER']->user['realName'] ? htmlspecialchars($GLOBALS['BE_USER']->user['realName']) : '');
403 }
404 }
405
406 $tableRows[] = '
407 <tr>
408 <th>' . rtrim($fieldLabel, ':') . '</th>
409 <td>' . ($name === 'cruser_id' ? $rowValue : htmlspecialchars($rowValue)) . '</td>
410 </tr>';
411 }
412
413 // Traverse the list of fields to display for the record:
414 $fieldList = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$this->table]['interface']['showRecordFieldList'], true);
415 foreach ($fieldList as $name) {
416 $name = trim($name);
417 $uid = $this->row['uid'];
418
419 if (!isset($GLOBALS['TCA'][$this->table]['columns'][$name])) {
420 continue;
421 }
422
423 // Storage is already handled above
424 if ($this->type === 'file' && $name === 'storage') {
425 continue;
426 }
427
428 $isExcluded = !(!$GLOBALS['TCA'][$this->table]['columns'][$name]['exclude'] || $this->getBackendUser()->check('non_exclude_fields', $this->table . ':' . $name));
429 if ($isExcluded) {
430 continue;
431 }
432
433 $itemValue = BackendUtility::getProcessedValue($this->table, $name, $this->row[$name], 0, 0, false, $uid);
434 $itemLabel = $lang->sL(BackendUtility::getItemLabel($this->table, $name), true);
435 $tableRows[] = '
436 <tr>
437 <th>' . $itemLabel . '</th>
438 <td>' . htmlspecialchars($itemValue) . '</td>
439 </tr>';
440 }
441
442 return '
443 <div class="table-fit table-fit-wrap">
444 <table class="table table-striped table-hover">
445 ' . implode('', $tableRows) . '
446 </table>
447 </div>';
448 }
449
450 /**
451 * Render references section (references from and references to current record)
452 *
453 * @return string
454 */
455 protected function renderReferences()
456 {
457 $content = '';
458
459 switch ($this->type) {
460 case 'db': {
461 $references = $this->makeRef($this->table, $this->row['uid']);
462 if (!empty($references)) {
463 $content .= $this->doc->section($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.referencesToThisItem'), $references);
464 }
465
466 $referencesFrom = $this->makeRefFrom($this->table, $this->row['uid']);
467 if (!empty($referencesFrom)) {
468 $content .= $this->doc->section($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.referencesFromThisItem'), $referencesFrom);
469 }
470 break;
471 }
472
473 case 'file': {
474 if ($this->fileObject && $this->fileObject->isIndexed()) {
475 $references = $this->makeRef('_FILE', $this->fileObject);
476
477 if (!empty($references)) {
478 $header = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.referencesToThisItem');
479 $content .= $this->doc->section($header, $references);
480 }
481 }
482 break;
483 }
484 }
485
486 return $content;
487 }
488
489 /**
490 * Render a back button, if a returnUrl was provided
491 *
492 * @return string
493 */
494 protected function renderBackButton()
495 {
496 $backLink = '';
497 $returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GET('returnUrl'));
498 if ($returnUrl) {
499 $backLink .= '
500 <a class="btn btn-primary" href="' . htmlspecialchars($returnUrl) . '>
501 ' . $this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL)->render() . '
502 ' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_common.xlf:back', true) . '
503 </a>';
504 }
505 return $backLink;
506 }
507
508 /**
509 * Renders file properties as html table
510 *
511 * @param array $fieldList
512 * @return string
513 */
514 protected function renderFileInformationAsTable($fieldList)
515 {
516 $tableRows = array();
517 foreach ($fieldList as $name) {
518 if (!isset($GLOBALS['TCA'][$this->table]['columns'][$name])) {
519 continue;
520 }
521 $isExcluded = !(!$GLOBALS['TCA'][$this->table]['columns'][$name]['exclude'] || $this->getBackendUser()->check('non_exclude_fields', $this->table . ':' . $name));
522 if ($isExcluded) {
523 continue;
524 }
525 $uid = $this->row['uid'];
526 $itemValue = BackendUtility::getProcessedValue($this->table, $name, $this->row[$name], 0, 0, false, $uid);
527 $itemLabel = $this->getLanguageService()->sL(BackendUtility::getItemLabel($this->table, $name), true);
528 $tableRows[] = '
529 <tr>
530 <th>' . $itemLabel . '</th>
531 <td>' . htmlspecialchars($itemValue) . '</td>
532 </tr>';
533 }
534
535 if (!$tableRows) {
536 return '';
537 }
538
539 return '
540 <div class="table-fit table-fit-wrap">
541 <table class="table table-striped table-hover">
542 ' . implode('', $tableRows) . '
543 </table>
544 </div>';
545 }
546
547 /**
548 * End page and print content
549 *
550 * @return void
551 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use mainAction() instead
552 */
553 public function printContent()
554 {
555 GeneralUtility::logDeprecatedFunction();
556 echo $this->doc->startPage($this->titleTag) .
557 $this->doc->insertStylesAndJS($this->content) .
558 $this->doc->endPage();
559 }
560
561 /**
562 * Get field name for specified table/column name
563 *
564 * @param string $tableName Table name
565 * @param string $fieldName Column name
566 * @return string label
567 */
568 public function getLabelForTableColumn($tableName, $fieldName)
569 {
570 if ($GLOBALS['TCA'][$tableName]['columns'][$fieldName]['label'] !== null) {
571 $field = $this->getLanguageService()->sL($GLOBALS['TCA'][$tableName]['columns'][$fieldName]['label']);
572 if (trim($field) === '') {
573 $field = $fieldName;
574 }
575 } else {
576 $field = $fieldName;
577 }
578 return $field;
579 }
580
581 /**
582 * Returns the rendered record actions
583 *
584 * @param string $table
585 * @param int $uid
586 * @return string
587 */
588 protected function getRecordActions($table, $uid)
589 {
590 if ($table === '' || $uid < 0) {
591 return '';
592 }
593
594 // Edit button
595 $urlParameters = [
596 'edit' => [
597 $table => [
598 $uid => 'edit'
599 ]
600 ],
601 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
602 ];
603 $url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
604 $pageActionIcons = '
605 <a class="btn btn-default btn-sm" href="' . htmlspecialchars($url) . '">
606 ' . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . '
607 </a>';
608
609 // History button
610 $urlParameters = [
611 'element' => $table . ':' . $uid,
612 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
613 ];
614 $url = BackendUtility::getModuleUrl('record_history', $urlParameters);
615 $pageActionIcons .= '
616 <a class="btn btn-default btn-sm" href="' . htmlspecialchars($url) . '">
617 ' . $this->iconFactory->getIcon('actions-document-history-open', Icon::SIZE_SMALL)->render() . '
618 </a>';
619
620 if ($table === 'pages') {
621 // Recordlist button
622 $url = BackendUtility::getModuleUrl('web_list', array('id' => $uid, 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')));
623 $pageActionIcons .= '
624 <a class="btn btn-default btn-sm" href="' . htmlspecialchars($url) . '" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.showList') . '">
625 ' . $this->iconFactory->getIcon('actions-system-list-open', Icon::SIZE_SMALL)->render() . '
626 </a>';
627
628 // View page button
629 $viewOnClick = BackendUtility::viewOnClick($uid, '', BackendUtility::BEgetRootLine($uid));
630 $pageActionIcons .= '
631 <a class="btn btn-default btn-sm" href="#" onclick="' . htmlspecialchars($viewOnClick) . '" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', true) . '">
632 ' . $this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL)->render() . '
633 </a>';
634 }
635
636 return '
637 <div class="btn-group" role="group">
638 ' . $pageActionIcons . '
639 </div>';
640 }
641
642 /**
643 * Make reference display
644 *
645 * @param string $table Table name
646 * @param string|\TYPO3\CMS\Core\Resource\File $ref Filename or uid
647 * @return string HTML
648 */
649 protected function makeRef($table, $ref)
650 {
651 $lang = $this->getLanguageService();
652 // Files reside in sys_file table
653 if ($table === '_FILE') {
654 $selectTable = 'sys_file';
655 $selectUid = $ref->getUid();
656 } else {
657 $selectTable = $table;
658 $selectUid = $ref;
659 }
660 $rows = $this->getDatabaseConnection()->exec_SELECTgetRows(
661 '*',
662 'sys_refindex',
663 'ref_table=' . $this->getDatabaseConnection()->fullQuoteStr($selectTable, 'sys_refindex') . ' AND ref_uid=' . (int)$selectUid . ' AND deleted=0'
664 );
665
666 // Compile information for title tag:
667 $infoData = array();
668 $infoDataHeader = '';
669 if (!empty($rows)) {
670 $infoDataHeader = '
671 <tr>
672 <th class="col-icon"></th>
673 <th class="col-title">' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.title') . '</th>
674 <th>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.table') . '</th>
675 <th>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.uid') . '</th>
676 <th>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.field') . '</th>
677 <th>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.flexpointer') . '</th>
678 <th>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.softrefKey') . '</th>
679 <th>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.sorting') . '</th>
680 <th class="col-control"></th>
681 </tr>';
682 }
683 foreach ($rows as $row) {
684 if ($row['tablename'] === 'sys_file_reference') {
685 $row = $this->transformFileReferenceToRecordReference($row);
686 if ($row['tablename'] === null || $row['recuid'] === null) {
687 return '';
688 }
689 }
690 $record = BackendUtility::getRecord($row['tablename'], $row['recuid']);
691 if ($record) {
692 $parentRecord = BackendUtility::getRecord('pages', $record['pid']);
693 $parentRecordTitle = is_array($parentRecord)
694 ? BackendUtility::getRecordTitle('pages', $parentRecord)
695 : '';
696 $icon = $this->iconFactory->getIconForRecord($row['tablename'], $record, Icon::SIZE_SMALL)->render();
697 $actions = $this->getRecordActions($row['tablename'], $row['recuid']);
698 $urlParameters = [
699 'edit' => [
700 $row['tablename'] => [
701 $row['recuid'] => 'edit'
702 ]
703 ],
704 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
705 ];
706 $url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
707 $infoData[] = '
708 <tr>
709 <td class="col-icon">
710 <a href="' . htmlspecialchars($url) . '" title="id=' . $record['uid'] . '">
711 ' . $icon . '
712 </a>
713 </td>
714 <td class="col-title">
715 <a href="' . htmlspecialchars($url) . '" title="id=' . $record['uid'] . '" >
716 ' . BackendUtility::getRecordTitle($row['tablename'], $record, true) . '
717 </a>
718 </td>
719 <td>' . $lang->sL($GLOBALS['TCA'][$row['tablename']]['ctrl']['title'], true) . '</td>
720 <td>
721 <span title="' . $lang->sL('LLL:EXT:lang/locallang_common.xlf:page') . ': '
722 . htmlspecialchars($parentRecordTitle) . ' (uid=' . $record['pid'] . ')">
723 ' . $record['uid'] . '
724 </span>
725 </td>
726 <td>' . htmlspecialchars($this->getLabelForTableColumn($row['tablename'], $row['field'])) . '</td>
727 <td>' . htmlspecialchars($row['flexpointer']) . '</td>
728 <td>' . htmlspecialchars($row['softref_key']) . '</td>
729 <td>' . htmlspecialchars($row['sorting']) . '</td>
730 <td class="col-control">' . $actions . '</td>
731 </tr>';
732 } else {
733 $infoData[] = '
734 <tr>
735 <td class="col-icon"></td>
736 <td class="col-title">' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.missing_record') . ' (uid=' . (int)$row['recuid'] . ')</td>
737 <td>' . htmlspecialchars($lang->sL($GLOBALS['TCA'][$row['tablename']]['ctrl']['title']) ?: $row['tablename']) . '</td>
738 <td></td>
739 <td>' . htmlspecialchars($this->getLabelForTableColumn($row['tablename'], $row['field'])) . '</td>
740 <td>' . htmlspecialchars($row['flexpointer']) . '</td>
741 <td>' . htmlspecialchars($row['softref_key']) . '</td>
742 <td>' . htmlspecialchars($row['sorting']) . '</td>
743 <td class="col-control"></td>
744 </tr>';
745 }
746 }
747 $referenceLine = '';
748 if (!empty($infoData)) {
749 $referenceLine = '
750 <div class="table-fit">
751 <table class="table table-striped table-hover">
752 <thead>' . $infoDataHeader . '</thead>
753 <tbody>' . implode('', $infoData) . '</tbody>
754 </table>
755 </div>';
756 }
757 return $referenceLine;
758 }
759
760 /**
761 * Make reference display (what this elements points to)
762 *
763 * @param string $table Table name
764 * @param string $ref Filename or uid
765 * @return string HTML
766 */
767 protected function makeRefFrom($table, $ref)
768 {
769 $lang = $this->getLanguageService();
770 $rows = $this->getDatabaseConnection()->exec_SELECTgetRows(
771 '*',
772 'sys_refindex',
773 'tablename=' . $this->getDatabaseConnection()->fullQuoteStr($table, 'sys_refindex') . ' AND recuid=' . (int)$ref
774 );
775
776 // Compile information for title tag:
777 $infoData = array();
778 $infoDataHeader = '';
779 if (!empty($rows)) {
780 $infoDataHeader = '
781 <tr>
782 <th class="col-icon"></th>
783 <th class="col-title">' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.title') . '</th>
784 <th>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.table') . '</th>
785 <th>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.uid') . '</th>
786 <th>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.field') . '</th>
787 <th>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.flexpointer') . '</th>
788 <th>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.softrefKey') . '</th>
789 <th>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.sorting') . '</th>
790 <th>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.refString') . '</th>
791 <th class="col-control"></th>
792 </tr>';
793 }
794 foreach ($rows as $row) {
795 $record = BackendUtility::getRecord($row['ref_table'], $row['ref_uid']);
796 if ($record) {
797 $icon = $this->iconFactory->getIconForRecord($row['tablename'], $record, Icon::SIZE_SMALL)->render();
798 $actions = $this->getRecordActions($row['ref_table'], $row['ref_uid']);
799
800 $urlParameters = [
801 'edit' => [
802 $row['ref_table'] => [
803 $row['ref_uid'] => 'edit'
804 ]
805 ],
806 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
807 ];
808 $url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
809 $infoData[] = '
810 <tr>
811 <td class="col-icon">
812 <a href="' . htmlspecialchars($url) . '" title="id=' . $record['uid'] . '">
813 ' . $icon . '
814 </a>
815 </td>
816 <td class="col-title">
817 <a href="' . htmlspecialchars($url) . '" title="id=' . $record['uid'] . '" >
818 ' . BackendUtility::getRecordTitle($row['ref_table'], $record, true) . '
819 </a>
820 </td>
821 <td>' . $lang->sL($GLOBALS['TCA'][$row['ref_table']]['ctrl']['title'], true) . '</td>
822 <td>' . htmlspecialchars($row['ref_uid']) . '</td>
823 <td>' . htmlspecialchars($this->getLabelForTableColumn($table, $row['field'])) . '</td>
824 <td>' . htmlspecialchars($row['flexpointer']) . '</td>
825 <td>' . htmlspecialchars($row['softref_key']) . '</td>
826 <td>' . htmlspecialchars($row['sorting']) . '</td>
827 <td>' . htmlspecialchars($row['ref_string']) . '</td>
828 <td class="col-control">' . $actions . '</td>
829 </tr>';
830 } else {
831 $infoData[] = '
832 <tr>
833 <td class="col-icon"></td>
834 <td class="col-title">' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:show_item.php.missing_record') . ' (uid=' . (int)$row['recuid'] . ')</td>
835 <td>' . $lang->sL($GLOBALS['TCA'][$row['ref_table']]['ctrl']['title'], true) . '</td>
836 <td></td>
837 <td>' . htmlspecialchars($this->getLabelForTableColumn($table, $row['field'])) . '</td>
838 <td>' . htmlspecialchars($row['flexpointer']) . '</td>
839 <td>' . htmlspecialchars($row['softref_key']) . '</td>
840 <td>' . htmlspecialchars($row['sorting']) . '</td>
841 <td>' . htmlspecialchars($row['ref_string']) . '</td>
842 <td class="col-control"></td>
843 </tr>';
844 }
845 }
846
847 if (empty($infoData)) {
848 return '';
849 }
850
851 return '
852 <div class="table-fit">
853 <table class="table table-striped table-hover">
854 <thead>' . $infoDataHeader . '</thead>
855 <tbody>' . implode('', $infoData) . '</tbody>
856 </table>
857 </div>';
858 }
859
860 /**
861 * Convert FAL file reference (sys_file_reference) to reference index (sys_refindex) table format
862 *
863 * @param array $referenceRecord
864 * @return array
865 */
866 protected function transformFileReferenceToRecordReference(array $referenceRecord)
867 {
868 $fileReference = $this->getDatabaseConnection()->exec_SELECTgetSingleRow(
869 '*',
870 'sys_file_reference',
871 'uid=' . (int)$referenceRecord['recuid']
872 );
873 return array(
874 'recuid' => $fileReference['uid_foreign'],
875 'tablename' => $fileReference['tablenames'],
876 'field' => $fileReference['fieldname'],
877 'flexpointer' => '',
878 'softref_key' => '',
879 'sorting' => $fileReference['sorting_foreign']
880 );
881 }
882
883 /**
884 * Returns LanguageService
885 *
886 * @return \TYPO3\CMS\Lang\LanguageService
887 */
888 protected function getLanguageService()
889 {
890 return $GLOBALS['LANG'];
891 }
892
893 /**
894 * Returns the current BE user.
895 *
896 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
897 */
898 protected function getBackendUser()
899 {
900 return $GLOBALS['BE_USER'];
901 }
902
903 /**
904 * Returns the database connection
905 *
906 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
907 */
908 protected function getDatabaseConnection()
909 {
910 return $GLOBALS['TYPO3_DB'];
911 }
912 }