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