‪TYPO3CMS  ‪main
RecordLinkHandler.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
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 
19 
20 use Psr\Http\Message\ServerRequestInterface;
21 use TYPO3\CMS\Backend\Controller\AbstractLinkBrowserController;
24 use TYPO3\CMS\Backend\Utility\BackendUtility;
26 use TYPO3\CMS\Core\Imaging\IconSize;
31 
58 {
62  protected string ‪$identifier;
63 
67  protected array ‪$configuration = [];
68 
72  protected array ‪$linkParts = [];
73 
74  protected int ‪$expandPage = 0;
75 
76  public function ‪__construct(
77  private readonly ‪ElementBrowserRecordList $elementBrowserRecordList,
78  private readonly ‪RecordSearchBoxComponent $recordSearchBoxComponent,
79  private readonly ‪LinkService $linkService,
80  ) {
81  parent::__construct();
82  }
83 
84  public function ‪initialize(AbstractLinkBrowserController ‪$linkBrowser, ‪$identifier, array ‪$configuration)
85  {
86  parent::initialize(‪$linkBrowser, ‪$identifier, ‪$configuration);
87  $this->identifier = ‪$identifier;
88  if (empty(‪$configuration['table'])) {
89  throw new \LogicException(
90  'Page TSconfig TCEMAIN.linkHandler.' . ‪$identifier . '.configuration.table is mandatory and must be set to a table name.',
91  1657960610
92  );
93  }
94  $this->configuration = ‪$configuration;
95  }
96 
103  public function ‪canHandleLink(array ‪$linkParts): bool
104  {
105  if (!‪$linkParts['url'] || !isset(‪$linkParts['url']['identifier']) || ‪$linkParts['url']['identifier'] !== $this->identifier) {
106  return false;
107  }
108 
109  $data = ‪$linkParts['url'];
110 
111  // Get the related record
112  $table = $this->configuration['table'];
113  ‪$record = BackendUtility::getRecord($table, $data['uid']);
114  if (‪$record === null) {
115  ‪$linkParts['title'] = $this->‪getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_browse_links.xlf:recordNotFound');
116  } else {
117  $linkParts['pid'] = (int)‪$record['pid'];
118  ‪$linkParts['title'] = !empty(‪$linkParts['title']) ? ‪$linkParts['title'] : BackendUtility::getRecordTitle($table, ‪$record);
119  }
120  ‪$linkParts['tableName'] = $this->‪getLanguageService()->sL(‪$GLOBALS['TCA'][$table]['ctrl']['title']);
121  ‪$linkParts['url']['type'] = ‪$linkParts['type'];
122  $this->linkParts = ‪$linkParts;
123 
124  return true;
125  }
126 
130  public function ‪formatCurrentUrl(): string
131  {
132  return sprintf(
133  '%s: %s [uid: %d]',
134  $this->linkParts['tableName'],
135  $this->linkParts['title'],
136  $this->linkParts['url']['uid']
137  );
138  }
139 
143  public function ‪render(ServerRequestInterface $request): string
144  {
145  $this->pageRenderer->loadJavaScriptModule('@typo3/backend/record-link-handler.js');
146  $this->pageRenderer->loadJavaScriptModule('@typo3/backend/record-search.js');
147  $this->pageRenderer->loadJavaScriptModule('@typo3/backend/viewport/resizable-navigation.js');
148  $this->pageRenderer->loadJavaScriptModule('@typo3/backend/column-selector-button.js');
149  $this->pageRenderer->loadJavaScriptModule('@typo3/backend/tree/page-browser.js');
150  $this->‪getBackendUser()->initializeWebmountsForElementBrowser();
151 
152  // Define the current page
153  if (isset($request->getQueryParams()['expandPage'])) {
154  $this->expandPage = (int)$request->getQueryParams()['expandPage'];
155  } elseif (isset($this->configuration['storagePid'])) {
156  $this->expandPage = (int)$this->configuration['storagePid'];
157  } elseif (isset($this->linkParts['pid'])) {
158  $this->expandPage = (int)$this->linkParts['pid'];
159  }
160 
161  $pageTreeMountPoints = (string)($this->configuration['pageTreeMountPoints'] ?? '');
162  $this->view->assignMultiple([
163  'treeEnabled' => (bool)($this->configuration['hidePageTree'] ?? false) === false,
164  'pageTreeMountPoints' => ‪GeneralUtility::intExplode(',', $pageTreeMountPoints, true),
165  'recordList' => $this->‪renderTableRecords($request),
166  'initialNavigationWidth' => $this->‪getBackendUser()->uc['selector']['navigation']['width'] ?? 250,
167  'treeActions' => ['link'],
168  ]);
169 
170  return $this->view->render('LinkBrowser/Record');
171  }
172 
178  public function ‪getBodyTagAttributes(): array
179  {
180  $attributes = [
181  'data-linkbrowser-identifier' => 't3://record?identifier=' . $this->identifier . '&uid=',
182  ];
183  if (!empty($this->linkParts)) {
184  $attributes['data-linkbrowser-current-link'] = $this->linkService->asString($this->linkParts['url']);
185  }
186  return $attributes;
187  }
188 
195  public function ‪getUrlParameters(array $values): array
196  {
197  $pid = isset($values['pid']) ? (int)$values['pid'] : $this->expandPage;
198  $parameters = [
199  'expandPage' => $pid,
200  ];
201 
202  return array_merge(
203  $this->linkBrowser->getUrlParameters($values),
204  ['P' => $this->linkBrowser->getParameters()],
205  $parameters
206  );
207  }
208 
212  protected function ‪renderTableRecords(ServerRequestInterface $request): string
213  {
214  $html = [];
215  $backendUser = $this->‪getBackendUser();
216  $selectedPage = ‪$this->expandPage;
217  if ($selectedPage < 0 || !$backendUser->isInWebMount($selectedPage)) {
218  return '';
219  }
220  $table = $this->configuration['table'];
221  $permsClause = $backendUser->getPagePermsClause(‪Permission::PAGE_SHOW);
222  $pageInfo = BackendUtility::readPageAccess($selectedPage, $permsClause);
223  $selectedTable = (string)($request->getParsedBody()['table'] ?? $request->getQueryParams()['table'] ?? '');
224  $searchWord = (string)($request->getParsedBody()['searchTerm'] ?? $request->getQueryParams()['searchTerm'] ?? '');
225  $pointer = (int)($request->getParsedBody()['pointer'] ?? $request->getQueryParams()['pointer'] ?? 0);
226 
227  // If table is 'pages', add a pre-entry to make selected page selectable directly.
228  $titleLen = (int)$backendUser->uc['titleLen'];
229  $mainPageRecord = BackendUtility::getRecordWSOL('pages', $selectedPage);
230  if (is_array($mainPageRecord)) {
231  $pText = htmlspecialchars(‪GeneralUtility::fixed_lgd_cs($mainPageRecord['title'], $titleLen));
232  $html[] = '<p>' . $this->iconFactory->getIconForRecord('pages', $mainPageRecord, IconSize::SMALL)->render() . '&nbsp;';
233  if ($table === 'pages') {
234  $html[] = '<span data-uid="' . htmlspecialchars((string)$mainPageRecord['uid']) . '" data-table="pages" data-title="' . htmlspecialchars($mainPageRecord['title']) . '">';
235  $html[] = '<a href="#" data-close="0">' . $this->iconFactory->getIcon('actions-plus', IconSize::SMALL)->render() . '</a>';
236  $html[] = '<a href="#" data-close="1">' . $pText . '</a>';
237  $html[] = '</span>';
238  } else {
239  $html[] = $pText;
240  }
241  $html[] = '</p>';
242  }
243 
244  $dbList = $this->elementBrowserRecordList;
245  $dbList->setRequest($request);
246  $dbList->setOverrideUrlParameters(array_merge($this->‪getUrlParameters([]), ['mode' => 'db', 'expandPage' => $selectedPage]), $request);
247  $dbList->setIsEditable(false);
248  $dbList->calcPerms = new ‪Permission($backendUser->calcPerms($pageInfo));
249  $dbList->noControlPanels = true;
250  $dbList->clickMenuEnabled = false;
251  $dbList->displayRecordDownload = false;
252  $dbList->tableList = $table;
253  $dbList->start($selectedPage, $selectedTable, ‪MathUtility::forceIntegerInRange($pointer, 0, 100000), $searchWord);
254 
255  $html[] = $this->recordSearchBoxComponent
256  ->setSearchWord($searchWord)
257  ->render($request, $dbList->listURL('', '-1', 'pointer,searchTerm'));
258  $html[] = $dbList->generateList();
259 
260  return implode("\n", $html);
261  }
262 }
‪TYPO3\CMS\Core\Utility\GeneralUtility\fixed_lgd_cs
‪static string fixed_lgd_cs(string $string, int $chars, string $appendString='...')
Definition: GeneralUtility.php:92
‪TYPO3\CMS\Backend\RecordList\ElementBrowserRecordList
Definition: ElementBrowserRecordList.php:27
‪TYPO3\CMS\Core\Type\Bitmask\Permission
Definition: Permission.php:26
‪TYPO3\CMS\Webhooks\Message\$record
‪identifier readonly int readonly array $record
Definition: PageModificationMessage.php:36
‪TYPO3\CMS\Core\Type\Bitmask\Permission\PAGE_SHOW
‪const PAGE_SHOW
Definition: Permission.php:35
‪TYPO3\CMS\Backend\View\RecordSearchBoxComponent
Definition: RecordSearchBoxComponent.php:28
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:24
‪TYPO3\CMS\Core\Utility\MathUtility\forceIntegerInRange
‪static int forceIntegerInRange(mixed $theInt, int $min, int $max=2000000000, int $defaultValue=0)
Definition: MathUtility.php:34
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Utility\GeneralUtility\intExplode
‪static list< int > intExplode(string $delimiter, string $string, bool $removeEmptyValues=false)
Definition: GeneralUtility.php:756