TYPO3 CMS  TYPO3_7-6
AbstractPlugin.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 
25 
33 {
39  public $cObj;
40 
46  public $prefixId;
47 
54 
60  public $extKey;
61 
69  public $piVars = [
70  'pointer' => '',
71  // Used as a pointer for lists
72  'mode' => '',
73  // List mode
74  'sword' => '',
75  // Search word
76  'sort' => ''
77  ];
78 
86  public $internal = ['res_count' => 0, 'results_at_a_time' => 20, 'maxPages' => 10, 'currentRow' => [], 'currentTable' => ''];
87 
93  public $LOCAL_LANG = [];
94 
103  protected $LOCAL_LANG_UNSET = [];
104 
110  public $LOCAL_LANG_charset = [];
111 
118  public $LOCAL_LANG_loaded = 0;
119 
125  public $LLkey = 'default';
126 
132  public $altLLkey = '';
133 
140  public $LLtestPrefix = '';
141 
148  public $LLtestPrefixAlt = '';
149 
153  public $pi_isOnlyFields = 'mode,pointer';
154 
158  public $pi_alwaysPrev = 0;
159 
163  public $pi_lowerThan = 5;
164 
168  public $pi_moreParams = '';
169 
173  public $pi_listFields = '*';
174 
178  public $pi_autoCacheFields = [];
179 
183  public $pi_autoCacheEn = 0;
184 
192  public $pi_USER_INT_obj = false;
193 
200  public $pi_checkCHash = false;
201 
210  public $conf = [];
211 
218 
222  public $pi_tmpPageId = 0;
223 
230 
237 
247  {
248  $this->databaseConnection = $databaseConnection ?: $GLOBALS['TYPO3_DB'];
249  $this->frontendController = $frontendController ?: $GLOBALS['TSFE'];
250  // Setting piVars:
251  if ($this->prefixId) {
252  $this->piVars = GeneralUtility::_GPmerged($this->prefixId);
253  // cHash mode check
254  // IMPORTANT FOR CACHED PLUGINS (USER cObject): As soon as you generate cached plugin output which depends on parameters (eg. seeing the details of a news item) you MUST check if a cHash value is set.
255  // Background: The function call will check if a cHash parameter was sent with the URL because only if it was the page may be cached. If no cHash was found the function will simply disable caching to avoid unpredictable caching behaviour. In any case your plugin can generate the expected output and the only risk is that the content may not be cached. A missing cHash value is considered a mistake in the URL resulting from either URL manipulation, "realurl" "grayzones" etc. The problem is rare (more frequent with "realurl") but when it occurs it is very puzzling!
256  if ($this->pi_checkCHash && !empty($this->piVars)) {
257  $this->frontendController->reqCHash();
258  }
259  }
260  if (!empty($this->frontendController->config['config']['language'])) {
261  $this->LLkey = $this->frontendController->config['config']['language'];
262  if (empty($this->frontendController->config['config']['language_alt'])) {
264  $locales = GeneralUtility::makeInstance(Locales::class);
265  if (in_array($this->LLkey, $locales->getLocales())) {
266  $this->altLLkey = '';
267  foreach ($locales->getLocaleDependencies($this->LLkey) as $language) {
268  $this->altLLkey .= $language . ',';
269  }
270  $this->altLLkey = rtrim($this->altLLkey, ',');
271  }
272  } else {
273  $this->altLLkey = $this->frontendController->config['config']['language_alt'];
274  }
275  }
276  }
277 
285  protected function applyStdWrapRecursive(array $conf, $level = 0)
286  {
287  foreach ($conf as $key => $confNextLevel) {
288  if (strpos($key, '.') !== false) {
289  $key = substr($key, 0, -1);
290 
291  // descend into all non-stdWrap-subelements first
292  foreach ($confNextLevel as $subKey => $subConfNextLevel) {
293  if (is_array($subConfNextLevel) && strpos($subKey, '.') !== false && $subKey !== 'stdWrap.') {
294  $conf[$key . '.'] = $this->applyStdWrapRecursive($confNextLevel, $level + 1);
295  }
296  }
297 
298  // now for stdWrap
299  foreach ($confNextLevel as $subKey => $subConfNextLevel) {
300  if (is_array($subConfNextLevel) && $subKey === 'stdWrap.') {
301  $conf[$key] = $this->cObj->stdWrap($conf[$key], $conf[$key . '.']['stdWrap.']);
302  unset($conf[$key . '.']['stdWrap.']);
303  if (empty($conf[$key . '.'])) {
304  unset($conf[$key . '.']);
305  }
306  }
307  }
308  }
309  }
310  return $conf;
311  }
312 
318  public function pi_setPiVarDefaults()
319  {
320  if (isset($this->conf['_DEFAULT_PI_VARS.']) && is_array($this->conf['_DEFAULT_PI_VARS.'])) {
321  $this->conf['_DEFAULT_PI_VARS.'] = $this->applyStdWrapRecursive($this->conf['_DEFAULT_PI_VARS.']);
322  $tmp = $this->conf['_DEFAULT_PI_VARS.'];
323  ArrayUtility::mergeRecursiveWithOverrule($tmp, is_array($this->piVars) ? $this->piVars : []);
324  $this->piVars = $tmp;
325  }
326  }
327 
328  /***************************
329  *
330  * Link functions
331  *
332  **************************/
347  public function pi_getPageLink($id, $target = '', $urlParameters = [])
348  {
349  return $this->cObj->getTypoLink_URL($id, $urlParameters, $target);
350  }
351 
364  public function pi_linkToPage($str, $id, $target = '', $urlParameters = [])
365  {
366  return $this->cObj->getTypoLink($str, $id, $urlParameters, $target);
367  }
368 
380  public function pi_linkTP($str, $urlParameters = [], $cache = false, $altPageId = 0)
381  {
382  $conf = [];
383  $conf['useCacheHash'] = $this->pi_USER_INT_obj ? 0 : $cache;
384  $conf['no_cache'] = $this->pi_USER_INT_obj ? 0 : !$cache;
385  $conf['parameter'] = $altPageId ? $altPageId : ($this->pi_tmpPageId ? $this->pi_tmpPageId : $this->frontendController->id);
386  $conf['additionalParams'] = $this->conf['parent.']['addParams'] . GeneralUtility::implodeArrayForUrl('', $urlParameters, '', true) . $this->pi_moreParams;
387  return $this->cObj->typoLink($str, $conf);
388  }
389 
403  public function pi_linkTP_keepPIvars($str, $overrulePIvars = [], $cache = false, $clearAnyway = false, $altPageId = 0)
404  {
405  if (is_array($this->piVars) && is_array($overrulePIvars) && !$clearAnyway) {
407  unset($piVars['DATA']);
409  $overrulePIvars = $piVars;
410  if ($this->pi_autoCacheEn) {
411  $cache = $this->pi_autoCache($overrulePIvars);
412  }
413  }
414  return $this->pi_linkTP($str, [$this->prefixId => $overrulePIvars], $cache, $altPageId);
415  }
416 
428  public function pi_linkTP_keepPIvars_url($overrulePIvars = [], $cache = false, $clearAnyway = false, $altPageId = 0)
429  {
430  $this->pi_linkTP_keepPIvars('|', $overrulePIvars, $cache, $clearAnyway, $altPageId);
431  return $this->cObj->lastTypoLinkUrl;
432  }
433 
447  public function pi_list_linkSingle($str, $uid, $cache = false, $mergeArr = [], $urlOnly = false, $altPageId = 0)
448  {
449  if ($this->prefixId) {
450  if ($cache) {
451  $overrulePIvars = $uid ? ['showUid' => $uid] : [];
452  $overrulePIvars = array_merge($overrulePIvars, (array)$mergeArr);
453  $str = $this->pi_linkTP($str, [$this->prefixId => $overrulePIvars], $cache, $altPageId);
454  } else {
455  $overrulePIvars = ['showUid' => $uid ?: ''];
456  $overrulePIvars = array_merge($overrulePIvars, (array)$mergeArr);
457  $str = $this->pi_linkTP_keepPIvars($str, $overrulePIvars, $cache, 0, $altPageId);
458  }
459  // If urlOnly flag, return only URL as it has recently be generated.
460  if ($urlOnly) {
461  $str = $this->cObj->lastTypoLinkUrl;
462  }
463  }
464  return $str;
465  }
466 
475  public function pi_openAtagHrefInJSwindow($str, $winName = '', $winParams = 'width=670,height=500,status=0,menubar=0,scrollbars=1,resizable=1')
476  {
477  if (preg_match('/(.*)(<a[^>]*>)(.*)/i', $str, $match)) {
478  $aTagContent = GeneralUtility::get_tag_attributes($match[2]);
479  $onClick = 'vHWin=window.open('
480  . GeneralUtility::quoteJSvalue($this->frontendController->baseUrlWrap($aTagContent['href'])) . ','
481  . GeneralUtility::quoteJSvalue($winName ?: md5($aTagContent['href'])) . ','
482  . GeneralUtility::quoteJSvalue($winParams) . ');vHWin.focus();return false;';
483  $match[2] = '<a href="#" onclick="' . htmlspecialchars($onClick) . '">';
484  $str = $match[1] . $match[2] . $match[3];
485  }
486  return $str;
487  }
488 
489  /***************************
490  *
491  * Functions for listing, browsing, searching etc.
492  *
493  **************************/
518  public function pi_list_browseresults($showResultCount = 1, $tableParams = '', $wrapArr = [], $pointerName = 'pointer', $hscText = true, $forceOutput = false)
519  {
520  // example $wrapArr-array how it could be traversed from an extension
521  /* $wrapArr = array(
522  'browseBoxWrap' => '<div class="browseBoxWrap">|</div>',
523  'showResultsWrap' => '<div class="showResultsWrap">|</div>',
524  'browseLinksWrap' => '<div class="browseLinksWrap">|</div>',
525  'showResultsNumbersWrap' => '<span class="showResultsNumbersWrap">|</span>',
526  'disabledLinkWrap' => '<span class="disabledLinkWrap">|</span>',
527  'inactiveLinkWrap' => '<span class="inactiveLinkWrap">|</span>',
528  'activeLinkWrap' => '<span class="activeLinkWrap">|</span>'
529  );*/
530  // Initializing variables:
531  $pointer = (int)$this->piVars[$pointerName];
532  $count = (int)$this->internal['res_count'];
533  $results_at_a_time = MathUtility::forceIntegerInRange($this->internal['results_at_a_time'], 1, 1000);
534  $totalPages = ceil($count / $results_at_a_time);
535  $maxPages = MathUtility::forceIntegerInRange($this->internal['maxPages'], 1, 100);
537  if (!$forceOutput && $count <= $results_at_a_time) {
538  return '';
539  }
540  // $showResultCount determines how the results of the pagerowser will be shown.
541  // If set to 0: only the result-browser will be shown
542  // 1: (default) the text "Displaying results..." and the result-browser will be shown.
543  // 2: only the text "Displaying results..." will be shown
544  $showResultCount = (int)$showResultCount;
545  // If this is set, two links named "<< First" and "LAST >>" will be shown and point to the very first or last page.
546  $showFirstLast = $this->internal['showFirstLast'];
547  // If this has a value the "previous" button is always visible (will be forced if "showFirstLast" is set)
548  $alwaysPrev = $showFirstLast ? 1 : $this->pi_alwaysPrev;
549  if (isset($this->internal['pagefloat'])) {
550  if (strtoupper($this->internal['pagefloat']) == 'CENTER') {
551  $pagefloat = ceil(($maxPages - 1) / 2);
552  } else {
553  // pagefloat set as integer. 0 = left, value >= $this->internal['maxPages'] = right
554  $pagefloat = MathUtility::forceIntegerInRange($this->internal['pagefloat'], -1, $maxPages - 1);
555  }
556  } else {
557  // pagefloat disabled
558  $pagefloat = -1;
559  }
560  // Default values for "traditional" wrapping with a table. Can be overwritten by vars from $wrapArr
561  $wrapper['disabledLinkWrap'] = '<td nowrap="nowrap"><p>|</p></td>';
562  $wrapper['inactiveLinkWrap'] = '<td nowrap="nowrap"><p>|</p></td>';
563  $wrapper['activeLinkWrap'] = '<td' . $this->pi_classParam('browsebox-SCell') . ' nowrap="nowrap"><p>|</p></td>';
564  $wrapper['browseLinksWrap'] = rtrim('<table ' . $tableParams) . '><tr>|</tr></table>';
565  $wrapper['showResultsWrap'] = '<p>|</p>';
566  $wrapper['browseBoxWrap'] = '
567  <!--
568  List browsing box:
569  -->
570  <div ' . $this->pi_classParam('browsebox') . '>
571  |
572  </div>';
573  // Now overwrite all entries in $wrapper which are also in $wrapArr
574  $wrapper = array_merge($wrapper, $wrapArr);
575  // Show pagebrowser
576  if ($showResultCount != 2) {
577  if ($pagefloat > -1) {
578  $lastPage = min($totalPages, max($pointer + 1 + $pagefloat, $maxPages));
579  $firstPage = max(0, $lastPage - $maxPages);
580  } else {
581  $firstPage = 0;
582  $lastPage = MathUtility::forceIntegerInRange($totalPages, 1, $maxPages);
583  }
584  $links = [];
585  // Make browse-table/links:
586  // Link to first page
587  if ($showFirstLast) {
588  if ($pointer > 0) {
589  $links[] = $this->cObj->wrap($this->pi_linkTP_keepPIvars($this->pi_getLL('pi_list_browseresults_first', '<< First', $hscText), [$pointerName => null], $pi_isOnlyFields), $wrapper['inactiveLinkWrap']);
590  } else {
591  $links[] = $this->cObj->wrap($this->pi_getLL('pi_list_browseresults_first', '<< First', $hscText), $wrapper['disabledLinkWrap']);
592  }
593  }
594  // Link to previous page
595  if ($alwaysPrev >= 0) {
596  if ($pointer > 0) {
597  $links[] = $this->cObj->wrap($this->pi_linkTP_keepPIvars($this->pi_getLL('pi_list_browseresults_prev', '< Previous', $hscText), [$pointerName => ($pointer - 1) ?: ''], $pi_isOnlyFields), $wrapper['inactiveLinkWrap']);
598  } elseif ($alwaysPrev) {
599  $links[] = $this->cObj->wrap($this->pi_getLL('pi_list_browseresults_prev', '< Previous', $hscText), $wrapper['disabledLinkWrap']);
600  }
601  }
602  // Links to pages
603  for ($a = $firstPage; $a < $lastPage; $a++) {
604  if ($this->internal['showRange']) {
605  $pageText = ($a * $results_at_a_time + 1) . '-' . min($count, ($a + 1) * $results_at_a_time);
606  } else {
607  $pageText = trim($this->pi_getLL('pi_list_browseresults_page', 'Page', $hscText) . ' ' . ($a + 1));
608  }
609  // Current page
610  if ($pointer == $a) {
611  if ($this->internal['dontLinkActivePage']) {
612  $links[] = $this->cObj->wrap($pageText, $wrapper['activeLinkWrap']);
613  } else {
614  $links[] = $this->cObj->wrap($this->pi_linkTP_keepPIvars($pageText, [$pointerName => $a ?: ''], $pi_isOnlyFields), $wrapper['activeLinkWrap']);
615  }
616  } else {
617  $links[] = $this->cObj->wrap($this->pi_linkTP_keepPIvars($pageText, [$pointerName => $a ?: ''], $pi_isOnlyFields), $wrapper['inactiveLinkWrap']);
618  }
619  }
620  if ($pointer < $totalPages - 1 || $showFirstLast) {
621  // Link to next page
622  if ($pointer >= $totalPages - 1) {
623  $links[] = $this->cObj->wrap($this->pi_getLL('pi_list_browseresults_next', 'Next >', $hscText), $wrapper['disabledLinkWrap']);
624  } else {
625  $links[] = $this->cObj->wrap($this->pi_linkTP_keepPIvars($this->pi_getLL('pi_list_browseresults_next', 'Next >', $hscText), [$pointerName => $pointer + 1], $pi_isOnlyFields), $wrapper['inactiveLinkWrap']);
626  }
627  }
628  // Link to last page
629  if ($showFirstLast) {
630  if ($pointer < $totalPages - 1) {
631  $links[] = $this->cObj->wrap($this->pi_linkTP_keepPIvars($this->pi_getLL('pi_list_browseresults_last', 'Last >>', $hscText), [$pointerName => $totalPages - 1], $pi_isOnlyFields), $wrapper['inactiveLinkWrap']);
632  } else {
633  $links[] = $this->cObj->wrap($this->pi_getLL('pi_list_browseresults_last', 'Last >>', $hscText), $wrapper['disabledLinkWrap']);
634  }
635  }
636  $theLinks = $this->cObj->wrap(implode(LF, $links), $wrapper['browseLinksWrap']);
637  } else {
638  $theLinks = '';
639  }
640  $pR1 = $pointer * $results_at_a_time + 1;
641  $pR2 = $pointer * $results_at_a_time + $results_at_a_time;
642  if ($showResultCount) {
643  if ($wrapper['showResultsNumbersWrap']) {
644  // This will render the resultcount in a more flexible way using markers (new in TYPO3 3.8.0).
645  // The formatting string is expected to hold template markers (see function header). Example: 'Displaying results ###FROM### to ###TO### out of ###OUT_OF###'
646  $markerArray['###FROM###'] = $this->cObj->wrap($this->internal['res_count'] > 0 ? $pR1 : 0, $wrapper['showResultsNumbersWrap']);
647  $markerArray['###TO###'] = $this->cObj->wrap(min($this->internal['res_count'], $pR2), $wrapper['showResultsNumbersWrap']);
648  $markerArray['###OUT_OF###'] = $this->cObj->wrap($this->internal['res_count'], $wrapper['showResultsNumbersWrap']);
649  $markerArray['###FROM_TO###'] = $this->cObj->wrap(($this->internal['res_count'] > 0 ? $pR1 : 0) . ' ' . $this->pi_getLL('pi_list_browseresults_to', 'to') . ' ' . min($this->internal['res_count'], $pR2), $wrapper['showResultsNumbersWrap']);
650  $markerArray['###CURRENT_PAGE###'] = $this->cObj->wrap($pointer + 1, $wrapper['showResultsNumbersWrap']);
651  $markerArray['###TOTAL_PAGES###'] = $this->cObj->wrap($totalPages, $wrapper['showResultsNumbersWrap']);
652  // Substitute markers
653  $resultCountMsg = $this->cObj->substituteMarkerArray($this->pi_getLL('pi_list_browseresults_displays', 'Displaying results ###FROM### to ###TO### out of ###OUT_OF###'), $markerArray);
654  } else {
655  // Render the resultcount in the "traditional" way using sprintf
656  $resultCountMsg = sprintf(str_replace('###SPAN_BEGIN###', '<span' . $this->pi_classParam('browsebox-strong') . '>', $this->pi_getLL('pi_list_browseresults_displays', 'Displaying results ###SPAN_BEGIN###%s to %s</span> out of ###SPAN_BEGIN###%s</span>')), $count > 0 ? $pR1 : 0, min($count, $pR2), $count);
657  }
658  $resultCountMsg = $this->cObj->wrap($resultCountMsg, $wrapper['showResultsWrap']);
659  } else {
660  $resultCountMsg = '';
661  }
662  $sTables = $this->cObj->wrap($resultCountMsg . $theLinks, $wrapper['browseBoxWrap']);
663  return $sTables;
664  }
665 
674  public function pi_list_searchBox($tableParams = '')
675  {
677  // Search box design:
678  $sTables = '
679 
680  <!--
681  List search box:
682  -->
683  <div' . $this->pi_classParam('searchbox') . '>
684  <form action="' . htmlspecialchars(GeneralUtility::getIndpEnv('REQUEST_URI')) . '" method="post" style="margin: 0 0 0 0;">
685  <' . rtrim('table ' . $tableParams) . '>
686  <tr>
687  <td><input type="text" name="' . $this->prefixId . '[sword]" value="' . htmlspecialchars($this->piVars['sword']) . '"' . $this->pi_classParam('searchbox-sword') . ' /></td>
688  <td><input type="submit" value="' . $this->pi_getLL('pi_list_searchBox_search', 'Search', true) . '"' . $this->pi_classParam('searchbox-button') . ' />' . '<input type="hidden" name="no_cache" value="1" />' . '<input type="hidden" name="' . $this->prefixId . '[pointer]" value="" />' . '</td>
689  </tr>
690  </table>
691  </form>
692  </div>';
693  return $sTables;
694  }
695 
703  public function pi_list_modeSelector($items = [], $tableParams = '')
704  {
705  $cells = [];
706  foreach ($items as $k => $v) {
707  $cells[] = '
708  <td' . ($this->piVars['mode'] == $k ? $this->pi_classParam('modeSelector-SCell') : '') . '><p>' . $this->pi_linkTP_keepPIvars(htmlspecialchars($v), ['mode' => $k], $this->pi_isOnlyFields($this->pi_isOnlyFields)) . '</p></td>';
709  }
710  $sTables = '
711 
712  <!--
713  Mode selector (menu for list):
714  -->
715  <div' . $this->pi_classParam('modeSelector') . '>
716  <' . rtrim('table ' . $tableParams) . '>
717  <tr>
718  ' . implode('', $cells) . '
719  </tr>
720  </table>
721  </div>';
722  return $sTables;
723  }
724 
737  public function pi_list_makelist($res, $tableParams = '')
738  {
739  // Make list table header:
740  $tRows = [];
741  $this->internal['currentRow'] = '';
742  $tRows[] = $this->pi_list_header();
743  // Make list table rows
744  $c = 0;
745  while ($this->internal['currentRow'] = $this->databaseConnection->sql_fetch_assoc($res)) {
746  $tRows[] = $this->pi_list_row($c);
747  $c++;
748  }
749  $out = '
750 
751  <!--
752  Record list:
753  -->
754  <div' . $this->pi_classParam('listrow') . '>
755  <' . rtrim('table ' . $tableParams) . '>
756  ' . implode('', $tRows) . '
757  </table>
758  </div>';
759  return $out;
760  }
761 
770  public function pi_list_row($c)
771  {
772  // Dummy
773  return '<tr' . ($c % 2 ? $this->pi_classParam('listrow-odd') : '') . '><td><p>[dummy row]</p></td></tr>';
774  }
775 
783  public function pi_list_header()
784  {
785  return '<tr' . $this->pi_classParam('listrow-header') . '><td><p>[dummy header row]</p></td></tr>';
786  }
787 
788  /***************************
789  *
790  * Stylesheet, CSS
791  *
792  **************************/
799  public function pi_getClassName($class)
800  {
801  return str_replace('_', '-', $this->prefixId) . ($this->prefixId ? '-' : '') . $class;
802  }
803 
813  public function pi_classParam($class, $addClasses = '')
814  {
815  $output = '';
816  $classNames = GeneralUtility::trimExplode(',', $class);
817  foreach ($classNames as $className) {
818  $output .= ' ' . $this->pi_getClassName($className);
819  }
820  $additionalClassNames = GeneralUtility::trimExplode(',', $addClasses);
821  foreach ($additionalClassNames as $additionalClassName) {
822  $output .= ' ' . $additionalClassName;
823  }
824  return ' class="' . trim($output) . '"';
825  }
826 
834  public function pi_wrapInBaseClass($str)
835  {
836  $content = '<div class="' . str_replace('_', '-', $this->prefixId) . '">
837  ' . $str . '
838  </div>
839  ';
840  if (!$this->frontendController->config['config']['disablePrefixComment']) {
841  $content = '
842 
843 
844  <!--
845 
846  BEGIN: Content of extension "' . $this->extKey . '", plugin "' . $this->prefixId . '"
847 
848  -->
849  ' . $content . '
850  <!-- END: Content of extension "' . $this->extKey . '", plugin "' . $this->prefixId . '" -->
851 
852  ';
853  }
854  return $content;
855  }
856 
857  /***************************
858  *
859  * Frontend editing: Edit panel, edit icons
860  *
861  **************************/
872  public function pi_getEditPanel($row = [], $tablename = '', $label = '', $conf = [])
873  {
874  $panel = '';
875  if (!$row || !$tablename) {
876  $row = $this->internal['currentRow'];
877  $tablename = $this->internal['currentTable'];
878  }
879  if ($this->frontendController->beUserLogin) {
880  // Create local cObj if not set:
881  if (!is_object($this->pi_EPtemp_cObj)) {
882  $this->pi_EPtemp_cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
883  $this->pi_EPtemp_cObj->setParent($this->cObj->data, $this->cObj->currentRecord);
884  }
885  // Initialize the cObj object with current row
886  $this->pi_EPtemp_cObj->start($row, $tablename);
887  // Setting TypoScript values in the $conf array. See documentation in TSref for the EDITPANEL cObject.
888  $conf['allow'] = 'edit,new,delete,move,hide';
889  $panel = $this->pi_EPtemp_cObj->cObjGetSingle('EDITPANEL', $conf, 'editpanel');
890  }
891  if ($panel) {
892  if ($label) {
893  return '<!-- BEGIN: EDIT PANEL --><table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td valign="top">' . $label . '</td><td valign="top" align="right">' . $panel . '</td></tr></table><!-- END: EDIT PANEL -->';
894  } else {
895  return '<!-- BEGIN: EDIT PANEL -->' . $panel . '<!-- END: EDIT PANEL -->';
896  }
897  } else {
898  return $label;
899  }
900  }
901 
915  public function pi_getEditIcon($content, $fields, $title = '', $row = [], $tablename = '', $oConf = [])
916  {
917  if ($this->frontendController->beUserLogin) {
918  if (!$row || !$tablename) {
919  $row = $this->internal['currentRow'];
920  $tablename = $this->internal['currentTable'];
921  }
922  $conf = array_merge([
923  'beforeLastTag' => 1,
924  'iconTitle' => $title
925  ], $oConf);
926  $content = $this->cObj->editIcons($content, $tablename . ':' . $fields, $conf, $tablename . ':' . $row['uid'], $row, '&viewUrl=' . rawurlencode(GeneralUtility::getIndpEnv('REQUEST_URI')));
927  }
928  return $content;
929  }
930 
931  /***************************
932  *
933  * Localization, locallang functions
934  *
935  **************************/
945  public function pi_getLL($key, $alternativeLabel = '', $hsc = false)
946  {
947  $word = null;
948  if (!empty($this->LOCAL_LANG[$this->LLkey][$key][0]['target'])
949  || isset($this->LOCAL_LANG_UNSET[$this->LLkey][$key])
950  ) {
951  // The "from" charset of csConv() is only set for strings from TypoScript via _LOCAL_LANG
952  if (isset($this->LOCAL_LANG_charset[$this->LLkey][$key])) {
953  $word = $this->frontendController->csConv($this->LOCAL_LANG[$this->LLkey][$key][0]['target'], $this->LOCAL_LANG_charset[$this->LLkey][$key]);
954  } else {
955  $word = $this->LOCAL_LANG[$this->LLkey][$key][0]['target'];
956  }
957  } elseif ($this->altLLkey) {
958  $alternativeLanguageKeys = GeneralUtility::trimExplode(',', $this->altLLkey, true);
959  $alternativeLanguageKeys = array_reverse($alternativeLanguageKeys);
960  foreach ($alternativeLanguageKeys as $languageKey) {
961  if (!empty($this->LOCAL_LANG[$languageKey][$key][0]['target'])
962  || isset($this->LOCAL_LANG_UNSET[$languageKey][$key])
963  ) {
964  // Alternative language translation for key exists
965  $word = $this->LOCAL_LANG[$languageKey][$key][0]['target'];
966  // The "from" charset of csConv() is only set for strings from TypoScript via _LOCAL_LANG
967  if (isset($this->LOCAL_LANG_charset[$languageKey][$key])) {
968  $word = $this->frontendController->csConv(
969  $word,
970  $this->LOCAL_LANG_charset[$this->altLLkey][$key]
971  );
972  }
973  break;
974  }
975  }
976  }
977  if ($word === null) {
978  if (!empty($this->LOCAL_LANG['default'][$key][0]['target'])
979  || isset($this->LOCAL_LANG_UNSET['default'][$key])
980  ) {
981  // Get default translation (without charset conversion, english)
982  $word = $this->LOCAL_LANG['default'][$key][0]['target'];
983  } else {
984  // Return alternative string or empty
985  $word = isset($this->LLtestPrefixAlt) ? $this->LLtestPrefixAlt . $alternativeLabel : $alternativeLabel;
986  }
987  }
988  $output = isset($this->LLtestPrefix) ? $this->LLtestPrefix . $word : $word;
989  if ($hsc) {
990  $output = htmlspecialchars($output);
991  }
992  return $output;
993  }
994 
1006  public function pi_loadLL($languageFilePath = '')
1007  {
1008  if ($this->LOCAL_LANG_loaded) {
1009  return;
1010  }
1011 
1012  if ($languageFilePath === '' && $this->scriptRelPath) {
1013  $languageFilePath = 'EXT:' . $this->extKey . '/' . dirname($this->scriptRelPath) . '/locallang.xlf';
1014  }
1015  if ($languageFilePath !== '') {
1017  $languageFactory = GeneralUtility::makeInstance(LocalizationFactory::class);
1018  // Read the strings in the required charset (since TYPO3 4.2)
1019  $this->LOCAL_LANG = $languageFactory->getParsedData($languageFilePath, $this->LLkey, $this->frontendController->renderCharset);
1020  $alternativeLanguageKeys = GeneralUtility::trimExplode(',', $this->altLLkey, true);
1021  foreach ($alternativeLanguageKeys as $languageKey) {
1022  $tempLL = $languageFactory->getParsedData($languageFilePath, $languageKey);
1023  if ($this->LLkey !== 'default' && isset($tempLL[$languageKey])) {
1024  $this->LOCAL_LANG[$languageKey] = $tempLL[$languageKey];
1025  }
1026  }
1027  // Overlaying labels from TypoScript (including fictitious language keys for non-system languages!):
1028  if (isset($this->conf['_LOCAL_LANG.'])) {
1029  // Clear the "unset memory"
1030  $this->LOCAL_LANG_UNSET = [];
1031  foreach ($this->conf['_LOCAL_LANG.'] as $languageKey => $languageArray) {
1032  // Remove the dot after the language key
1033  $languageKey = substr($languageKey, 0, -1);
1034  // Don't process label if the language is not loaded
1035  if (is_array($languageArray) && isset($this->LOCAL_LANG[$languageKey])) {
1036  foreach ($languageArray as $labelKey => $labelValue) {
1037  if (!is_array($labelValue)) {
1038  $this->LOCAL_LANG[$languageKey][$labelKey][0]['target'] = $labelValue;
1039  if ($labelValue === '') {
1040  $this->LOCAL_LANG_UNSET[$languageKey][$labelKey] = '';
1041  }
1042  $this->LOCAL_LANG_charset[$languageKey][$labelKey] = 'utf-8';
1043  }
1044  }
1045  }
1046  }
1047  }
1048  }
1049  $this->LOCAL_LANG_loaded = 1;
1050  }
1051 
1052  /***************************
1053  *
1054  * Database, queries
1055  *
1056  **************************/
1071  public function pi_exec_query($table, $count = false, $addWhere = '', $mm_cat = '', $groupBy = '', $orderBy = '', $query = '')
1072  {
1073  // Begin Query:
1074  if (!$query) {
1075  // Fetches the list of PIDs to select from.
1076  // TypoScript property .pidList is a comma list of pids. If blank, current page id is used.
1077  // TypoScript property .recursive is an int+ which determines how many levels down from the pids in the pid-list subpages should be included in the select.
1078  $pidList = $this->pi_getPidList($this->conf['pidList'], $this->conf['recursive']);
1079  if (is_array($mm_cat)) {
1080  // This adds WHERE-clauses that ensures deleted, hidden, starttime/endtime/access records are NOT
1081  // selected, if they should not! Almost ALWAYS add this to your queries!
1082  $query = 'FROM ' . $table . ',' . $mm_cat['table'] . ',' . $mm_cat['mmtable'] . LF . ' WHERE ' . $table . '.uid=' . $mm_cat['mmtable'] . '.uid_local AND ' . $mm_cat['table'] . '.uid=' . $mm_cat['mmtable'] . '.uid_foreign ' . LF . (strcmp($mm_cat['catUidList'], '') ? ' AND ' . $mm_cat['table'] . '.uid IN (' . $mm_cat['catUidList'] . ')' : '') . LF . ' AND ' . $table . '.pid IN (' . $pidList . ')' . LF . $this->cObj->enableFields($table) . LF;
1083  } else {
1084  // This adds WHERE-clauses that ensures deleted, hidden, starttime/endtime/access records are NOT
1085  // selected, if they should not! Almost ALWAYS add this to your queries!
1086  $query = 'FROM ' . $table . ' WHERE pid IN (' . $pidList . ')' . LF . $this->cObj->enableFields($table) . LF;
1087  }
1088  }
1089  // Split the "FROM ... WHERE" string so we get the WHERE part and TABLE names separated...:
1090  list($TABLENAMES, $WHERE) = preg_split('/WHERE/i', trim($query), 2);
1091  $TABLENAMES = trim(substr(trim($TABLENAMES), 5));
1092  $WHERE = trim($WHERE);
1093  // Add '$addWhere'
1094  if ($addWhere) {
1095  $WHERE .= ' ' . $addWhere . LF;
1096  }
1097  // Search word:
1098  if ($this->piVars['sword'] && $this->internal['searchFieldList']) {
1099  $WHERE .= $this->cObj->searchWhere($this->piVars['sword'], $this->internal['searchFieldList'], $table) . LF;
1100  }
1101  if ($count) {
1102  $queryParts = [
1103  'SELECT' => 'count(*)',
1104  'FROM' => $TABLENAMES,
1105  'WHERE' => $WHERE,
1106  'GROUPBY' => '',
1107  'ORDERBY' => '',
1108  'LIMIT' => ''
1109  ];
1110  } else {
1111  // Order by data:
1112  if (!$orderBy && $this->internal['orderBy']) {
1113  if (GeneralUtility::inList($this->internal['orderByList'], $this->internal['orderBy'])) {
1114  $orderBy = 'ORDER BY ' . $table . '.' . $this->internal['orderBy'] . ($this->internal['descFlag'] ? ' DESC' : '');
1115  }
1116  }
1117  // Limit data:
1118  $pointer = (int)$this->piVars['pointer'];
1119  $results_at_a_time = MathUtility::forceIntegerInRange($this->internal['results_at_a_time'], 1, 1000);
1120  $LIMIT = $pointer * $results_at_a_time . ',' . $results_at_a_time;
1121  // Add 'SELECT'
1122  $queryParts = [
1123  'SELECT' => $this->pi_prependFieldsWithTable($table, $this->pi_listFields),
1124  'FROM' => $TABLENAMES,
1125  'WHERE' => $WHERE,
1126  'GROUPBY' => $this->databaseConnection->stripGroupBy($groupBy),
1127  'ORDERBY' => $this->databaseConnection->stripOrderBy($orderBy),
1128  'LIMIT' => $LIMIT
1129  ];
1130  }
1131  return $this->databaseConnection->exec_SELECT_queryArray($queryParts);
1132  }
1133 
1143  public function pi_getRecord($table, $uid, $checkPage = false)
1144  {
1145  return $this->frontendController->sys_page->checkRecord($table, $uid, $checkPage);
1146  }
1147 
1155  public function pi_getPidList($pid_list, $recursive = 0)
1156  {
1157  if (!strcmp($pid_list, '')) {
1158  $pid_list = $this->frontendController->id;
1159  }
1160  $recursive = MathUtility::forceIntegerInRange($recursive, 0);
1161  $pid_list_arr = array_unique(GeneralUtility::trimExplode(',', $pid_list, true));
1162  $pid_list = [];
1163  foreach ($pid_list_arr as $val) {
1164  $val = MathUtility::forceIntegerInRange($val, 0);
1165  if ($val) {
1166  $_list = $this->cObj->getTreeList(-1 * $val, $recursive);
1167  if ($_list) {
1168  $pid_list[] = $_list;
1169  }
1170  }
1171  }
1172  return implode(',', $pid_list);
1173  }
1174 
1182  public function pi_prependFieldsWithTable($table, $fieldList)
1183  {
1184  $list = GeneralUtility::trimExplode(',', $fieldList, true);
1185  $return = [];
1186  foreach ($list as $listItem) {
1187  $return[] = $table . '.' . $listItem;
1188  }
1189  return implode(',', $return);
1190  }
1191 
1203  public function pi_getCategoryTableContents($table, $pid, $whereClause = '', $groupBy = '', $orderBy = '', $limit = '')
1204  {
1205  $res = $this->databaseConnection->exec_SELECTquery('*', $table, 'pid=' . (int)$pid . $this->cObj->enableFields($table) . ' ' . $whereClause, $groupBy, $orderBy, $limit);
1206  $outArr = [];
1207  while ($row = $this->databaseConnection->sql_fetch_assoc($res)) {
1208  $outArr[$row['uid']] = $row;
1209  }
1210  $this->databaseConnection->sql_free_result($res);
1211  return $outArr;
1212  }
1213 
1214  /***************************
1215  *
1216  * Various
1217  *
1218  **************************/
1227  public function pi_isOnlyFields($fList, $lowerThan = -1)
1228  {
1229  $lowerThan = $lowerThan == -1 ? $this->pi_lowerThan : $lowerThan;
1230  $fList = GeneralUtility::trimExplode(',', $fList, true);
1231  $tempPiVars = $this->piVars;
1232  foreach ($fList as $k) {
1233  if (!MathUtility::canBeInterpretedAsInteger($tempPiVars[$k]) || $tempPiVars[$k] < $lowerThan) {
1234  unset($tempPiVars[$k]);
1235  }
1236  }
1237  if (empty($tempPiVars)) {
1238  //@TODO: How do we deal with this? return TRUE would be the right thing to do here but that might be breaking
1239  return 1;
1240  }
1241  return null;
1242  }
1243 
1253  public function pi_autoCache($inArray)
1254  {
1255  if (is_array($inArray)) {
1256  foreach ($inArray as $fN => $fV) {
1257  if (!strcmp($inArray[$fN], '')) {
1258  unset($inArray[$fN]);
1259  } elseif (is_array($this->pi_autoCacheFields[$fN])) {
1260  if (is_array($this->pi_autoCacheFields[$fN]['range']) && (int)$inArray[$fN] >= (int)$this->pi_autoCacheFields[$fN]['range'][0] && (int)$inArray[$fN] <= (int)$this->pi_autoCacheFields[$fN]['range'][1]) {
1261  unset($inArray[$fN]);
1262  }
1263  if (is_array($this->pi_autoCacheFields[$fN]['list']) && in_array($inArray[$fN], $this->pi_autoCacheFields[$fN]['list'])) {
1264  unset($inArray[$fN]);
1265  }
1266  }
1267  }
1268  }
1269  if (empty($inArray)) {
1270  //@TODO: How do we deal with this? return TRUE would be the right thing to do here but that might be breaking
1271  return 1;
1272  }
1273  return null;
1274  }
1275 
1285  public function pi_RTEcssText($str)
1286  {
1287  $parseFunc = $this->frontendController->tmpl->setup['lib.']['parseFunc_RTE.'];
1288  if (is_array($parseFunc)) {
1289  $str = $this->cObj->parseFunc($str, $parseFunc);
1290  }
1291  return $str;
1292  }
1293 
1294  /*******************************
1295  *
1296  * FlexForms related functions
1297  *
1298  *******************************/
1305  public function pi_initPIflexForm($field = 'pi_flexform')
1306  {
1307  // Converting flexform data into array:
1308  if (!is_array($this->cObj->data[$field]) && $this->cObj->data[$field]) {
1309  $this->cObj->data[$field] = GeneralUtility::xml2array($this->cObj->data[$field]);
1310  if (!is_array($this->cObj->data[$field])) {
1311  $this->cObj->data[$field] = [];
1312  }
1313  }
1314  }
1315 
1326  public function pi_getFFvalue($T3FlexForm_array, $fieldName, $sheet = 'sDEF', $lang = 'lDEF', $value = 'vDEF')
1327  {
1328  $sheetArray = is_array($T3FlexForm_array) ? $T3FlexForm_array['data'][$sheet][$lang] : '';
1329  if (is_array($sheetArray)) {
1330  return $this->pi_getFFvalueFromSheetArray($sheetArray, explode('/', $fieldName), $value);
1331  }
1332  return null;
1333  }
1334 
1345  public function pi_getFFvalueFromSheetArray($sheetArray, $fieldNameArr, $value)
1346  {
1347  $tempArr = $sheetArray;
1348  foreach ($fieldNameArr as $k => $v) {
1350  if (is_array($tempArr)) {
1351  $c = 0;
1352  foreach ($tempArr as $values) {
1353  if ($c == $v) {
1354  $tempArr = $values;
1355  break;
1356  }
1357  $c++;
1358  }
1359  }
1360  } else {
1361  $tempArr = $tempArr[$v];
1362  }
1363  }
1364  return $tempArr[$value];
1365  }
1366 }
pi_getFFvalue($T3FlexForm_array, $fieldName, $sheet='sDEF', $lang='lDEF', $value='vDEF')
static forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:31
pi_getEditIcon($content, $fields, $title='', $row=[], $tablename='', $oConf=[])
pi_getRecord($table, $uid, $checkPage=false)
applyStdWrapRecursive(array $conf, $level=0)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
pi_linkTP_keepPIvars_url($overrulePIvars=[], $cache=false, $clearAnyway=false, $altPageId=0)
pi_linkTP_keepPIvars($str, $overrulePIvars=[], $cache=false, $clearAnyway=false, $altPageId=0)
pi_list_modeSelector($items=[], $tableParams='')
static implodeArrayForUrl($name, array $theArray, $str='', $skipBlank=false, $rawurlencodeParamName=false)
pi_getPageLink($id, $target='', $urlParameters=[])
pi_getCategoryTableContents($table, $pid, $whereClause='', $groupBy='', $orderBy='', $limit='')
static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
pi_exec_query($table, $count=false, $addWhere='', $mm_cat='', $groupBy='', $orderBy='', $query='')
static xml2array($string, $NSprefix='', $reportDocTag=false)
$uid
Definition: server.php:38
pi_getFFvalueFromSheetArray($sheetArray, $fieldNameArr, $value)
pi_getEditPanel($row=[], $tablename='', $label='', $conf=[])
pi_list_browseresults($showResultCount=1, $tableParams='', $wrapArr=[], $pointerName='pointer', $hscText=true, $forceOutput=false)
pi_linkTP($str, $urlParameters=[], $cache=false, $altPageId=0)
pi_list_linkSingle($str, $uid, $cache=false, $mergeArr=[], $urlOnly=false, $altPageId=0)
pi_getLL($key, $alternativeLabel='', $hsc=false)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
$locales
Definition: be_users.php:6
pi_linkToPage($str, $id, $target='', $urlParameters=[])
pi_openAtagHrefInJSwindow($str, $winName='', $winParams='width=670, height=500, status=0, menubar=0, scrollbars=1, resizable=1')