c2038119a4c1324868694e06d6b87d1de68379a0
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Controller / ContentElement / ElementInformationController.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Backend\Controller\ContentElement;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use Psr\Http\Message\ResponseInterface;
19 use Psr\Http\Message\ServerRequestInterface;
20 use TYPO3\CMS\Backend\Backend\Avatar\Avatar;
21 use TYPO3\CMS\Backend\Template\ModuleTemplate;
22 use TYPO3\CMS\Backend\Utility\BackendUtility;
23 use TYPO3\CMS\Core\Compatibility\PublicMethodDeprecationTrait;
24 use TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait;
25 use TYPO3\CMS\Core\Database\ConnectionPool;
26 use TYPO3\CMS\Core\Http\HtmlResponse;
27 use TYPO3\CMS\Core\Imaging\Icon;
28 use TYPO3\CMS\Core\Imaging\IconFactory;
29 use TYPO3\CMS\Core\Resource\AbstractFile;
30 use TYPO3\CMS\Core\Resource\File;
31 use TYPO3\CMS\Core\Resource\Folder;
32 use TYPO3\CMS\Core\Resource\ResourceFactory;
33 use TYPO3\CMS\Core\Type\Bitmask\Permission;
34 use TYPO3\CMS\Core\Utility\GeneralUtility;
35 use TYPO3\CMS\Fluid\View\StandaloneView;
36
37 /**
38 * Script Class for showing information about an item.
39 * @internal This class is a specific Backend controller implementation and is not considered part of the Public TYPO3 API.
40 */
41 class ElementInformationController
42 {
43 use PublicMethodDeprecationTrait;
44 use PublicPropertyDeprecationTrait;
45
46 /**
47 * @var array
48 */
49 private $deprecatedPublicMethods = [
50 'getLabelForTableColumn' => 'Using ElementInformationController::getLabelForTableColumn() is deprecated and will not be possible anymore in TYPO3 v10.0.',
51 ];
52
53 /**
54 * Properties which have been moved to protected status from public
55 *
56 * @var array
57 */
58 private $deprecatedPublicProperties = [
59 'table' => 'Using $table of class ElementInformationController from the outside is discouraged, as this variable is only used for internal storage.',
60 'uid' => 'Using $uid of class ElementInformationController from the outside is discouraged, as this variable is only used for internal storage.',
61 'access' => 'Using $access of class ElementInformationController from the outside is discouraged, as this variable is only used for internal storage.',
62 'type' => 'Using $type of class ElementInformationController from the outside is discouraged, as this variable is only used for internal storage.',
63 'pageInfo' => 'Using $pageInfo of class ElementInformationController from the outside is discouraged, as this variable is only used for internal storage.',
64 ];
65
66 /**
67 * Record table name
68 *
69 * @var string
70 */
71 protected $table;
72
73 /**
74 * Record uid
75 *
76 * @var int
77 */
78 protected $uid;
79
80 /**
81 * @var string
82 */
83 protected $permsClause;
84
85 /**
86 * @var bool
87 */
88 protected $access = false;
89
90 /**
91 * Which type of element:
92 * - "file"
93 * - "db"
94 *
95 * @var string
96 */
97 protected $type = '';
98
99 /**
100 * @var ModuleTemplate
101 */
102 protected $moduleTemplate;
103
104 /**
105 * For type "db": Set to page record of the parent page of the item set
106 * (if type="db")
107 *
108 * @var array
109 */
110 protected $pageInfo;
111
112 /**
113 * Database records identified by table/uid
114 *
115 * @var array
116 */
117 protected $row;
118
119 /**
120 * @var \TYPO3\CMS\Core\Resource\File
121 */
122 protected $fileObject;
123
124 /**
125 * @var Folder
126 */
127 protected $folderObject;
128
129 /**
130 * @var IconFactory
131 */
132 protected $iconFactory;
133
134 /**
135 * Constructor
136 */
137 public function __construct()
138 {
139 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
140 $GLOBALS['SOBE'] = $this;
141
142 // @deprecated since TYPO3 v9, will be obsolete in TYPO3 v10.0 with removal of init()
143 $request = $GLOBALS['TYPO3_REQUEST'];
144 // @deprecated since TYPO3 v9, will be moved out of __construct() in TYPO3 v10.0
145 $this->init($request);
146 }
147
148 /**
149 * Injects the request object for the current request or subrequest
150 * As this controller goes only through the main() method, it is rather simple for now
151 *
152 * @param ServerRequestInterface $request the current request
153 * @return ResponseInterface the response with the content
154 */
155 public function mainAction(ServerRequestInterface $request): ResponseInterface
156 {
157 $this->main($request);
158 return new HtmlResponse($this->moduleTemplate->renderContent());
159 }
160
161 /**
162 * Determines if table/uid point to database record or file and
163 * if user has access to view information
164 *
165 * @param ServerRequestInterface|null $request
166 */
167 public function init(ServerRequestInterface $request = null): void
168 {
169 if ($request === null) {
170 // Missing argument? This method must have been called from outside.
171 // Method will be protected and $request mandatory in TYPO3 v10.0, giving core freedom to move stuff around
172 // New v10 signature: "protected function init(ServerRequestInterface $request): void"
173 // @deprecated since TYPO3 v9, method argument $request will be set to mandatory
174 trigger_error('ElementInformationController->init() will be set to protected in TYPO3 v10.0. Do not call from other extension.', E_USER_DEPRECATED);
175 $request = $GLOBALS['TYPO3_REQUEST'];
176 }
177
178 $queryParams = $request->getQueryParams();
179
180 $this->table = $queryParams['table'] ?? null;
181 $this->uid = $queryParams['uid'] ?? null;
182
183 $this->permsClause = $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW);
184 $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
185 $this->moduleTemplate->getDocHeaderComponent()->disable();
186
187 if (isset($GLOBALS['TCA'][$this->table])) {
188 $this->initDatabaseRecord();
189 } elseif ($this->table === '_FILE' || $this->table === '_FOLDER' || $this->table === 'sys_file') {
190 $this->initFileOrFolderRecord();
191 }
192 }
193
194 /**
195 * Init database records (table)
196 */
197 protected function initDatabaseRecord()
198 {
199 $this->type = 'db';
200 $this->uid = (int)$this->uid;
201
202 // Check permissions and uid value:
203 if ($this->uid && $this->getBackendUser()->check('tables_select', $this->table)) {
204 if ((string)$this->table === 'pages') {
205 $this->pageInfo = BackendUtility::readPageAccess($this->uid, $this->permsClause);
206 $this->access = is_array($this->pageInfo);
207 $this->row = $this->pageInfo;
208 } else {
209 $this->row = BackendUtility::getRecordWSOL($this->table, $this->uid);
210 if ($this->row) {
211 $this->pageInfo = BackendUtility::readPageAccess($this->row['pid'], $this->permsClause);
212 $this->access = is_array($this->pageInfo);
213 }
214 }
215 }
216 }
217
218 /**
219 * Init file/folder parameters
220 */
221 protected function initFileOrFolderRecord()
222 {
223 $fileOrFolderObject = ResourceFactory::getInstance()->retrieveFileOrFolderObject($this->uid);
224
225 if ($fileOrFolderObject instanceof Folder) {
226 $this->folderObject = $fileOrFolderObject;
227 $this->access = $this->folderObject->checkActionPermission('read');
228 $this->type = 'folder';
229 } elseif ($fileOrFolderObject instanceof File) {
230 $this->fileObject = $fileOrFolderObject;
231 $this->access = $this->fileObject->checkActionPermission('read');
232 $this->type = 'file';
233 $this->table = 'sys_file';
234
235 try {
236 $this->row = BackendUtility::getRecordWSOL($this->table, $fileOrFolderObject->getUid());
237 } catch (\Exception $e) {
238 $this->row = [];
239 }
240 }
241 }
242
243 /**
244 * Compiles the whole content to be outputted, which is then set as content to the moduleTemplate
245 * There is a hook to do a custom rendering of a record.
246 *
247 * @param ServerRequestInterface $request
248 */
249 public function main(ServerRequestInterface $request = null): void
250 {
251 if ($request === null) {
252 // Missing argument? This method must have been called from outside.
253 // @deprecated since TYPO3 v9, method argument $request will be set to mandatory
254 trigger_error('ElementInformationController->main() will be set to protected in TYPO3 v10.0. Do not call from other extension.', E_USER_DEPRECATED);
255 $request = $GLOBALS['TYPO3_REQUEST'];
256 }
257
258 $content = '';
259
260 // Rendering of the output via fluid
261 $view = GeneralUtility::makeInstance(StandaloneView::class);
262 $view->setTemplateRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates')]);
263 $view->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Partials')]);
264 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName(
265 'EXT:backend/Resources/Private/Templates/ContentElement/ElementInformation.html'
266 ));
267
268 if ($this->access) {
269 // render type by user func
270 $typeRendered = false;
271 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/show_item.php']['typeRendering'] ?? [] as $className) {
272 $typeRenderObj = GeneralUtility::makeInstance($className);
273 if (is_object($typeRenderObj) && method_exists($typeRenderObj, 'isValid') && method_exists($typeRenderObj, 'render')) {
274 if ($typeRenderObj->isValid($this->type, $this)) {
275 $content .= $typeRenderObj->render($this->type, $this);
276 $typeRendered = true;
277 break;
278 }
279 }
280 }
281
282 if (!$typeRendered) {
283 $view->assign('accessAllowed', true);
284 $view->assignMultiple($this->getPageTitle());
285 $view->assignMultiple($this->getPreview());
286 $view->assignMultiple($this->getPropertiesForTable());
287 $view->assignMultiple($this->getReferences($request));
288 $view->assign('returnUrl', GeneralUtility::sanitizeLocalUrl($request->getQueryParams()['returnUrl']));
289 $view->assign('maxTitleLength', $this->getBackendUser()->uc['titleLen'] ?? 20);
290 $content .= $view->render();
291 }
292 } else {
293 $content .= $view->render();
294 }
295
296 $this->moduleTemplate->setContent($content);
297 }
298
299 /**
300 * Get page title with icon, table title and record title
301 *
302 * @return array
303 */
304 protected function getPageTitle(): array
305 {
306 $pageTitle = [
307 'title' => BackendUtility::getRecordTitle($this->table, $this->row, false)
308 ];
309 if ($this->type === 'folder') {
310 $pageTitle['table'] = $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:folder');
311 $pageTitle['icon'] = $this->iconFactory->getIconForResource($this->folderObject, Icon::SIZE_SMALL)->render();
312 } elseif ($this->type === 'file') {
313 $pageTitle['table'] = $this->getLanguageService()->sL($GLOBALS['TCA'][$this->table]['ctrl']['title']);
314 $pageTitle['icon'] = $this->iconFactory->getIconForResource($this->fileObject, Icon::SIZE_SMALL)->render();
315 } else {
316 $pageTitle['table'] = $this->getLanguageService()->sL($GLOBALS['TCA'][$this->table]['ctrl']['title']);
317 $pageTitle['icon'] = $this->iconFactory->getIconForRecord($this->table, $this->row, Icon::SIZE_SMALL);
318 }
319 $this->moduleTemplate->setTitle($pageTitle['table'] . ': ' . $pageTitle['title']);
320 return $pageTitle;
321 }
322
323 /**
324 * Get preview for current record
325 *
326 * @return array
327 */
328 protected function getPreview(): array
329 {
330 $preview = [];
331 // Perhaps @todo in future: Also display preview for records - without fileObject
332 if (!$this->fileObject) {
333 return $preview;
334 }
335
336 // check if file is marked as missing
337 if ($this->fileObject->isMissing()) {
338 $preview['missingFile'] = $this->fileObject->getName();
339 } else {
340 /** @var \TYPO3\CMS\Core\Resource\Rendering\RendererRegistry $rendererRegistry */
341 $rendererRegistry = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\Rendering\RendererRegistry::class);
342 $fileRenderer = $rendererRegistry->getRenderer($this->fileObject);
343 $fileExtension = $this->fileObject->getExtension();
344 $preview['url'] = $this->fileObject->getPublicUrl(true);
345
346 $width = '590m';
347 $heigth = '400m';
348
349 // Check if there is a FileRenderer
350 if ($fileRenderer !== null) {
351 $preview['fileRenderer'] = $fileRenderer->render(
352 $this->fileObject,
353 $width,
354 $heigth,
355 [],
356 true
357 );
358
359 // else check if we can create an Image preview
360 } elseif (GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileExtension)) {
361 $preview['fileObject'] = $this->fileObject;
362 $preview['width'] = $width;
363 $preview['heigth'] = $heigth;
364 }
365 }
366 return $preview;
367 }
368
369 /**
370 * Get property array for html table
371 *
372 * @return array
373 */
374 protected function getPropertiesForTable(): array
375 {
376 $propertiesForTable = [];
377 $lang = $this->getLanguageService();
378
379 $extraFields = [
380 'uid' => htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:show_item.php.uid'))
381 ];
382
383 if (in_array($this->type, ['folder', 'file'], true)) {
384 if ($this->type === 'file') {
385 $extraFields['creation_date'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.creationDate'));
386 $extraFields['modification_date'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.timestamp'));
387 if ($this->fileObject->getType() === AbstractFile::FILETYPE_IMAGE) {
388 $extraFields['width'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.width'));
389 $extraFields['height'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.height'));
390 }
391 }
392 $extraFields['storage'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_file.storage'));
393 $extraFields['folder'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:folder'));
394 } else {
395 $extraFields['crdate'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.creationDate'));
396 $extraFields['cruser_id'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.creationUserId'));
397 $extraFields['tstamp'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.timestamp'));
398
399 // check if the special fields are defined in the TCA ctrl section of the table
400 foreach ($extraFields as $fieldName => $fieldLabel) {
401 if (isset($GLOBALS['TCA'][$this->table]['ctrl'][$fieldName])) {
402 $extraFields[$GLOBALS['TCA'][$this->table]['ctrl'][$fieldName]] = $fieldLabel;
403 } elseif ($fieldName !== 'uid') {
404 unset($extraFields[$fieldName]);
405 }
406 }
407 }
408
409 foreach ($extraFields as $name => $fieldLabel) {
410 $rowValue = '';
411 $thisRow = [];
412 if (!isset($this->row[$name])) {
413 $resourceObject = $this->fileObject ?: $this->folderObject;
414 if ($name === 'storage') {
415 $rowValue = $resourceObject->getStorage()->getName();
416 } elseif ($name === 'folder') {
417 $rowValue = $resourceObject->getParentFolder()->getReadablePath();
418 } elseif ($name === 'width') {
419 $rowValue = $this->fileObject->getProperty('width') . 'px';
420 } elseif ($name === 'height') {
421 $rowValue = $this->fileObject->getProperty('height') . 'px';
422 }
423 } elseif ($name === 'creation_date' || $name === 'modification_date' || $name === 'tstamp' || $name === 'crdate') {
424 $rowValue = BackendUtility::datetime($this->row[$name]);
425 } else {
426 $rowValue = BackendUtility::getProcessedValueExtra($this->table, $name, $this->row[$name]);
427 }
428 $thisRow['value'] = $rowValue;
429 $thisRow['fieldLabel'] = rtrim($fieldLabel, ':');
430 // show the backend username who created the issue
431 if ($name === 'cruser_id' && $rowValue) {
432 $creatorRecord = BackendUtility::getRecord('be_users', $rowValue);
433 if ($creatorRecord) {
434 /** @var Avatar $avatar */
435 $avatar = GeneralUtility::makeInstance(Avatar::class);
436 $creatorRecord['icon'] = $avatar->render($creatorRecord);
437 $thisRow['creatorRecord'] = $creatorRecord;
438 $thisRow['value'] = '';
439 }
440 }
441 $propertiesForTable['extraFields'][] = $thisRow;
442 }
443
444 // Traverse the list of fields to display for the record:
445 $fieldList = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$this->table]['interface']['showRecordFieldList'], true);
446 foreach ($fieldList as $name) {
447 $thisRow = [];
448 $name = trim($name);
449 $uid = $this->row['uid'];
450
451 if (!isset($GLOBALS['TCA'][$this->table]['columns'][$name])) {
452 continue;
453 }
454
455 // Storage is already handled above
456 if ($this->type === 'file' && $name === 'storage') {
457 continue;
458 }
459
460 // format file size as bytes/kilobytes/megabytes
461 if ($this->type === 'file' && $name === 'size') {
462 $this->row[$name] = GeneralUtility::formatSize($this->row[$name], htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:byteSizeUnits')));
463 }
464
465 $isExcluded = !(!$GLOBALS['TCA'][$this->table]['columns'][$name]['exclude'] || $this->getBackendUser()->check('non_exclude_fields', $this->table . ':' . $name));
466 if ($isExcluded) {
467 continue;
468 }
469
470 $thisRow['fieldValue'] = BackendUtility::getProcessedValue($this->table, $name, $this->row[$name], 0, 0, false, $uid);
471 $thisRow['fieldLabel'] = htmlspecialchars($lang->sL(BackendUtility::getItemLabel($this->table, $name)));
472 $propertiesForTable['fields'][] = $thisRow;
473 }
474 return $propertiesForTable;
475 }
476
477 /**
478 * Get references section (references from and references to current record)
479 *
480 * @param ServerRequestInterface $request
481 * @return array
482 */
483 protected function getReferences(ServerRequestInterface $request): array
484 {
485 $references = [];
486 switch ($this->type) {
487 case 'db': {
488 $references['refLines'] = $this->makeRef($this->table, $this->row['uid'], $request);
489 $references['refFromLines'] = $this->makeRefFrom($this->table, $this->row['uid'], $request);
490 break;
491 }
492
493 case 'file': {
494 if ($this->fileObject && $this->fileObject->isIndexed()) {
495 $references['refLines'] = $this->makeRef('_FILE', $this->fileObject, $request);
496 }
497 break;
498 }
499 }
500 return $references;
501 }
502
503 /**
504 * Get field name for specified table/column name
505 *
506 * @param string $tableName Table name
507 * @param string $fieldName Column name
508 * @return string label
509 */
510 protected function getLabelForTableColumn($tableName, $fieldName)
511 {
512 if ($GLOBALS['TCA'][$tableName]['columns'][$fieldName]['label'] !== null) {
513 $field = $this->getLanguageService()->sL($GLOBALS['TCA'][$tableName]['columns'][$fieldName]['label']);
514 if (trim($field) === '') {
515 $field = $fieldName;
516 }
517 } else {
518 $field = $fieldName;
519 }
520 return $field;
521 }
522
523 /**
524 * Returns the record actions
525 *
526 * @param string $table
527 * @param int $uid
528 * @param ServerRequestInterface $request
529 * @return array
530 */
531 protected function getRecordActions($table, $uid, ServerRequestInterface $request): array
532 {
533 if ($table === '' || $uid < 0) {
534 return [];
535 }
536
537 $actions = [];
538 // Edit button
539 $urlParameters = [
540 'edit' => [
541 $table => [
542 $uid => 'edit'
543 ]
544 ],
545 'returnUrl' => $request->getAttribute('normalizedParams')->getRequestUri()
546 ];
547 /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
548 $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
549 $actions['recordEditUrl'] = (string)$uriBuilder->buildUriFromRoute('record_edit', $urlParameters);
550
551 // History button
552 $urlParameters = [
553 'element' => $table . ':' . $uid,
554 'returnUrl' => $request->getAttribute('normalizedParams')->getRequestUri()
555 ];
556 $actions['recordHistoryUrl'] = (string)$uriBuilder->buildUriFromRoute('record_history', $urlParameters);
557
558 if ($table === 'pages') {
559 // Recordlist button
560 $actions['webListUrl'] = (string)$uriBuilder->buildUriFromRoute('web_list', ['id' => $uid, 'returnUrl' => $request->getAttribute('normalizedParams')->getRequestUri()]);
561
562 // View page button
563 $actions['viewOnClick'] = BackendUtility::viewOnClick($uid, '', BackendUtility::BEgetRootLine($uid));
564 }
565
566 return $actions;
567 }
568
569 /**
570 * Make reference display
571 *
572 * @param string $table Table name
573 * @param string|\TYPO3\CMS\Core\Resource\File $ref Filename or uid
574 * @param ServerRequestInterface $request
575 * @return array
576 */
577 protected function makeRef($table, $ref, ServerRequestInterface $request)
578 {
579 $refLines = [];
580 $lang = $this->getLanguageService();
581 // Files reside in sys_file table
582 if ($table === '_FILE') {
583 $selectTable = 'sys_file';
584 $selectUid = $ref->getUid();
585 } else {
586 $selectTable = $table;
587 $selectUid = $ref;
588 }
589 /** @var \TYPO3\CMS\Core\Database\Query\QueryBuilder $queryBuilder */
590 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
591 ->getQueryBuilderForTable('sys_refindex');
592 $rows = $queryBuilder
593 ->select('*')
594 ->from('sys_refindex')
595 ->where(
596 $queryBuilder->expr()->eq(
597 'ref_table',
598 $queryBuilder->createNamedParameter($selectTable, \PDO::PARAM_STR)
599 ),
600 $queryBuilder->expr()->eq(
601 'ref_uid',
602 $queryBuilder->createNamedParameter($selectUid, \PDO::PARAM_INT)
603 ),
604 $queryBuilder->expr()->eq(
605 'deleted',
606 $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
607 )
608 )
609 ->execute()
610 ->fetchAll();
611
612 // Compile information for title tag:
613 foreach ($rows as $row) {
614 if ($row['tablename'] === 'sys_file_reference') {
615 $row = $this->transformFileReferenceToRecordReference($row);
616 if ($row['tablename'] === null || $row['recuid'] === null) {
617 return;
618 }
619 }
620 $line = [];
621 $record = BackendUtility::getRecord($row['tablename'], $row['recuid']);
622 if ($record) {
623 $parentRecord = BackendUtility::getRecord('pages', $record['pid']);
624 $parentRecordTitle = is_array($parentRecord)
625 ? BackendUtility::getRecordTitle('pages', $parentRecord)
626 : '';
627 $urlParameters = [
628 'edit' => [
629 $row['tablename'] => [
630 $row['recuid'] => 'edit'
631 ]
632 ],
633 'returnUrl' => $request->getAttribute('normalizedParams')->getRequestUri()
634 ];
635 /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
636 $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
637 $url = (string)$uriBuilder->buildUriFromRoute('record_edit', $urlParameters);
638 $line['url'] = $url;
639 $line['icon'] = $this->iconFactory->getIconForRecord($row['tablename'], $record, Icon::SIZE_SMALL)->render();
640 $line['row'] = $row;
641 $line['record'] = $record;
642 $line['recordTitle'] = BackendUtility::getRecordTitle($row['tablename'], $record, false, true);
643 $line['parentRecordTitle'] = $parentRecordTitle;
644 $line['title'] = $lang->sL($GLOBALS['TCA'][$row['tablename']]['ctrl']['title']);
645 $line['labelForTableColumn'] = $this->getLabelForTableColumn($row['tablename'], $row['field']);
646 $line['path'] = BackendUtility::getRecordPath($record['pid'], '', 0, 0);
647 $line['actions'] = $this->getRecordActions($row['tablename'], $row['recuid'], $request);
648 } else {
649 $line['row'] = $row;
650 $line['title'] = $lang->sL($GLOBALS['TCA'][$row['tablename']]['ctrl']['title']) ?: $row['tablename'];
651 $line['labelForTableColumn'] = $this->getLabelForTableColumn($row['tablename'], $row['field']);
652 }
653 $refLines[] = $line;
654 }
655 return $refLines;
656 }
657
658 /**
659 * Make reference display (what this elements points to)
660 *
661 * @param string $table Table name
662 * @param string $ref Filename or uid
663 * @param ServerRequestInterface $request
664 * @return array
665 */
666 protected function makeRefFrom($table, $ref, ServerRequestInterface $request): array
667 {
668 $refFromLines = [];
669 $lang = $this->getLanguageService();
670
671 /** @var \TYPO3\CMS\Core\Database\Query\QueryBuilder $queryBuilder */
672 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
673 ->getQueryBuilderForTable('sys_refindex');
674 $rows = $queryBuilder
675 ->select('*')
676 ->from('sys_refindex')
677 ->where(
678 $queryBuilder->expr()->eq(
679 'tablename',
680 $queryBuilder->createNamedParameter($table, \PDO::PARAM_STR)
681 ),
682 $queryBuilder->expr()->eq(
683 'recuid',
684 $queryBuilder->createNamedParameter($ref, \PDO::PARAM_INT)
685 )
686 )
687 ->execute()
688 ->fetchAll();
689
690 // Compile information for title tag:
691 foreach ($rows as $row) {
692 $line = [];
693 $record = BackendUtility::getRecord($row['ref_table'], $row['ref_uid']);
694 if ($record) {
695 $urlParameters = [
696 'edit' => [
697 $row['ref_table'] => [
698 $row['ref_uid'] => 'edit'
699 ]
700 ],
701 'returnUrl' => $request->getAttribute('normalizedParams')->getRequestUri()
702 ];
703 /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
704 $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
705 $url = (string)$uriBuilder->buildUriFromRoute('record_edit', $urlParameters);
706 $line['url'] = $url;
707 $line['icon'] = $this->iconFactory->getIconForRecord($row['tablename'], $record, Icon::SIZE_SMALL)->render();
708 $line['row'] = $row;
709 $line['record'] = $record;
710 $line['recordTitle'] = BackendUtility::getRecordTitle($row['ref_table'], $record, false, true);
711 $line['title'] = $lang->sL($GLOBALS['TCA'][$row['ref_table']]['ctrl']['title']);
712 $line['labelForTableColumn'] = $this->getLabelForTableColumn($table, $row['field']);
713 $line['path'] = BackendUtility::getRecordPath($record['pid'], '', 0, 0);
714 $line['actions'] = $this->getRecordActions($row['ref_table'], $row['ref_uid'], $request);
715 } else {
716 $line['row'] = $row;
717 $line['title'] = $lang->sL($GLOBALS['TCA'][$row['ref_table']]['ctrl']['title']);
718 $line['labelForTableColumn'] = $this->getLabelForTableColumn($table, $row['field']);
719 }
720 $refFromLines[] = $line;
721 }
722 return $refFromLines;
723 }
724
725 /**
726 * Convert FAL file reference (sys_file_reference) to reference index (sys_refindex) table format
727 *
728 * @param array $referenceRecord
729 * @return array
730 */
731 protected function transformFileReferenceToRecordReference(array $referenceRecord)
732 {
733 /** @var \TYPO3\CMS\Core\Database\Query\QueryBuilder $queryBuilder */
734 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
735 ->getQueryBuilderForTable('sys_file_reference');
736 $queryBuilder->getRestrictions()->removeAll();
737 $fileReference = $queryBuilder
738 ->select('*')
739 ->from('sys_file_reference')
740 ->where(
741 $queryBuilder->expr()->eq(
742 'uid',
743 $queryBuilder->createNamedParameter($referenceRecord['recuid'], \PDO::PARAM_INT)
744 )
745 )
746 ->execute()
747 ->fetch();
748
749 return [
750 'recuid' => $fileReference['uid_foreign'],
751 'tablename' => $fileReference['tablenames'],
752 'field' => $fileReference['fieldname'],
753 'flexpointer' => '',
754 'softref_key' => '',
755 'sorting' => $fileReference['sorting_foreign']
756 ];
757 }
758
759 /**
760 * Returns LanguageService
761 *
762 * @return \TYPO3\CMS\Core\Localization\LanguageService
763 */
764 protected function getLanguageService()
765 {
766 return $GLOBALS['LANG'];
767 }
768
769 /**
770 * Returns the current BE user.
771 *
772 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
773 */
774 protected function getBackendUser()
775 {
776 return $GLOBALS['BE_USER'];
777 }
778 }