TYPO3 CMS  TYPO3_7-6
AbstractLinkBrowserController.php
Go to the documentation of this file.
1 <?php
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 
28 
33 {
37  protected $doc;
38 
42  protected $parameters;
43 
49  protected $thisScript = '';
50 
54  protected $linkHandlers = [];
55 
63  protected $currentLinkParts = [];
64 
71 
78 
85 
93  protected $displayedLinkHandlerId = '';
94 
100  protected $linkAttributeFields = [];
101 
107  protected $linkAttributeValues = [];
108 
112  protected $hookObjects = [];
113 
117  public function __construct()
118  {
119  $this->initHookObjects();
120  $this->init();
121  }
122 
128  protected function init()
129  {
130  $this->getLanguageService()->includeLLFile('EXT:lang/locallang_browse_links.xlf');
131  }
132 
139  protected function initHookObjects()
140  {
141  if (
142  isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['LinkBrowser']['hooks'])
143  && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['LinkBrowser']['hooks'])
144  ) {
145  $hooks = GeneralUtility::makeInstance(DependencyOrderingService::class)->orderByDependencies(
146  $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['LinkBrowser']['hooks']
147  );
148  foreach ($hooks as $key => $hook) {
149  $this->hookObjects[] = GeneralUtility::makeInstance($hook['handler']);
150  }
151  }
152  }
153 
162  public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
163  {
164  $this->determineScriptUrl($request);
165  $this->initVariables($request);
166  $this->loadLinkHandlers();
167  $this->initCurrentUrl();
168 
169  $menuData = $this->buildMenuArray();
170  $renderLinkAttributeFields = $this->renderLinkAttributeFields();
171  $browserContent = $this->displayedLinkHandler->render($request);
172 
173  $this->initDocumentTemplate();
174  $content = $this->doc->startPage('Link Browser');
175  $content .= $this->doc->getFlashMessages();
176 
177  if (!empty($this->currentLinkParts)) {
178  $content .= $this->renderCurrentUrl();
179  }
180  $content .= $this->doc->getTabMenuRaw($menuData);
181  $content .= $renderLinkAttributeFields;
182 
183  $content .= '<div class="linkBrowser-tabContent">' . $browserContent . '</div>';
184  $content .= $this->doc->endPage();
185 
186  $response->getBody()->write($this->doc->insertStylesAndJS($content));
187  return $response;
188  }
189 
198  protected function determineScriptUrl(ServerRequestInterface $request)
199  {
200  if ($routePath = $request->getQueryParams()['route']) {
201  $router = GeneralUtility::makeInstance(Router::class);
202  $route = $router->match($routePath);
203  $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
204  $this->thisScript = (string)$uriBuilder->buildUriFromRoute($route->getOption('_identifier'));
205  } elseif ($moduleName = $request->getQueryParams()['M']) {
206  $this->thisScript = BackendUtility::getModuleUrl($moduleName);
207  } else {
208  $this->thisScript = GeneralUtility::getIndpEnv('SCRIPT_NAME');
209  }
210  }
211 
215  protected function initVariables(ServerRequestInterface $request)
216  {
217  $queryParams = $request->getQueryParams();
218  $act = isset($queryParams['act']) ? $queryParams['act'] : '';
219  // @deprecated since CMS 7, remove with CMS 8
220  if (strpos($act, '|')) {
221  GeneralUtility::deprecationLog('Using multiple values for the "act" parameter in the link wizard is deprecated. Only a single value is allowed. Values were: ' . $act);
222  $act = array_shift(explode('|', $act));
223  }
224  $this->displayedLinkHandlerId = $act;
225  $this->parameters = isset($queryParams['P']) ? $queryParams['P'] : [];
226  $this->linkAttributeValues = isset($queryParams['linkAttributes']) ? $queryParams['linkAttributes'] : [];
227  }
228 
233  protected function loadLinkHandlers()
234  {
235  $linkHandlers = $this->getLinkHandlers();
236  if (empty($linkHandlers)) {
237  throw new \UnexpectedValueException('No link handlers are configured. Check page TSconfig TCEMAIN.linkHandler.', 1442787911);
238  }
239 
240  $lang = $this->getLanguageService();
241  foreach ($linkHandlers as $identifier => $configuration) {
242  $identifier = rtrim($identifier, '.');
243 
244  if (empty($configuration['handler'])) {
245  throw new \UnexpectedValueException(sprintf('Missing handler for link handler "%1$s", check page TSconfig TCEMAIN.linkHandler.%1$s.handler', $identifier), 1494579849);
246  }
247 
249  $handler = GeneralUtility::makeInstance($configuration['handler']);
250  $handler->initialize(
251  $this,
252  $identifier,
253  isset($configuration['configuration.']) ? $configuration['configuration.'] : []
254  );
255 
256  $label = !empty($configuration['label']) ? $lang->sL($configuration['label']) : '';
257  $label = $label ?: $lang->sL('LLL:EXT:recordlist/Resources/Private/Language/locallang.xlf:error.linkHandlerTitleMissing');
258  $this->linkHandlers[$identifier] = [
259  'handlerInstance' => $handler,
260  'label' => $lang->sL($configuration['label'], true),
261  'displayBefore' => isset($configuration['displayBefore']) ? GeneralUtility::trimExplode(',', $configuration['displayBefore']) : [],
262  'displayAfter' => isset($configuration['displayAfter']) ? GeneralUtility::trimExplode(',', $configuration['displayAfter']) : [],
263  'scanBefore' => isset($configuration['scanBefore']) ? GeneralUtility::trimExplode(',', $configuration['scanBefore']) : [],
264  'scanAfter' => isset($configuration['scanAfter']) ? GeneralUtility::trimExplode(',', $configuration['scanAfter']) : [],
265  'addParams' => isset($configuration['addParams']) ? $configuration['addParams'] : '',
266  ];
267  }
268  }
269 
275  protected function getLinkHandlers()
276  {
277  $pageTSconfig = BackendUtility::getPagesTSconfig($this->getCurrentPageId());
278  $pageTSconfig = $this->getBackendUser()->getTSConfig('TCEMAIN.linkHandler.', $pageTSconfig);
279  $linkHandlers = (array)$pageTSconfig['properties'];
280 
281  foreach ($this->hookObjects as $hookObject) {
282  if (method_exists($hookObject, 'modifyLinkHandlers')) {
283  $linkHandlers = $hookObject->modifyLinkHandlers($linkHandlers, $this->currentLinkParts);
284  }
285  }
286 
287  return $linkHandlers;
288  }
289 
295  protected function initCurrentUrl()
296  {
297  if (empty($this->currentLinkParts)) {
298  return;
299  }
300 
301  $orderedHandlers = GeneralUtility::makeInstance(DependencyOrderingService::class)->orderByDependencies($this->linkHandlers, 'scanBefore', 'scanAfter');
302 
303  // find responsible handler for current link
304  foreach ($orderedHandlers as $key => $configuration) {
306  $handler = $configuration['handlerInstance'];
307  if ($handler->canHandleLink($this->currentLinkParts)) {
308  $this->currentLinkHandler = $handler;
309  $this->currentLinkHandlerId = $key;
310  break;
311  }
312  }
313  // reset the link if we have no handler for it
314  if (!$this->currentLinkHandler) {
315  $this->currentLinkParts = [];
316  }
317 
318  // overwrite any preexisting
319  foreach ($this->currentLinkParts as $key => $part) {
320  if ($key !== 'url') {
321  $this->linkAttributeValues[$key] = $part;
322  }
323  }
324  }
325 
331  protected function initDocumentTemplate()
332  {
333  $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
334  $this->doc->bodyTagId = 'typo3-browse-links-php';
335 
336  foreach ($this->getBodyTagAttributes() as $attributeName => $value) {
337  $this->doc->bodyTagAdditions .= ' ' . $attributeName . '="' . htmlspecialchars($value) . '"';
338  }
339 
340  // Finally, add the accumulated JavaScript to the template object:
341  // also unset the default jumpToUrl() function before
342  unset($this->doc->JScodeArray['jumpToUrl']);
343  }
344 
350  protected function renderCurrentUrl()
351  {
352  return '<!-- Print current URL -->
353  <table border="0" cellpadding="0" cellspacing="0" id="typo3-curUrl">
354  <tr>
355  <td>' . $this->getLanguageService()->getLL('currentLink', true) . ': ' . htmlspecialchars($this->currentLinkHandler->formatCurrentUrl()) . '</td>
356  </tr>
357  </table>';
358  }
359 
365  protected function buildMenuArray()
366  {
367  $allowedItems = $this->getAllowedItems();
368  if ($this->displayedLinkHandlerId && !in_array($this->displayedLinkHandlerId, $allowedItems, true)) {
369  $this->displayedLinkHandlerId = '';
370  }
371 
372  $allowedHandlers = array_flip($allowedItems);
373  $menuDef = [];
374  foreach ($this->linkHandlers as $identifier => $configuration) {
375  if (!isset($allowedHandlers[$identifier])) {
376  continue;
377  }
378 
380  $handlerInstance = $configuration['handlerInstance'];
381  $isActive = $this->displayedLinkHandlerId === $identifier || !$this->displayedLinkHandlerId && $handlerInstance === $this->currentLinkHandler;
382  if ($isActive) {
383  $this->displayedLinkHandler = $handlerInstance;
384  if (!$this->displayedLinkHandlerId) {
385  $this->displayedLinkHandlerId = $this->currentLinkHandlerId;
386  }
387  }
388 
389  if ($configuration['addParams']) {
390  $addParams = $configuration['addParams'];
391  } else {
392  $parameters = GeneralUtility::implodeArrayForUrl('', $this->getUrlParameters(['act' => $identifier]));
393  $addParams = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue('?' . ltrim($parameters, '&')) . ');return false;"';
394  }
395  $menuDef[$identifier] = [
396  'isActive' => $isActive,
397  'label' => $configuration['label'],
398  'url' => '#',
399  'addParams' => $addParams,
400  'before' => $configuration['displayBefore'],
401  'after' => $configuration['displayAfter']
402  ];
403  }
404 
405  $menuDef = GeneralUtility::makeInstance(DependencyOrderingService::class)->orderByDependencies($menuDef);
406 
407  // if there is no active tab
408  if (!$this->displayedLinkHandler) {
409  // empty the current link
410  $this->currentLinkParts = [];
411  $this->currentLinkHandler = null;
412  $this->currentLinkHandler = '';
413  // select first tab
414  reset($menuDef);
415  $this->displayedLinkHandlerId = key($menuDef);
416  $this->displayedLinkHandler = $this->linkHandlers[$this->displayedLinkHandlerId]['handlerInstance'];
417  $menuDef[$this->displayedLinkHandlerId]['isActive'] = true;
418  }
419 
420  return $menuDef;
421  }
422 
428  protected function getAllowedItems()
429  {
430  $allowedItems = array_keys($this->linkHandlers);
431 
432  foreach ($this->hookObjects as $hookObject) {
433  if (method_exists($hookObject, 'modifyAllowedItems')) {
434  $allowedItems = $hookObject->modifyAllowedItems($allowedItems, $this->currentLinkParts);
435  }
436  }
437 
438  // Initializing the action value, possibly removing blinded values etc:
439  $blindLinkOptions = isset($this->parameters['params']['blindLinkOptions'])
440  ? GeneralUtility::trimExplode(',', $this->parameters['params']['blindLinkOptions'])
441  : [];
442  $allowedItems = array_diff($allowedItems, $blindLinkOptions);
443 
444  return $allowedItems;
445  }
446 
452  protected function getAllowedLinkAttributes()
453  {
454  $allowedLinkAttributes = $this->displayedLinkHandler->getLinkAttributes();
455 
456  // Removing link fields if configured
457  $blindLinkFields = isset($this->parameters['params']['blindLinkFields'])
458  ? GeneralUtility::trimExplode(',', $this->parameters['params']['blindLinkFields'], true)
459  : [];
460  $allowedLinkAttributes = array_diff($allowedLinkAttributes, $blindLinkFields);
461 
462  return $allowedLinkAttributes;
463  }
464 
470  public function renderLinkAttributeFields()
471  {
472  $fieldRenderingDefinitions = $this->getLinkAttributeFieldDefinitions();
473 
474  $fieldRenderingDefinitions = $this->displayedLinkHandler->modifyLinkAttributes($fieldRenderingDefinitions);
475 
476  $this->linkAttributeFields = $this->getAllowedLinkAttributes();
477 
478  $content = '';
479  foreach ($this->linkAttributeFields as $attribute) {
480  $content .= $fieldRenderingDefinitions[$attribute];
481  }
482 
483  // add update button if appropriate
484  if (!empty($this->currentLinkParts) && $this->displayedLinkHandler === $this->currentLinkHandler && $this->currentLinkHandler->isUpdateSupported()) {
485  $content .= '
486  <form action="" name="lparamsform" id="lparamsform">
487  <table border="0" cellpadding="2" cellspacing="1" id="typo3-linkParams">
488  <tr><td>
489  <input class="btn btn-default t3js-linkCurrent" type="submit" value="' . $this->getLanguageService()->getLL('update', true) . '" />
490  </td></tr>
491  </table>
492  </form><br /><br />';
493  }
494 
495  return $content;
496  }
497 
503  protected function getLinkAttributeFieldDefinitions()
504  {
505  $lang = $this->getLanguageService();
506 
507  $fieldRenderingDefinitions = [];
508  $fieldRenderingDefinitions['target'] = '
509  <!--
510  Selecting target for link:
511  -->
512  <form action="" name="ltargetform" id="ltargetform" class="t3js-dummyform">
513  <table border="0" cellpadding="2" cellspacing="1" id="typo3-linkTarget">
514  <tr>
515  <td style="width: 96px;">' . $lang->getLL('target', true) . ':</td>
516  <td>
517  <input type="text" name="ltarget" class="t3js-linkTarget" value="' . htmlspecialchars($this->linkAttributeValues['target']) . '" />
518  <select name="ltarget_type" class="t3js-targetPreselect">
519  <option value=""></option>
520  <option value="_top">' . $lang->getLL('top', true) . '</option>
521  <option value="_blank">' . $lang->getLL('newWindow', true) . '</option>
522  </select>
523  </td>
524  </tr>
525  </table>
526  </form>';
527 
528  $fieldRenderingDefinitions['title'] = '
529  <!--
530  Selecting title for link:
531  -->
532  <form action="" name="ltitleform" id="ltitleform" class="t3js-dummyform">
533  <table border="0" cellpadding="2" cellspacing="1" id="typo3-linkTitle">
534  <tr>
535  <td style="width: 96px;">' . $lang->getLL('title', true) . '</td>
536  <td><input type="text" name="ltitle" class="typo3-link-input" value="' . htmlspecialchars($this->linkAttributeValues['title']) . '" /></td>
537  </tr>
538  </table>
539  </form>
540  ';
541 
542  $fieldRenderingDefinitions['class'] = '
543  <!--
544  Selecting class for link:
545  -->
546  <form action="" name="lclassform" id="lclassform" class="t3js-dummyform">
547  <table border="0" cellpadding="2" cellspacing="1" id="typo3-linkClass">
548  <tr>
549  <td style="width: 96px;">' . $lang->getLL('class', true) . '</td>
550  <td><input type="text" name="lclass" class="typo3-link-input" value="' . htmlspecialchars($this->linkAttributeValues['class']) . '" /></td>
551  </tr>
552  </table>
553  </form>
554  ';
555 
556  $fieldRenderingDefinitions['params'] = '
557  <!--
558  Selecting params for link:
559  -->
560  <form action="" name="lparamsform" id="lparamsform" class="t3js-dummyform">
561  <table border="0" cellpadding="2" cellspacing="1" id="typo3-linkParams">
562  <tr>
563  <td style="width: 96px;">' . $lang->getLL('params', true) . '</td>
564  <td><input type="text" name="lparams" class="typo3-link-input" value="' . htmlspecialchars($this->linkAttributeValues['params']) . '" /></td>
565  </tr>
566  </table>
567  </form>
568  ';
569 
570  return $fieldRenderingDefinitions;
571  }
572 
578  public function getUrlParameters(array $overrides = null)
579  {
580  return [
581  'act' => isset($overrides['act']) ? $overrides['act'] : $this->displayedLinkHandlerId,
582  'P' => isset($overrides['P']) ? $overrides['P'] : $this->parameters,
583  ];
584  }
585 
591  protected function getBodyTagAttributes()
592  {
593  $parameters = [];
594  $parameters['uid'] = $this->parameters['uid'];
595  $parameters['pid'] = $this->parameters['pid'];
596  $parameters['itemName'] = $this->parameters['itemName'];
597  $parameters['formName'] = $this->parameters['formName'];
598  $parameters['params']['allowedExtensions'] = isset($this->parameters['params']['allowedExtensions']) ? $this->parameters['params']['allowedExtensions'] : '';
599  $parameters['params']['blindLinkOptions'] = isset($this->parameters['params']['blindLinkOptions']) ? $this->parameters['params']['blindLinkOptions'] : '';
600  $parameters['params']['blindLinkFields'] = isset($this->parameters['params']['blindLinkFields']) ? $this->parameters['params']['blindLinkFields']: '';
601  $addPassOnParams = GeneralUtility::implodeArrayForUrl('P', $parameters);
602 
603  $attributes = $this->displayedLinkHandler->getBodyTagAttributes();
604  return array_merge(
605  $attributes,
606  [
607  'data-this-script-url' => strpos($this->thisScript, '?') === false ? $this->thisScript . '?' : $this->thisScript . '&',
608  'data-url-parameters' => json_encode($this->getUrlParameters()),
609  'data-parameters' => json_encode($this->parameters),
610  'data-add-on-params' => $addPassOnParams,
611  'data-link-attribute-fields' => json_encode($this->linkAttributeFields)
612  ]
613  );
614  }
615 
621  abstract protected function getCurrentPageId();
622 
626  public function getParameters()
627  {
628  return $this->parameters;
629  }
630 
636  public function getConfiguration()
637  {
638  return [];
639  }
640 
644  public function getDisplayedLinkHandlerId()
645  {
647  }
648 
652  public function getScriptUrl()
653  {
654  return $this->thisScript;
655  }
656 
660  protected function getLanguageService()
661  {
662  return $GLOBALS['LANG'];
663  }
664 
668  protected function getBackendUser()
669  {
670  return $GLOBALS['BE_USER'];
671  }
672 }
static getPagesTSconfig($id, $rootLine=null, $returnPartArray=false)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static implodeArrayForUrl($name, array $theArray, $str='', $skipBlank=false, $rawurlencodeParamName=false)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']