‪TYPO3CMS  10.4
AbstractLinkBrowserController.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
18 use Psr\Http\Message\ResponseInterface;
19 use Psr\Http\Message\ServerRequestInterface;
30 
36 {
40  protected ‪$moduleTemplate;
41 
45  protected ‪$parameters;
46 
52  protected ‪$thisScript = '';
53 
57  protected ‪$linkHandlers = [];
58 
66  protected ‪$currentLinkParts = [];
67 
74 
80  protected ‪$currentLinkHandlerId;
81 
88 
96  protected ‪$displayedLinkHandlerId = '';
97 
103  protected ‪$linkAttributeFields = [];
104 
110  protected ‪$linkAttributeValues = [];
111 
115  protected ‪$hookObjects = [];
116 
120  public function ‪__construct()
121  {
122  $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
123  $this->moduleTemplate->getDocHeaderComponent()->disable();
124  $this->moduleTemplate->getView()->setTemplate('LinkBrowser');
125  $this->‪initHookObjects();
126  $this->‪init();
127  }
128 
132  protected function ‪init()
133  {
134  $this->‪getLanguageService()->‪includeLLFile('EXT:recordlist/Resources/Private/Language/locallang_browse_links.xlf');
135  }
136 
142  protected function ‪initHookObjects()
143  {
144  $hooks = GeneralUtility::makeInstance(DependencyOrderingService::class)->orderByDependencies(
145  ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['LinkBrowser']['hooks'] ?? []
146  );
147  foreach ($hooks as $key => $hook) {
148  $this->hookObjects[] = GeneralUtility::makeInstance($hook['handler']);
149  }
150  }
151 
159  public function ‪mainAction(ServerRequestInterface $request): ResponseInterface
160  {
161  $this->‪determineScriptUrl($request);
162  $this->‪initVariables($request);
163  $this->‪loadLinkHandlers();
164  $this->‪initCurrentUrl();
165 
166  $menuData = $this->‪buildMenuArray();
167  $renderLinkAttributeFields = $this->‪renderLinkAttributeFields();
168  $browserContent = $this->displayedLinkHandler->render($request);
169 
170  $this->‪initDocumentTemplate();
171  $view = $this->moduleTemplate->getView();
172  $this->moduleTemplate->setTitle('Link Browser');
173 
174  if (!empty($this->currentLinkParts)) {
175  $this->‪renderCurrentUrl();
176  }
177 
178  $view->assign('menuItems', $menuData);
179  $view->assign('linkAttributes', $renderLinkAttributeFields);
180  $view->assign('content', $browserContent);
181 
182  return new ‪HtmlResponse($this->moduleTemplate->renderContent());
183  }
184 
193  protected function ‪determineScriptUrl(ServerRequestInterface $request)
194  {
195  if ($routePath = $request->getQueryParams()['route']) {
196  $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
197  $this->thisScript = (string)$uriBuilder->buildUriFromRoutePath($routePath);
198  } else {
199  $this->thisScript = GeneralUtility::getIndpEnv('SCRIPT_NAME');
200  }
201  }
202 
206  protected function ‪initVariables(ServerRequestInterface $request)
207  {
208  $queryParams = $request->getQueryParams();
209  $this->displayedLinkHandlerId = $queryParams['act'] ?? '';
210  $this->parameters = $queryParams['P'] ?? [];
211  $this->linkAttributeValues = $queryParams['linkAttributes'] ?? [];
212  }
213 
217  protected function ‪loadLinkHandlers()
218  {
219  ‪$linkHandlers = $this->getLinkHandlers();
220  if (empty(‪$linkHandlers)) {
221  throw new \UnexpectedValueException('No link handlers are configured. Check page TSconfig TCEMAIN.linkHandler.', 1442787911);
222  }
223 
224  $lang = $this->‪getLanguageService();
225  foreach ($linkHandlers as $identifier => $configuration) {
226  $identifier = rtrim($identifier, '.');
227 
228  if (empty($configuration['handler'])) {
229  throw new \UnexpectedValueException(sprintf('Missing handler for link handler "%1$s", check page TSconfig TCEMAIN.linkHandler.%1$s.handler', $identifier), 1494579849);
230  }
231 
233  $handler = GeneralUtility::makeInstance($configuration['handler']);
234  $handler->initialize(
235  $this,
236  $identifier,
237  $configuration['configuration.'] ?? []
238  );
239 
240  $label = !empty($configuration['label']) ? $lang->sL($configuration['label']) : '';
241  $label = $label ?: $lang->sL('LLL:EXT:recordlist/Resources/Private/Language/locallang.xlf:error.linkHandlerTitleMissing');
242  $this->linkHandlers[$identifier] = [
243  'handlerInstance' => $handler,
244  'label' => htmlspecialchars($label),
245  'displayBefore' => isset($configuration['displayBefore']) ? ‪GeneralUtility::trimExplode(',', $configuration['displayBefore']) : [],
246  'displayAfter' => isset($configuration['displayAfter']) ? GeneralUtility::trimExplode(',', $configuration['displayAfter']) : [],
247  'scanBefore' => isset($configuration['scanBefore']) ? GeneralUtility::trimExplode(',', $configuration['scanBefore']) : [],
248  'scanAfter' => isset($configuration['scanAfter']) ? GeneralUtility::trimExplode(',', $configuration['scanAfter']) : [],
249  'addParams' => $configuration['addParams'] ?? '',
250  ];
251  }
252  }
253 
259  protected function getLinkHandlers()
260  {
261  ‪$linkHandlers = (array)(‪BackendUtility::getPagesTSconfig($this->‪getCurrentPageId())['TCEMAIN.']['linkHandler.'] ?? []);
262  foreach ($this->hookObjects as $hookObject) {
263  if (method_exists($hookObject, 'modifyLinkHandlers')) {
264  ‪$linkHandlers = $hookObject->modifyLinkHandlers(‪$linkHandlers, $this->currentLinkParts);
265  }
266  }
267 
268  return ‪$linkHandlers;
269  }
270 
274  protected function ‪initCurrentUrl()
275  {
276  if (empty($this->currentLinkParts)) {
277  return;
278  }
279 
280  $orderedHandlers = GeneralUtility::makeInstance(DependencyOrderingService::class)->orderByDependencies($this->linkHandlers, 'scanBefore', 'scanAfter');
281 
282  // find responsible handler for current link
283  foreach ($orderedHandlers as $key => $configuration) {
285  $handler = $configuration['handlerInstance'];
286  if ($handler->canHandleLink($this->currentLinkParts)) {
287  $this->currentLinkHandler = $handler;
288  $this->currentLinkHandlerId = $key;
289  break;
290  }
291  }
292  // reset the link if we have no handler for it
293  if (!$this->currentLinkHandler) {
294  $this->currentLinkParts = [];
295  }
296 
297  // overwrite any preexisting
298  foreach ($this->currentLinkParts as $key => $part) {
299  if ($key !== 'url') {
300  $this->linkAttributeValues[$key] = $part;
301  }
302  }
303  }
304 
308  protected function ‪initDocumentTemplate()
309  {
310  $bodyTag = $this->moduleTemplate->getBodyTag();
311  $bodyTag = str_replace('>', ' ' . GeneralUtility::implodeAttributes($this->‪getBodyTagAttributes(), true, true) . '>', $bodyTag);
312  $this->moduleTemplate->setBodyTag($bodyTag);
313  }
314 
318  protected function ‪renderCurrentUrl()
319  {
320  $this->moduleTemplate->getView()->assign('currentUrl', $this->currentLinkHandler->formatCurrentUrl());
321  }
322 
328  protected function ‪buildMenuArray()
329  {
330  $allowedItems = $this->‪getAllowedItems();
331  if ($this->displayedLinkHandlerId && !in_array($this->displayedLinkHandlerId, $allowedItems, true)) {
332  $this->displayedLinkHandlerId = '';
333  }
334 
335  $allowedHandlers = array_flip($allowedItems);
336  $menuDef = [];
337  foreach ($this->linkHandlers as $identifier => $configuration) {
338  if (!isset($allowedHandlers[$identifier])) {
339  continue;
340  }
341 
343  $handlerInstance = $configuration['handlerInstance'];
344  $isActive = $this->displayedLinkHandlerId === $identifier || !$this->displayedLinkHandlerId && $handlerInstance === ‪$this->currentLinkHandler;
345  if ($isActive) {
346  $this->displayedLinkHandler = $handlerInstance;
347  if (!$this->displayedLinkHandlerId) {
348  $this->displayedLinkHandlerId = ‪$this->currentLinkHandlerId;
349  }
350  }
351 
352  $menuDef[$identifier] = [
353  'isActive' => $isActive,
354  'label' => $configuration['label'],
355  'url' => $this->thisScript . ‪HttpUtility::buildQueryString($this->‪getUrlParameters(['act' => $identifier]), '&'),
356  'addParams' => $configuration['addParams'] ?? '',
357  'before' => $configuration['displayBefore'],
358  'after' => $configuration['displayAfter']
359  ];
360  }
361 
362  $menuDef = GeneralUtility::makeInstance(DependencyOrderingService::class)->orderByDependencies($menuDef);
363 
364  // if there is no active tab
365  if (!$this->displayedLinkHandler) {
366  // empty the current link
367  $this->currentLinkParts = [];
368  $this->currentLinkHandler = null;
369  $this->currentLinkHandler = '';
370  // select first tab
371  reset($menuDef);
372  $this->displayedLinkHandlerId = key($menuDef);
373  $this->displayedLinkHandler = $this->linkHandlers[‪$this->displayedLinkHandlerId]['handlerInstance'];
374  $menuDef[‪$this->displayedLinkHandlerId]['isActive'] = true;
375  }
376 
377  return $menuDef;
378  }
379 
385  protected function ‪getAllowedItems()
386  {
387  $allowedItems = array_keys($this->linkHandlers);
388 
389  foreach ($this->hookObjects as $hookObject) {
390  if (method_exists($hookObject, 'modifyAllowedItems')) {
391  $allowedItems = $hookObject->modifyAllowedItems($allowedItems, $this->currentLinkParts);
392  }
393  }
394 
395  // Initializing the action value, possibly removing blinded values etc:
396  $blindLinkOptions = isset($this->parameters['params']['blindLinkOptions'])
397  ? ‪GeneralUtility::trimExplode(',', $this->parameters['params']['blindLinkOptions'])
398  : [];
399  $allowedItems = array_diff($allowedItems, $blindLinkOptions);
400 
401  return $allowedItems;
402  }
403 
409  protected function ‪getAllowedLinkAttributes()
410  {
411  $allowedLinkAttributes = $this->displayedLinkHandler->getLinkAttributes();
412 
413  // Removing link fields if configured
414  $blindLinkFields = isset($this->parameters['params']['blindLinkFields'])
415  ? ‪GeneralUtility::trimExplode(',', $this->parameters['params']['blindLinkFields'], true)
416  : [];
417  $allowedLinkAttributes = array_diff($allowedLinkAttributes, $blindLinkFields);
418 
419  return $allowedLinkAttributes;
420  }
421 
427  protected function ‪renderLinkAttributeFields()
428  {
429  $fieldRenderingDefinitions = $this->‪getLinkAttributeFieldDefinitions();
430 
431  $fieldRenderingDefinitions = $this->displayedLinkHandler->modifyLinkAttributes($fieldRenderingDefinitions);
432 
433  $this->linkAttributeFields = $this->‪getAllowedLinkAttributes();
434 
435  $content = '';
436  foreach ($this->linkAttributeFields as $attribute) {
437  $content .= $fieldRenderingDefinitions[$attribute];
438  }
439 
440  // add update button if appropriate
441  if (!empty($this->currentLinkParts) && $this->displayedLinkHandler === $this->currentLinkHandler && $this->currentLinkHandler->isUpdateSupported()) {
442  $this->moduleTemplate->getView()->assign('showUpdateParametersButton', true);
443  }
444  return $content;
445  }
446 
452  protected function ‪getLinkAttributeFieldDefinitions()
453  {
454  $lang = $this->‪getLanguageService();
455 
456  $fieldRenderingDefinitions = [];
457  $fieldRenderingDefinitions['target'] = '
458  <!-- Selecting target for link: -->
459  <form action="" name="ltargetform" id="ltargetform" class="t3js-dummyform form-horizontal">
460  <div class="form-group form-group-sm" id="typo3-linkTarget">
461  <label class="col-xs-4 control-label">' . htmlspecialchars($lang->getLL('target')) . '</label>
462  <div class="col-xs-3">
463  <input type="text" name="ltarget" class="t3js-linkTarget form-control"
464  value="' . htmlspecialchars($this->linkAttributeValues['target']) . '" />
465  </div>
466  <div class="col-xs-5">
467  <select name="ltarget_type" class="t3js-targetPreselect form-control">
468  <option value=""></option>
469  <option value="_top">' . htmlspecialchars($lang->getLL('top')) . '</option>
470  <option value="_blank">' . htmlspecialchars($lang->getLL('newWindow')) . '</option>
471  </select>
472  </div>
473  </div>
474  </form>';
475 
476  $fieldRenderingDefinitions['title'] = '
477  <!-- Selecting title for link: -->
478  <form action="" name="ltitleform" id="ltitleform" class="t3js-dummyform form-horizontal">
479  <div class="form-group form-group-sm" id="typo3-linkTitle">
480  <label class="col-xs-4 control-label">' . htmlspecialchars($lang->getLL('title')) . '</label>
481  <div class="col-xs-8">
482  <input type="text" name="ltitle" class="form-control"
483  value="' . htmlspecialchars($this->linkAttributeValues['title']) . '" />
484  </div>
485  </div>
486  </form>';
487 
488  $fieldRenderingDefinitions['class'] = '
489  <!-- Selecting class for link: -->
490  <form action="" name="lclassform" id="lclassform" class="t3js-dummyform form-horizontal">
491  <div class="form-group form-group-sm" id="typo3-linkClass">
492  <label class="col-xs-4 control-label">' . htmlspecialchars($lang->getLL('class')) . '</label>
493  <div class="col-xs-8">
494  <input type="text" name="lclass" class="form-control"
495  value="' . htmlspecialchars($this->linkAttributeValues['class']) . '" />
496  </div>
497  </div>
498  </form>';
499 
500  $fieldRenderingDefinitions['params'] = '
501  <!-- Selecting params for link: -->
502  <form action="" name="lparamsform" id="lparamsform" class="t3js-dummyform form-horizontal">
503  <div class="form-group form-group-sm" id="typo3-linkParams">
504  <label class="col-xs-4 control-label">' . htmlspecialchars($lang->getLL('params')) . '</label>
505  <div class="col-xs-8">
506  <input type="text" name="lparams" class="form-control"
507  value="' . htmlspecialchars($this->linkAttributeValues['params']) . '" />
508  </div>
509  </div>
510  </form>';
511 
512  return $fieldRenderingDefinitions;
513  }
514 
520  public function ‪getUrlParameters(array $overrides = null)
521  {
522  return [
523  'act' => $overrides['act'] ?? ‪$this->displayedLinkHandlerId,
524  'P' => $overrides['P'] ?? ‪$this->parameters,
525  ];
526  }
527 
533  protected function ‪getBodyTagAttributes()
534  {
535  ‪$parameters = [];
536  ‪$parameters['uid'] = $this->parameters['uid'];
537  ‪$parameters['pid'] = $this->parameters['pid'];
538  ‪$parameters['itemName'] = $this->parameters['itemName'];
539  ‪$parameters['formName'] = $this->parameters['formName'];
540  ‪$parameters['params']['allowedExtensions'] = $this->parameters['params']['allowedExtensions'] ?? '';
541  ‪$parameters['params']['blindLinkOptions'] = $this->parameters['params']['blindLinkOptions'] ?? '';
542  ‪$parameters['params']['blindLinkFields'] = $this->parameters['params']['blindLinkFields'] ?? '';
543  $addPassOnParams = ‪HttpUtility::buildQueryString(['P' => ‪$parameters], '&');
544 
545  $attributes = $this->displayedLinkHandler->getBodyTagAttributes();
546  return array_merge(
547  $attributes,
548  [
549  'data-this-script-url' => strpos($this->thisScript, '?') === false ? $this->thisScript . '?' : $this->thisScript . '&',
550  'data-url-parameters' => json_encode($this->‪getUrlParameters()),
551  'data-parameters' => json_encode($this->parameters),
552  'data-add-on-params' => $addPassOnParams,
553  'data-link-attribute-fields' => json_encode($this->linkAttributeFields)
554  ]
555  );
556  }
557 
563  abstract protected function ‪getCurrentPageId();
564 
568  public function ‪getParameters()
569  {
570  return ‪$this->parameters;
571  }
572 
578  public function ‪getConfiguration()
579  {
580  return [];
581  }
582 
586  protected function ‪getDisplayedLinkHandlerId()
587  {
589  }
590 
594  public function ‪getScriptUrl()
595  {
596  return ‪$this->thisScript;
597  }
598 
602  protected function ‪getLanguageService()
603  {
604  return ‪$GLOBALS['LANG'];
605  }
606 
610  protected function ‪getBackendUser()
611  {
612  return ‪$GLOBALS['BE_USER'];
613  }
614 }
‪TYPO3\CMS\Core\Localization\LanguageService\includeLLFile
‪array includeLLFile($fileRef, $setGlobal=null, $mergeLocalOntoDefault=null)
Definition: LanguageService.php:297
‪TYPO3\CMS\Backend\Template\ModuleTemplate
Definition: ModuleTemplate.php:43
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:38
‪TYPO3\CMS\Core\Utility\HttpUtility\buildQueryString
‪static string buildQueryString(array $parameters, string $prependCharacter='', bool $skipEmptyParameters=false)
Definition: HttpUtility.php:163
‪TYPO3\CMS\Backend\Utility\BackendUtility\getPagesTSconfig
‪static array getPagesTSconfig($id)
Definition: BackendUtility.php:698
‪TYPO3\CMS\Recordlist\Controller
Definition: AbstractLinkBrowserController.php:16
‪TYPO3\CMS\Core\Service\DependencyOrderingService
Definition: DependencyOrderingService.php:32
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Backend\Utility\BackendUtility
Definition: BackendUtility.php:75
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static string[] trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:1059
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Utility\HttpUtility
Definition: HttpUtility.php:24
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:42
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Core\Http\HtmlResponse
Definition: HtmlResponse.php:26