‪TYPO3CMS  ‪main
ContentObjectRenderer.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 Doctrine\DBAL\Exception as DBALException;
19 use Doctrine\DBAL\Result;
20 use Psr\Container\ContainerInterface;
21 use Psr\EventDispatcher\EventDispatcherInterface;
22 use Psr\Http\Message\ServerRequestInterface;
23 use Psr\Log\LoggerAwareInterface;
24 use Psr\Log\LoggerAwareTrait;
25 use Psr\Log\LogLevel;
44 use TYPO3\CMS\Core\Imaging\ImageResource;
89 use TYPO3\CMS\Frontend\Typolink\LinkResult;
93 use TYPO3\HtmlSanitizer\Builder\BuilderInterface;
94 
102 class ‪ContentObjectRenderer implements LoggerAwareInterface
103 {
104  use LoggerAwareTrait;
106 
110  protected ‪$container;
111 
118  public array ‪$stdWrapOrder = [
119  BeforeStdWrapFunctionsInitializedEvent::class => 'event',
120  'cacheRead' => 'hook', // this is a placeholder for checking if the content is available in cache
121  'setContentToCurrent' => 'boolean',
122  'setContentToCurrent.' => 'array',
123  'addPageCacheTags' => 'string',
124  'addPageCacheTags.' => 'array',
125  'setCurrent' => 'string',
126  'setCurrent.' => 'array',
127  'lang.' => 'array',
128  'data' => 'getText',
129  'data.' => 'array',
130  'field' => 'fieldName',
131  'field.' => 'array',
132  'current' => 'boolean',
133  'current.' => 'array',
134  'cObject' => 'cObject',
135  'cObject.' => 'array',
136  'numRows.' => 'array',
137  'preUserFunc' => 'functionName',
138  AfterStdWrapFunctionsInitializedEvent::class => 'event',
139  'override' => 'string',
140  'override.' => 'array',
141  'preIfEmptyListNum' => 'listNum',
142  'preIfEmptyListNum.' => 'array',
143  'ifNull' => 'string',
144  'ifNull.' => 'array',
145  'ifEmpty' => 'string',
146  'ifEmpty.' => 'array',
147  'ifBlank' => 'string',
148  'ifBlank.' => 'array',
149  'listNum' => 'listNum',
150  'listNum.' => 'array',
151  'trim' => 'boolean',
152  'trim.' => 'array',
153  'strPad.' => 'array',
154  'stdWrap' => 'stdWrap',
155  'stdWrap.' => 'array',
156  BeforeStdWrapFunctionsExecutedEvent::class => 'event',
157  'required' => 'boolean',
158  'required.' => 'array',
159  'if.' => 'array',
160  'fieldRequired' => 'fieldName',
161  'fieldRequired.' => 'array',
162  'csConv' => 'string',
163  'csConv.' => 'array',
164  'parseFunc' => 'objectpath',
165  'parseFunc.' => 'array',
166  'HTMLparser' => 'boolean',
167  'HTMLparser.' => 'array',
168  'split.' => 'array',
169  'replacement.' => 'array',
170  'prioriCalc' => 'boolean',
171  'prioriCalc.' => 'array',
172  'char' => 'integer',
173  'char.' => 'array',
174  'intval' => 'boolean',
175  'intval.' => 'array',
176  'hash' => 'string',
177  'hash.' => 'array',
178  'round' => 'boolean',
179  'round.' => 'array',
180  'numberFormat.' => 'array',
181  'expandList' => 'boolean',
182  'expandList.' => 'array',
183  'date' => 'dateconf',
184  'date.' => 'array',
185  'strtotime' => 'strtotimeconf',
186  'strtotime.' => 'array',
187  'strftime' => 'strftimeconf',
188  'strftime.' => 'array',
189  'formattedDate' => 'formattedDateconf',
190  'formattedDate.' => 'array',
191  'age' => 'boolean',
192  'age.' => 'array',
193  'case' => 'case',
194  'case.' => 'array',
195  'bytes' => 'boolean',
196  'bytes.' => 'array',
197  'substring' => 'parameters',
198  'substring.' => 'array',
199  'cropHTML' => 'crop',
200  'cropHTML.' => 'array',
201  'stripHtml' => 'boolean',
202  'stripHtml.' => 'array',
203  'crop' => 'crop',
204  'crop.' => 'array',
205  'rawUrlEncode' => 'boolean',
206  'rawUrlEncode.' => 'array',
207  'htmlSpecialChars' => 'boolean',
208  'htmlSpecialChars.' => 'array',
209  'encodeForJavaScriptValue' => 'boolean',
210  'encodeForJavaScriptValue.' => 'array',
211  'doubleBrTag' => 'string',
212  'doubleBrTag.' => 'array',
213  'br' => 'boolean',
214  'br.' => 'array',
215  'brTag' => 'string',
216  'brTag.' => 'array',
217  'encapsLines.' => 'array',
218  'keywords' => 'boolean',
219  'keywords.' => 'array',
220  'innerWrap' => 'wrap',
221  'innerWrap.' => 'array',
222  'innerWrap2' => 'wrap',
223  'innerWrap2.' => 'array',
224  'preCObject' => 'cObject',
225  'preCObject.' => 'array',
226  'postCObject' => 'cObject',
227  'postCObject.' => 'array',
228  'wrapAlign' => 'align',
229  'wrapAlign.' => 'array',
230  'typolink.' => 'array',
231  'wrap' => 'wrap',
232  'wrap.' => 'array',
233  'noTrimWrap' => 'wrap',
234  'noTrimWrap.' => 'array',
235  'wrap2' => 'wrap',
236  'wrap2.' => 'array',
237  'dataWrap' => 'dataWrap',
238  'dataWrap.' => 'array',
239  'prepend' => 'cObject',
240  'prepend.' => 'array',
241  'append' => 'cObject',
242  'append.' => 'array',
243  'wrap3' => 'wrap',
244  'wrap3.' => 'array',
245  'orderedStdWrap' => 'stdWrap',
246  'orderedStdWrap.' => 'array',
247  'outerWrap' => 'wrap',
248  'outerWrap.' => 'array',
249  'insertData' => 'boolean',
250  'insertData.' => 'array',
251  'postUserFunc' => 'functionName',
252  'postUserFuncInt' => 'functionName',
253  'prefixComment' => 'string',
254  'prefixComment.' => 'array',
255  'htmlSanitize' => 'boolean',
256  'htmlSanitize.' => 'array',
257  'cacheStore' => 'hook', // this is a placeholder for storing the content in cache
258  AfterStdWrapFunctionsExecutedEvent::class => 'event',
259  'debug' => 'boolean',
260  'debug.' => 'array',
261  'debugFunc' => 'boolean',
262  'debugFunc.' => 'array',
263  'debugData' => 'boolean',
264  'debugData.' => 'array',
265  ];
266 
276  public ‪$data = [];
277 
281  protected ‪$table = '';
282 
288  public ‪$parameters = [];
289 
293  public ‪$currentValKey = 'currentValue_kidjls9dksoje';
294 
301  public ‪$currentRecord = '';
302 
308  public ‪$currentRecordNumber = 0;
309 
315  public ‪$parentRecordNumber = 0;
316 
322  public ‪$parentRecord = [];
323 
329 
331 
335  protected ‪$currentFile;
336 
341  public ‪$doConvertToUserIntObject = false;
342 
349  protected ‪$userObjectType = false;
350 
354  protected ‪$stopRendering = [];
355 
359  protected ‪$stdWrapRecursionLevel = 0;
360 
365 
369  private ?ServerRequestInterface ‪$request = null;
370 
376  public const ‪OBJECTTYPE_USER_INT = 1;
382  public const ‪OBJECTTYPE_USER = 2;
383 
384  public function ‪__construct(?‪TypoScriptFrontendController ‪$typoScriptFrontendController = null, ?ContainerInterface ‪$container = null)
385  {
386  $this->typoScriptFrontendController = ‪$typoScriptFrontendController;
387  $this->container = ‪$container;
388  }
389 
390  public function ‪setRequest(ServerRequestInterface ‪$request): void
391  {
392  $this->request = ‪$request;
393  }
394 
402  public function ‪__sleep()
403  {
404  $vars = get_object_vars($this);
405  unset($vars['typoScriptFrontendController'], $vars['logger'], $vars['container'], $vars['request']);
406  if ($this->currentFile instanceof ‪FileReference) {
407  $this->currentFile = 'FileReference:' . $this->currentFile->getUid();
408  } elseif ($this->currentFile instanceof ‪File) {
409  $this->currentFile = 'File:' . $this->currentFile->getIdentifier();
410  } else {
411  unset($vars['currentFile']);
412  }
413  return array_keys($vars);
414  }
415 
421  public function ‪__wakeup()
422  {
423  if (isset(‪$GLOBALS['TSFE'])) {
424  $this->typoScriptFrontendController = ‪$GLOBALS['TSFE'];
425  }
426  if (is_string($this->currentFile)) {
427  [$objectType, ‪$identifier] = explode(':', $this->currentFile, 2);
428  try {
429  if ($objectType === 'File') {
430  $this->currentFile = GeneralUtility::makeInstance(ResourceFactory::class)->retrieveFileOrFolderObject(‪$identifier);
431  } elseif ($objectType === 'FileReference') {
432  $this->currentFile = GeneralUtility::makeInstance(ResourceFactory::class)->getFileReferenceObject((int)‪$identifier);
433  }
434  } catch (ResourceDoesNotExistException $e) {
435  $this->currentFile = null;
436  }
437  }
438  $this->logger = GeneralUtility::makeInstance(LogManager::class)->getLogger(__CLASS__);
439  $this->container = GeneralUtility::getContainer();
440 
441  // We do not derive $this->request from globals here. The request is expected to be injected
442  // using setRequest(), a fallback to $GLOBALS['TYPO3_REQUEST'] is available in getRequest() for BC.
443  }
444 
453  public function ‪start(‪$data, ‪$table = '')
454  {
455  $this->data = ‪$data;
456  $this->table = ‪$table;
457  $this->currentRecord = ‪$table !== ''
458  ? ‪$table . ':' . ($this->data['uid'] ?? '')
459  : '';
460  $this->parameters = [];
461 
462  GeneralUtility::makeInstance(EventDispatcherInterface::class)->dispatch(
464  );
465  }
466 
472  public function ‪getCurrentTable()
473  {
474  return ‪$this->table;
475  }
476 
485  public function ‪setParent(‪$data, ‪$currentRecord)
486  {
487  $this->parentRecord = [
488  'data' => ‪$data,
489  'currentRecord' => ‪$currentRecord,
490  ];
491  }
492 
493  /***********************************************
494  *
495  * CONTENT_OBJ:
496  *
497  ***********************************************/
506  public function ‪getCurrentVal()
507  {
508  return $this->data[‪$this->currentValKey] ?? null;
509  }
510 
517  public function ‪setCurrentVal($value)
518  {
519  $this->data[‪$this->currentValKey] = $value;
520  }
521 
531  public function ‪cObjGet($setup, $addKey = '')
532  {
533  if (!is_array($setup)) {
534  return '';
535  }
536  return implode('', $this->‪cObjGetSeparated($setup, $addKey));
537  }
538 
545  public function ‪cObjGetSeparated(?array $setup, string $addKey = ''): array
546  {
547  if ($setup === null || $setup === []) {
548  return [];
549  }
550  $sKeyArray = ArrayUtility::filterAndSortByNumericKeys($setup);
551  $contentObjects = [];
552  foreach ($sKeyArray as $theKey) {
553  $theValue = $setup[$theKey];
554  if ((int)$theKey && !str_contains($theKey, '.')) {
555  $conf = $setup[$theKey . '.'] ?? [];
556  $contentObjects[] = $this->‪cObjGetSingle($theValue, $conf, $addKey . $theKey);
557  }
558  }
559  return $contentObjects;
560  }
561 
571  public function ‪cObjGetSingle(string ‪$name, $conf, $TSkey = '__')
572  {
573  $timeTracker = $this->‪getTimeTracker();
574  $name = trim(‪$name);
575  if ($timeTracker->LR) {
576  $timeTracker->push($TSkey, ‪$name);
577  }
578  $fullConfigArray = [
579  'tempKey' => ‪$name,
580  'tempKey.' => is_array($conf) ? $conf : [],
581  ];
582  // Resolve '=<' operator if needed
583  $fullConfigArray = $this->‪mergeTSRef($fullConfigArray, 'tempKey');
584  $contentObject = $this->‪getContentObject($fullConfigArray['tempKey']);
585  $content = '';
586  if ($contentObject) {
587  $content = $this->‪render($contentObject, $fullConfigArray['tempKey.']);
588  }
589  if ($timeTracker->LR) {
590  $timeTracker->pull($content);
591  }
592  return $content;
593  }
594 
601  public function ‪getContentObject(‪$name): ?AbstractContentObject
602  {
603  $contentObjectFactory = $this->container
604  ? $this->container->get(ContentObjectFactory::class)
605  : GeneralUtility::makeInstance(ContentObjectFactory::class);
606  return $contentObjectFactory->getContentObject(‪$name, $this->‪getRequest(), $this);
607  }
608 
609  /********************************************
610  *
611  * Functions rendering content objects (cObjects)
612  *
613  ********************************************/
624  public function ‪render(‪AbstractContentObject $contentObject, $configuration = []): string
625  {
626  $content = '';
627 
628  // Evaluate possible cache and return
629  $cacheConfiguration = $configuration['cache.'] ?? null;
630  if ($cacheConfiguration !== null) {
631  unset($configuration['cache.']);
632  $cache = $this->‪getFromCache($cacheConfiguration);
633  if ($cache !== false) {
634  return $cache;
635  }
636  }
637 
638  // Render content
639  try {
640  $content .= $contentObject->‪render($configuration);
641  } catch (‪ContentRenderingException $exception) {
642  // Content rendering Exceptions indicate a critical problem which should not be
643  // caught e.g. when something went wrong with Exception handling itself
644  throw $exception;
645  } catch (\Throwable $exception) {
646  $exceptionHandler = $this->‪createExceptionHandler($configuration);
647  if ($exceptionHandler === null) {
648  throw $exception;
649  }
650  // Ensure that the exception handler receives an \Exception instance,
651  // which is required by the \ExceptionHandlerInterface.
652  if (!$exception instanceof \‪Exception) {
653  $exception = new \Exception($exception->getMessage(), 1698347363, $exception);
654  }
655  $content = $exceptionHandler->handle($exception, $contentObject, $configuration);
656  }
657 
658  // Store cache
659  if ($cacheConfiguration !== null && $this->‪getRequest()->getAttribute('frontend.cache.instruction')->isCachingAllowed()) {
660  $key = $this->‪calculateCacheKey($cacheConfiguration);
661  if (!empty($key)) {
662  $cacheFrontend = GeneralUtility::makeInstance(CacheManager::class)->getCache('hash');
663  $tags = $this->‪calculateCacheTags($cacheConfiguration);
664  $lifetime = $this->‪calculateCacheLifetime($cacheConfiguration);
665  $cachedData = [
666  'content' => $content,
667  'cacheTags' => $tags,
668  ];
669  $cacheFrontend->set($key, $cachedData, $tags, $lifetime);
670  $this->‪getTypoScriptFrontendController()->addCacheTags($tags);
671  }
672  }
673 
674  return $content;
675  }
676 
683  protected function ‪createExceptionHandler(array $configuration): ?ExceptionHandlerInterface
684  {
685  $exceptionHandler = null;
686  $exceptionHandlerClassName = $this->‪determineExceptionHandlerClassName($configuration);
687  if (!empty($exceptionHandlerClassName)) {
688  $exceptionHandler = GeneralUtility::makeInstance($exceptionHandlerClassName);
689  if (!$exceptionHandler instanceof ‪ExceptionHandlerInterface) {
690  throw new ‪ContentRenderingException('An exception handler was configured but the class does not exist or does not implement the ExceptionHandlerInterface', 1403653369);
691  }
692  $exceptionHandler->setConfiguration($this->‪mergeExceptionHandlerConfiguration($configuration));
693  }
694  return $exceptionHandler;
695  }
696 
700  protected function ‪determineExceptionHandlerClassName(array $configuration): ?string
701  {
702  $typoScriptConfigArray = $this->‪getRequest()->getAttribute('frontend.typoscript')->getConfigArray();
703  $exceptionHandlerClassName = null;
704  if (!isset($typoScriptConfigArray['contentObjectExceptionHandler'])) {
705  if (‪Environment::getContext()->isProduction()) {
706  $exceptionHandlerClassName = '1';
707  }
708  } else {
709  $exceptionHandlerClassName = $typoScriptConfigArray['contentObjectExceptionHandler'];
710  }
711  if (isset($configuration['exceptionHandler'])) {
712  $exceptionHandlerClassName = $configuration['exceptionHandler'];
713  }
714  if ($exceptionHandlerClassName === '1') {
715  $exceptionHandlerClassName = ProductionExceptionHandler::class;
716  }
717  return $exceptionHandlerClassName;
718  }
719 
724  protected function ‪mergeExceptionHandlerConfiguration(array $configuration): array
725  {
726  $exceptionHandlerConfiguration = [];
727  $typoScriptConfigArray = $this->‪getRequest()->getAttribute('frontend.typoscript')->getConfigArray();
728  if (!empty($typoScriptConfigArray['contentObjectExceptionHandler.'])) {
729  $exceptionHandlerConfiguration = $typoScriptConfigArray['contentObjectExceptionHandler.'];
730  }
731  if (!empty($configuration['exceptionHandler.'])) {
732  $exceptionHandlerConfiguration = array_replace_recursive($exceptionHandlerConfiguration, $configuration['exceptionHandler.']);
733  }
734  return $exceptionHandlerConfiguration;
735  }
736 
745  public function ‪getUserObjectType()
746  {
748  }
749 
756  {
757  $this->userObjectType = ‪$userObjectType;
758  }
759 
763  public function ‪convertToUserIntObject()
764  {
765  if ($this->userObjectType !== self::OBJECTTYPE_USER) {
766  $this->‪getTimeTracker()->‪setTSlogMessage(self::class . '::convertToUserIntObject() is called in the wrong context or for the wrong object type', LogLevel::WARNING);
767  } else {
768  $this->doConvertToUserIntObject = true;
769  }
770  }
771 
772  /************************************
773  *
774  * Various helper functions for content objects:
775  *
776  ************************************/
784  public function ‪readFlexformIntoConf($flexData, &$conf, $recursive = false)
785  {
786  if ($recursive === false && is_string($flexData)) {
787  $flexData = ‪GeneralUtility::xml2array($flexData, 'T3');
788  }
789  if (is_array($flexData) && isset($flexData['data']['sDEF']['lDEF'])) {
790  $flexData = $flexData['data']['sDEF']['lDEF'];
791  }
792  if (!is_array($flexData)) {
793  return;
794  }
795  foreach ($flexData as $key => $value) {
796  if (!is_array($value)) {
797  continue;
798  }
799  if (isset($value['el'])) {
800  if (is_array($value['el']) && !empty($value['el'])) {
801  foreach ($value['el'] as $ekey => $element) {
802  if (isset($element['vDEF'])) {
803  $conf[$ekey] = $element['vDEF'];
804  } else {
805  if (is_array($element)) {
806  $this->‪readFlexformIntoConf($element, $conf[$key][key($element)][$ekey], true);
807  } else {
808  $this->‪readFlexformIntoConf($element, $conf[$key][$ekey], true);
809  }
810  }
811  }
812  } else {
813  $this->‪readFlexformIntoConf($value['el'], $conf[$key], true);
814  }
815  }
816  if (isset($value['vDEF'])) {
817  $conf[$key] = $value['vDEF'];
818  }
819  }
820  }
821 
830  public function ‪getSlidePids($pidList, $pidConf): string
831  {
832  // todo: phpstan states that $pidConf always exists and is not nullable. At the moment, this is a false positive
833  // as null can be passed into this method via $pidConf. As soon as more strict types are used, this isset
834  // check must be replaced with a more appropriate check like empty or count.
835  $pidList = isset($pidConf) ? trim((string)$this->‪stdWrap($pidList, $pidConf)) : trim($pidList);
836  if ($pidList === '') {
837  $pidList = 'this';
838  }
839  $pageRepository = $this->‪getPageRepository();
840  $listArr = null;
841  if (trim($pidList)) {
842  $contentPid = $this->‪getRequest()->getAttribute('frontend.page.information')->getContentFromPid();
843  $listArr = ‪GeneralUtility::intExplode(',', str_replace('this', (string)$contentPid, $pidList));
844  $listArr = $this->‪checkPidArray($listArr);
845  }
846  $pidList = [];
847  if (is_array($listArr) && !empty($listArr)) {
848  foreach ($listArr as ‪$uid) {
849  $page = $pageRepository->getPage((int)‪$uid);
850  if (!$page['is_siteroot']) {
851  $pidList[] = $page['pid'];
852  }
853  }
854  }
855  return implode(',', $pidList);
856  }
857 
867  public function ‪imageLinkWrap($string, $imageFile, $conf)
868  {
869  $string = (string)$string;
870  $enable = $this->‪stdWrapValue('enable', $conf ?? []);
871  if (!$enable) {
872  return $string;
873  }
874  $content = (string)$this->‪typoLink($string, $conf['typolink.'] ?? []);
875  if (isset($conf['file.']) && is_scalar($imageFile)) {
876  $imageFile = $this->‪stdWrap((string)$imageFile, $conf['file.']);
877  }
878 
879  if ($imageFile instanceof File) {
880  $file = $imageFile;
881  } elseif ($imageFile instanceof FileReference) {
882  $file = $imageFile->getOriginalFile();
883  } else {
885  $file = GeneralUtility::makeInstance(ResourceFactory::class)->getFileObject((int)$imageFile);
886  } else {
887  $file = GeneralUtility::makeInstance(ResourceFactory::class)->getFileObjectFromCombinedIdentifier($imageFile);
888  }
889  }
890 
891  // Create imageFileLink if not created with typolink
892  if ($content === $string && $file !== null) {
893  $parameterNames = ['width', 'height', 'effects', 'bodyTag', 'title', 'wrap', 'crop'];
894  ‪$parameters = [];
895  $sample = $this->‪stdWrapValue('sample', $conf ?? []);
896  if ($sample) {
897  ‪$parameters['sample'] = 1;
898  }
899  foreach ($parameterNames as $parameterName) {
900  if (isset($conf[$parameterName . '.'])) {
901  $conf[$parameterName] = $this->‪stdWrap($conf[$parameterName] ?? '', $conf[$parameterName . '.'] ?? []);
902  }
903  if (isset($conf[$parameterName]) && $conf[$parameterName]) {
904  ‪$parameters[$parameterName] = $conf[$parameterName];
905  }
906  }
907  $parametersEncoded = base64_encode((string)json_encode(‪$parameters));
908  $hashService = GeneralUtility::makeInstance(HashService::class);
909  $hmac = $hashService->hmac(implode('|', [$file->getUid(), $parametersEncoded]), 'tx_cms_showpic');
910  $params = '&md5=' . $hmac;
911  foreach (str_split($parametersEncoded, 64) as $index => $chunk) {
912  $params .= '&parameters' . rawurlencode('[') . $index . rawurlencode(']') . '=' . rawurlencode($chunk);
913  }
914  ‪$url = $this->‪getTypoScriptFrontendController()->absRefPrefix . 'index.php?eID=tx_cms_showpic&file=' . $file->getUid() . $params;
915  $directImageLink = $this->‪stdWrapValue('directImageLink', $conf ?? []);
916  if ($directImageLink) {
917  $imgResourceConf = [
918  'file' => $imageFile,
919  'file.' => $conf,
920  ];
921  ‪$url = $this->‪cObjGetSingle('IMG_RESOURCE', $imgResourceConf);
922  if (!‪$url) {
923  // If no imagemagick / gm is available
924  ‪$url = $imageFile;
925  }
926  }
927  $target = (string)$this->‪stdWrapValue('target', $conf ?? []);
928  if ($target === '') {
929  $target = 'thePicture';
930  }
931  $a1 = '';
932  $a2 = '';
933  $conf['JSwindow'] = $this->‪stdWrapValue('JSwindow', $conf ?? []);
934  if ($conf['JSwindow']) {
935  $altUrl = $this->‪stdWrapValue('altUrl', $conf['JSwindow.'] ?? []);
936  if ($altUrl) {
937  ‪$url = $altUrl . (($conf['JSwindow.']['altUrl_noDefaultParams'] ?? false) ? '' : '?file=' . rawurlencode((string)$imageFile) . $params);
938  }
939 
940  $processedFile = $file->process(‪ProcessedFile::CONTEXT_IMAGECROPSCALEMASK, $conf);
941  $JSwindowExpand = $this->‪stdWrapValue('expand', $conf['JSwindow.'] ?? []);
942  $offset = ‪GeneralUtility::intExplode(',', $JSwindowExpand . ',');
943  $newWindow = $this->‪stdWrapValue('newWindow', $conf['JSwindow.'] ?? []);
944  $params = [
945  'width' => ($processedFile->getProperty('width') + $offset[0]),
946  'height' => ($processedFile->getProperty('height') + $offset[1]),
947  'status' => '0',
948  'menubar' => '0',
949  ];
950  // params override existing parameters from above, or add more
951  $windowParams = (string)$this->‪stdWrapValue('params', $conf['JSwindow.'] ?? []);
952  $windowParams = explode(',', $windowParams);
953  foreach ($windowParams as $windowParam) {
954  $windowParamParts = explode('=', $windowParam);
955  $paramKey = $windowParamParts[0];
956  $paramValue = $windowParamParts[1] ?? null;
957 
958  if ($paramKey === '') {
959  continue;
960  }
961 
962  if ($paramValue !== '') {
963  $params[$paramKey] = $paramValue;
964  } else {
965  unset($params[$paramKey]);
966  }
967  }
968  $paramString = '';
969  foreach ($params as $paramKey => $paramValue) {
970  $paramString .= htmlspecialchars($paramKey) . '=' . htmlspecialchars((string)$paramValue) . ',';
971  }
972 
973  $attrs = [
974  'href' => (string)‪$url,
975  'data-window-url' => ‪$url,
976  'data-window-target' => $newWindow ? md5((string)‪$url) : 'thePicture',
977  'data-window-features' => rtrim($paramString, ','),
978  ];
979  if ($target !== '') {
980  $attrs['target'] = $target;
981  }
982 
983  $typoScriptConfigArray = $this->‪getRequest()->getAttribute('frontend.typoscript')->getConfigArray();
984  $a1 = sprintf(
985  '<a %s%s>',
986  GeneralUtility::implodeAttributes($attrs, true),
987  trim($typoScriptConfigArray['ATagParams'] ?? '') ? ' ' . trim($typoScriptConfigArray['ATagParams']) : ''
988  );
989  $a2 = '</a>';
990  $this->addDefaultFrontendJavaScript($this->‪getRequest());
991  } else {
992  $conf['linkParams.']['directImageLink'] = (bool)($conf['directImageLink'] ?? false);
993  $conf['linkParams.']['parameter'] = ‪$url;
994  $string = (string)$this->‪typoLink($string, $conf['linkParams.']);
995  }
996  if (isset($conf['stdWrap.'])) {
997  $string = (string)$this->‪stdWrap($string, $conf['stdWrap.']);
998  }
999  $content = $a1 . $string . $a2;
1000  }
1001  return $content;
1002  }
1003 
1012  public function ‪lastChanged($tstamp)
1013  {
1014  $tstamp = (int)$tstamp;
1015  $tsfe = $this->‪getTypoScriptFrontendController();
1016  if ($tstamp > (int)($tsfe->register['SYS_LASTCHANGED'] ?? 0)) {
1017  $tsfe->register['SYS_LASTCHANGED'] = $tstamp;
1018  }
1019  }
1020 
1021  /***********************************************
1022  *
1023  * HTML template processing functions
1024  *
1025  ***********************************************/
1032  public function ‪setCurrentFile($fileObject)
1033  {
1034  $this->currentFile = $fileObject;
1035  }
1036 
1042  public function ‪getCurrentFile()
1043  {
1044  return ‪$this->currentFile;
1045  }
1046 
1047  /***********************************************
1048  *
1049  * "stdWrap" + sub functions
1050  *
1051  ***********************************************/
1061  public function ‪stdWrap($content = '', $conf = [])
1062  {
1063  $content = (string)$content;
1064  if (!is_array($conf) || !$conf) {
1065  return $content;
1066  }
1067 
1068  // Activate the stdWrap PSR-14 Events - They will be executed
1069  // as stdWrap functions, based on the defined "stdWrapOrder".
1070  $conf[BeforeStdWrapFunctionsInitializedEvent::class] = 1;
1071  $conf[AfterStdWrapFunctionsInitializedEvent::class] = 1;
1072  $conf[BeforeStdWrapFunctionsExecutedEvent::class] = 1;
1073  $conf[AfterStdWrapFunctionsExecutedEvent::class] = 1;
1074  $eventDispatcher = GeneralUtility::makeInstance(EventDispatcherInterface::class);
1075 
1076  // Cache handling
1077  if (isset($conf['cache.']) && is_array($conf['cache.'])) {
1078  $conf['cache.']['key'] = $this->‪stdWrapValue('key', $conf['cache.'] ?? []);
1079  $conf['cache.']['tags'] = $this->‪stdWrapValue('tags', $conf['cache.'] ?? []);
1080  $conf['cache.']['lifetime'] = $this->‪stdWrapValue('lifetime', $conf['cache.'] ?? []);
1081  $conf['cacheRead'] = 1;
1082  $conf['cacheStore'] = 1;
1083  }
1084  // The configuration is sorted and filtered by intersection with the defined stdWrapOrder.
1085  $sortedConf = array_keys(array_intersect_key($this->stdWrapOrder, $conf));
1086  // Functions types that should not make use of nested stdWrap function calls to avoid conflicts with internal TypoScript used by these functions
1087  $stdWrapDisabledFunctionTypes = 'cObject,functionName,stdWrap';
1088  // Additional Array to check whether a function has already been executed
1089  $isExecuted = [];
1090  // Additional switch to make sure 'required', 'if' and 'fieldRequired'
1091  // will still stop rendering immediately in case they return FALSE
1092  $this->stdWrapRecursionLevel++;
1093  $this->stopRendering[‪$this->stdWrapRecursionLevel] = false;
1094  // execute each function in the predefined order
1095  foreach ($sortedConf as $stdWrapName) {
1096  // eliminate the second key of a pair 'key'|'key.' to make sure functions get called only once and check if rendering has been stopped
1097  if ((!isset($isExecuted[$stdWrapName]) || !$isExecuted[$stdWrapName]) && !$this->stopRendering[$this->stdWrapRecursionLevel]) {
1098  $functionName = rtrim($stdWrapName, '.');
1099  $functionProperties = $functionName . '.';
1100  $functionType = $this->stdWrapOrder[$functionName] ?? '';
1101  // If there is any code on the next level, check if it contains "official" stdWrap functions
1102  // if yes, execute them first - will make each function stdWrap aware
1103  // so additional stdWrap calls within the functions can be removed, since the result will be the same
1104  if (!empty($conf[$functionProperties]) && !‪GeneralUtility::inList($stdWrapDisabledFunctionTypes, $functionType)) {
1105  if (array_intersect_key($this->stdWrapOrder, $conf[$functionProperties])) {
1106  // Check if there's already content available before processing
1107  // any ifEmpty or ifBlank stdWrap properties
1108  if (($functionName === 'ifBlank' && $content !== '') ||
1109  ($functionName === 'ifEmpty' && !empty(trim((string)$content)))) {
1110  continue;
1111  }
1112 
1113  $conf[$functionName] = $this->‪stdWrap($conf[$functionName] ?? '', $conf[$functionProperties]);
1114  }
1115  }
1116  // Check if key is still containing something, since it might have been changed by next level stdWrap before
1117  if ((isset($conf[$functionName]) || ($conf[$functionProperties] ?? null))
1118  && ($functionType !== 'boolean' || ($conf[$functionName] ?? null))
1119  ) {
1120  // Get just that part of $conf that is needed for the particular function
1121  $singleConf = [
1122  $functionName => $conf[$functionName] ?? null,
1123  $functionProperties => $conf[$functionProperties] ?? null,
1124  ];
1125  // Hand over the whole $conf array to the hooks
1126  if ($functionType === 'hook') {
1127  $singleConf = $conf;
1128  }
1129  // Add both keys - with and without the dot - to the set of executed functions
1130  $isExecuted[$functionName] = true;
1131  $isExecuted[$functionProperties] = true;
1132  if ($functionType === 'event') {
1133  $content = $eventDispatcher->dispatch(
1134  new $functionName($content, $conf, $this)
1135  )->getContent();
1136  } else {
1137  // Call the function with the prefix stdWrap_ to make sure nobody can execute functions just by adding their name to the TS Array
1138  $functionName = 'stdWrap_' . $functionName;
1139  $content = $this->{$functionName}($content, $singleConf);
1140  }
1141  } elseif ($functionType === 'boolean' && !($conf[$functionName] ?? null)) {
1142  $isExecuted[$functionName] = true;
1143  $isExecuted[$functionProperties] = true;
1144  }
1145  }
1146  }
1147  unset($this->stopRendering[$this->stdWrapRecursionLevel]);
1148  $this->stdWrapRecursionLevel--;
1149 
1150  return $content;
1151  }
1152 
1161  public function ‪stdWrapValue($key, array $config, $defaultValue = '')
1162  {
1163  if (isset($config[$key])) {
1164  if (!isset($config[$key . '.'])) {
1165  return $config[$key];
1166  }
1167  } elseif (isset($config[$key . '.'])) {
1168  $config[$key] = '';
1169  } else {
1170  return $defaultValue;
1171  }
1172  $stdWrapped = $this->‪stdWrap($config[$key], $config[$key . '.']);
1173  // The string "0" should be returned.
1174  return $stdWrapped !== '' ? $stdWrapped : $defaultValue;
1175  }
1176 
1184  public function ‪stdWrap_cacheRead($content = '', $conf = [])
1185  {
1186  if (!isset($conf['cache.'])) {
1187  return $content;
1188  }
1189  $result = $this->‪getFromCache($conf['cache.']);
1190  return $result === false ? $content : $result;
1191  }
1192 
1200  public function ‪stdWrap_addPageCacheTags($content = '', $conf = [])
1201  {
1202  $tags = (string)$this->‪stdWrapValue('addPageCacheTags', $conf ?? []);
1203  if (!empty($tags)) {
1204  $cacheTags = ‪GeneralUtility::trimExplode(',', $tags, true);
1205  $this->‪getTypoScriptFrontendController()->addCacheTags($cacheTags);
1206  }
1207  return $content;
1208  }
1209 
1217  public function ‪stdWrap_setContentToCurrent($content = '')
1218  {
1219  $this->data[‪$this->currentValKey] = $content;
1220  return $content;
1221  }
1222 
1231  public function ‪stdWrap_setCurrent($content = '', $conf = [])
1232  {
1233  $this->data[‪$this->currentValKey] = $conf['setCurrent'] ?? null;
1234  return $content;
1235  }
1236 
1245  public function ‪stdWrap_lang($content = '', $conf = [])
1246  {
1247  // @todo: Check when/if there are scenarios where attribute 'language' is not yet set in $request.
1248  $siteLanguage = $this->‪getRequest()->getAttribute('language') ?? $this->‪getRequest()->getAttribute('site')->getDefaultLanguage();
1249  $currentLanguageCode = $siteLanguage->getTypo3Language();
1250  if (!$currentLanguageCode) {
1251  return $content;
1252  }
1253  if (isset($conf['lang.'][$currentLanguageCode])) {
1254  $content = $conf['lang.'][$currentLanguageCode];
1255  } else {
1256  // @todo: use the Locale object and its dependencies in TYPO3 v13
1257  // Check language dependencies
1258  $locales = GeneralUtility::makeInstance(Locales::class);
1259  foreach ($locales->getLocaleDependencies($currentLanguageCode) as $languageCode) {
1260  if (isset($conf['lang.'][$languageCode])) {
1261  $content = $conf['lang.'][$languageCode];
1262  break;
1263  }
1264  }
1265  }
1266  return $content;
1267  }
1268 
1276  public function ‪stdWrap_data($_ = '', $conf = [])
1277  {
1278  return $this->‪getData($conf['data'], $this->data);
1279  }
1280 
1289  public function ‪stdWrap_field($content = '', $conf = [])
1290  {
1291  return $this->‪getFieldVal($conf['field']);
1292  }
1293 
1303  public function ‪stdWrap_current($content = '', $conf = [])
1304  {
1305  return $this->‪getCurrentVal();
1306  }
1307 
1317  public function ‪stdWrap_cObject($content = '', $conf = [])
1318  {
1319  return $this->‪cObjGetSingle($conf['cObject'] ?? '', $conf['cObject.'] ?? [], '/stdWrap/.cObject');
1320  }
1321 
1331  public function ‪stdWrap_numRows($content = '', $conf = [])
1332  {
1333  return $this->‪numRows($conf['numRows.']);
1334  }
1335 
1344  public function ‪stdWrap_preUserFunc($content = '', $conf = [])
1345  {
1346  return $this->‪callUserFunction($conf['preUserFunc'], $conf['preUserFunc.'] ?? [], $content);
1347  }
1348 
1357  public function ‪stdWrap_override($content = '', $conf = [])
1358  {
1359  if (trim($conf['override'] ?? false)) {
1360  $content = $conf['override'];
1361  }
1362  return $content;
1363  }
1364 
1374  public function ‪stdWrap_preIfEmptyListNum($content = '', $conf = [])
1375  {
1376  return $this->‪listNum($content, $conf['preIfEmptyListNum'] ?? '0', $conf['preIfEmptyListNum.']['splitChar'] ?? ',');
1377  }
1378 
1387  public function ‪stdWrap_ifNull($content = '', $conf = [])
1388  {
1389  return $content ?? $conf['ifNull'];
1390  }
1391 
1401  public function ‪stdWrap_ifEmpty($content = '', $conf = [])
1402  {
1403  if (empty(trim((string)$content))) {
1404  $content = $conf['ifEmpty'];
1405  }
1406  return $content;
1407  }
1408 
1418  public function ‪stdWrap_ifBlank($content = '', $conf = [])
1419  {
1420  if (trim((string)$content) === '') {
1421  $content = $conf['ifBlank'];
1422  }
1423  return $content;
1424  }
1425 
1436  public function ‪stdWrap_listNum($content = '', $conf = [])
1437  {
1438  return $this->‪listNum($content, $conf['listNum'] ?? '0', $conf['listNum.']['splitChar'] ?? ',');
1439  }
1440 
1448  public function ‪stdWrap_trim($content = '')
1449  {
1450  return trim((string)$content);
1451  }
1452 
1461  public function ‪stdWrap_strPad($content = '', $conf = [])
1462  {
1463  // Must specify a length in conf for this to make sense
1464  $length = (int)$this->‪stdWrapValue('length', $conf['strPad.'] ?? [], 0);
1465  // Padding with space is PHP-default
1466  $padWith = (string)$this->‪stdWrapValue('padWith', $conf['strPad.'] ?? [], ' ');
1467  // Padding on the right side is PHP-default
1468  $padType = STR_PAD_RIGHT;
1469 
1470  if (!empty($conf['strPad.']['type'])) {
1471  $type = (string)$this->‪stdWrapValue('type', $conf['strPad.'] ?? []);
1472  if (strtolower($type) === 'left') {
1473  $padType = STR_PAD_LEFT;
1474  } elseif (strtolower($type) === 'both') {
1475  $padType = STR_PAD_BOTH;
1476  }
1477  }
1478  return ‪StringUtility::multibyteStringPad($content, $length, $padWith, $padType);
1479  }
1480 
1492  public function ‪stdWrap_stdWrap($content = '', $conf = [])
1493  {
1494  return $this->‪stdWrap($content, $conf['stdWrap.']);
1495  }
1496 
1505  public function ‪stdWrap_required($content = '')
1506  {
1507  if ((string)$content === '') {
1508  $content = '';
1509  $this->stopRendering[‪$this->stdWrapRecursionLevel] = true;
1510  }
1511  return $content;
1512  }
1513 
1523  public function ‪stdWrap_if($content = '', $conf = [])
1524  {
1525  if (empty($conf['if.']) || $this->‪checkIf($conf['if.'])) {
1526  return $content;
1527  }
1528  $this->stopRendering[‪$this->stdWrapRecursionLevel] = true;
1529  return '';
1530  }
1531 
1541  public function ‪stdWrap_fieldRequired($content = '', $conf = [])
1542  {
1543  if (!trim($this->data[$conf['fieldRequired'] ?? null] ?? '')) {
1544  $content = '';
1545  $this->stopRendering[‪$this->stdWrapRecursionLevel] = true;
1546  }
1547  return $content;
1548  }
1549 
1560  public function ‪stdWrap_csConv($content = '', $conf = [])
1561  {
1562  if (!empty($conf['csConv'])) {
1563  $output = mb_convert_encoding($content, 'utf-8', trim(strtolower($conf['csConv'])));
1564  return $output !== false && $output !== '' ? $output : $content;
1565  }
1566  return $content;
1567  }
1568 
1578  public function ‪stdWrap_parseFunc($content = '', $conf = [])
1579  {
1580  return $this->‪parseFunc($content, $conf['parseFunc.'], $conf['parseFunc']);
1581  }
1582 
1592  public function ‪stdWrap_HTMLparser($content = '', $conf = [])
1593  {
1594  if (isset($conf['HTMLparser.']) && is_array($conf['HTMLparser.'])) {
1595  $content = $this->‪HTMLparser_TSbridge($content, $conf['HTMLparser.']);
1596  }
1597  return $content;
1598  }
1599 
1609  public function ‪stdWrap_split($content = '', $conf = [])
1610  {
1611  return $this->‪splitObj($content, $conf['split.']);
1612  }
1613 
1622  public function ‪stdWrap_replacement($content = '', $conf = [])
1623  {
1624  return $this->‪replacement($content, $conf['replacement.']);
1625  }
1626 
1636  public function ‪stdWrap_prioriCalc($content = '', $conf = [])
1637  {
1638  $content = ‪MathUtility::calculateWithParentheses($content);
1639  if (!empty($conf['prioriCalc']) && $conf['prioriCalc'] === 'intval') {
1640  $content = (int)$content;
1641  }
1642  return $content;
1643  }
1644 
1656  public function ‪stdWrap_char($content = '', $conf = [])
1657  {
1658  return chr((int)$conf['char']);
1659  }
1660 
1668  public function ‪stdWrap_intval($content = '')
1669  {
1670  return (int)$content;
1671  }
1672 
1681  public function ‪stdWrap_hash($content = '', array $conf = [])
1682  {
1683  $algorithm = (string)$this->‪stdWrapValue('hash', $conf ?? []);
1684  if (in_array($algorithm, hash_algos())) {
1685  return hash($algorithm, $content);
1686  }
1687  // Non-existing hashing algorithm
1688  return '';
1689  }
1690 
1699  public function ‪stdWrap_round($content = '', $conf = [])
1700  {
1701  return $this->‪round($content, $conf['round.']);
1702  }
1703 
1712  public function ‪stdWrap_numberFormat($content = '', $conf = [])
1713  {
1714  return $this->‪numberFormat((float)$content, $conf['numberFormat.'] ?? []);
1715  }
1716 
1724  public function ‪stdWrap_expandList($content = '')
1725  {
1726  return ‪GeneralUtility::expandList($content);
1727  }
1728 
1738  public function ‪stdWrap_date($content = '', $conf = [])
1739  {
1740  // Check for zero length string to mimic default case of date/gmdate.
1741  $content = (string)$content === '' ? ‪$GLOBALS['EXEC_TIME'] : (int)$content;
1742  $content = !empty($conf['date.']['GMT']) ? gmdate($conf['date'] ?? null, $content) : date($conf['date'] ?? null, $content);
1743  return $content;
1744  }
1745 
1755  public function ‪stdWrap_strftime($content = '', $conf = [])
1756  {
1757  // Check for zero length string to mimic default case of strtime/gmstrftime
1758  $content = (string)$content === '' ? ‪$GLOBALS['EXEC_TIME'] : (int)$content;
1759  $content = (isset($conf['strftime.']['GMT']) && $conf['strftime.']['GMT'])
1760  ? (new ‪DateFormatter())->strftime($conf['strftime'] ?? '', $content, null, true)
1761  : (new ‪DateFormatter())->strftime($conf['strftime'] ?? '', $content);
1762  if (!empty($conf['strftime.']['charset'])) {
1763  $output = mb_convert_encoding((string)$content, 'utf-8', trim(strtolower($conf['strftime.']['charset'])));
1764  return $output ?: $content;
1765  }
1766  return $content;
1767  }
1768 
1777  public function ‪stdWrap_strtotime($content = '', $conf = [])
1778  {
1779  if ($conf['strtotime'] !== '1') {
1780  $content .= ' ' . $conf['strtotime'];
1781  }
1782  return strtotime($content, ‪$GLOBALS['EXEC_TIME']);
1783  }
1784 
1794  public function ‪stdWrap_formattedDate(string $content, array $conf): string
1795  {
1796  $pattern = $conf['formattedDate'] ?? 'LONG';
1797  // @todo: Check when/if there are scenarios where attribute 'language' is not yet set in $request.
1798  $language = $this->‪getRequest()->getAttribute('language') ?? $this->‪getRequest()->getAttribute('site')->getDefaultLanguage();
1799  $locale = $conf['formattedDate.']['locale'] ?? $language->getLocale();
1800 
1801  if ($content === '' || $content === '0') {
1802  $content = GeneralUtility::makeInstance(Context::class)->getAspect('date')->getDateTime();
1803  } else {
1804  // format this to a timestamp now
1805  $content = strtotime((‪MathUtility::canBeInterpretedAsInteger($content) ? '@' : '') . $content);
1806  if ($content === false) {
1807  $content = GeneralUtility::makeInstance(Context::class)->getAspect('date')->getDateTime();
1808  }
1809  }
1810  return (new DateFormatter())->format($content, $pattern, $locale);
1811  }
1812 
1821  public function ‪stdWrap_age($content = '', $conf = [])
1822  {
1823  return $this->‪calcAge((int)(‪$GLOBALS['EXEC_TIME'] ?? 0) - (int)$content, $conf['age'] ?? null);
1824  }
1825 
1835  public function ‪stdWrap_case($content = '', $conf = [])
1836  {
1837  return $this->‪HTMLcaseshift($content, $conf['case']);
1838  }
1839 
1848  public function ‪stdWrap_bytes($content = '', $conf = [])
1849  {
1850  return GeneralUtility::formatSize((int)$content, $conf['bytes.']['labels'] ?? '', $conf['bytes.']['base'] ?? 0);
1851  }
1852 
1861  public function ‪stdWrap_substring($content = '', $conf = [])
1862  {
1863  return $this->‪substring($content, $conf['substring']);
1864  }
1865 
1874  public function ‪stdWrap_cropHTML($content = '', $conf = [])
1875  {
1876  return $this->‪cropHTML($content, $conf['cropHTML'] ?? '');
1877  }
1878 
1886  public function ‪stdWrap_stripHtml($content = '')
1887  {
1888  return strip_tags((string)$content);
1889  }
1890 
1899  public function ‪stdWrap_crop($content = '', $conf = [])
1900  {
1901  return $this->‪crop($content, $conf['crop']);
1902  }
1903 
1911  public function ‪stdWrap_rawUrlEncode($content = '')
1912  {
1913  return rawurlencode($content);
1914  }
1915 
1925  public function ‪stdWrap_htmlSpecialChars($content = '', $conf = [])
1926  {
1927  if (!empty($conf['htmlSpecialChars.']['preserveEntities'])) {
1928  $content = htmlspecialchars((string)$content, ENT_COMPAT, 'UTF-8', false);
1929  } else {
1930  $content = htmlspecialchars((string)$content);
1931  }
1932  return $content;
1933  }
1934 
1942  public function ‪stdWrap_encodeForJavaScriptValue($content = '')
1943  {
1944  return GeneralUtility::quoteJSvalue($content);
1945  }
1946 
1955  public function ‪stdWrap_doubleBrTag($content = '', $conf = [])
1956  {
1957  return preg_replace('/\R{1,2}[\t\x20]*\R{1,2}/', $conf['doubleBrTag'] ?? '', $content);
1958  }
1959 
1968  public function ‪stdWrap_br($content = '')
1969  {
1970  $docType = GeneralUtility::makeInstance(PageRenderer::class)->getDocType();
1971  return nl2br($content, $docType->isXmlCompliant());
1972  }
1973 
1982  public function ‪stdWrap_brTag($content = '', $conf = [])
1983  {
1984  return str_replace(LF, (string)($conf['brTag'] ?? ''), $content);
1985  }
1986 
1996  public function ‪stdWrap_encapsLines($content = '', $conf = [])
1997  {
1998  return $this->‪encaps_lineSplit($content, $conf['encapsLines.']);
1999  }
2000 
2008  public function ‪stdWrap_keywords($content = '')
2009  {
2010  return $this->‪keywords($content);
2011  }
2012 
2022  public function ‪stdWrap_innerWrap($content = '', $conf = [])
2023  {
2024  return $this->‪wrap($content, $conf['innerWrap'] ?? null);
2025  }
2026 
2036  public function ‪stdWrap_innerWrap2($content = '', $conf = [])
2037  {
2038  return $this->‪wrap($content, $conf['innerWrap2'] ?? null);
2039  }
2040 
2049  public function ‪stdWrap_preCObject($content = '', $conf = [])
2050  {
2051  return $this->‪cObjGetSingle($conf['preCObject'], $conf['preCObject.'], '/stdWrap/.preCObject') . $content;
2052  }
2053 
2062  public function ‪stdWrap_postCObject($content = '', $conf = [])
2063  {
2064  return $content . $this->‪cObjGetSingle($conf['postCObject'], $conf['postCObject.'], '/stdWrap/.postCObject');
2065  }
2066 
2076  public function ‪stdWrap_wrapAlign($content = '', $conf = [])
2077  {
2078  $wrapAlign = trim($conf['wrapAlign'] ?? '');
2079  if ($wrapAlign) {
2080  $content = $this->‪wrap($content, '<div style="text-align:' . htmlspecialchars($wrapAlign) . ';">|</div>');
2081  }
2082  return $content;
2083  }
2084 
2095  public function ‪stdWrap_typolink($content = '', $conf = [])
2096  {
2097  return $this->‪typoLink((string)$content, $conf['typolink.'] ?? []);
2098  }
2099 
2112  public function ‪stdWrap_wrap($content = '', $conf = [])
2113  {
2114  return $this->‪wrap(
2115  $content,
2116  $conf['wrap'] ?? null,
2117  $conf['wrap.']['splitChar'] ?? '|'
2118  );
2119  }
2120 
2130  public function ‪stdWrap_noTrimWrap($content = '', $conf = [])
2131  {
2132  $splitChar = isset($conf['noTrimWrap.']['splitChar.'])
2133  ? $this->‪stdWrap($conf['noTrimWrap.']['splitChar'] ?? '', $conf['noTrimWrap.']['splitChar.'])
2134  : $conf['noTrimWrap.']['splitChar'] ?? '';
2135  if ($splitChar === null || $splitChar === '') {
2136  $splitChar = '|';
2137  }
2138  $content = $this->‪noTrimWrap(
2139  $content,
2140  $conf['noTrimWrap'],
2141  $splitChar
2142  );
2143  return $content;
2144  }
2145 
2155  public function ‪stdWrap_wrap2($content = '', $conf = [])
2156  {
2157  return $this->‪wrap(
2158  $content,
2159  $conf['wrap2'] ?? null,
2160  $conf['wrap2.']['splitChar'] ?? '|'
2161  );
2162  }
2163 
2173  public function ‪stdWrap_dataWrap($content = '', $conf = [])
2174  {
2175  return $this->‪dataWrap($content, $conf['dataWrap']);
2176  }
2177 
2186  public function ‪stdWrap_prepend($content = '', $conf = [])
2187  {
2188  return $this->‪cObjGetSingle($conf['prepend'], $conf['prepend.'], '/stdWrap/.prepend') . $content;
2189  }
2190 
2199  public function ‪stdWrap_append($content = '', $conf = [])
2200  {
2201  return $content . $this->‪cObjGetSingle($conf['append'], $conf['append.'], '/stdWrap/.append');
2202  }
2203 
2213  public function ‪stdWrap_wrap3($content = '', $conf = [])
2214  {
2215  return $this->‪wrap(
2216  $content,
2217  $conf['wrap3'] ?? null,
2218  $conf['wrap3.']['splitChar'] ?? '|'
2219  );
2220  }
2221 
2230  public function ‪stdWrap_orderedStdWrap($content = '', $conf = [])
2231  {
2232  $sortedKeysArray = ArrayUtility::filterAndSortByNumericKeys($conf['orderedStdWrap.'], true);
2233  foreach ($sortedKeysArray as $key) {
2234  $content = (string)$this->‪stdWrap($content, $conf['orderedStdWrap.'][$key . '.'] ?? null);
2235  }
2236  return $content;
2237  }
2238 
2247  public function ‪stdWrap_outerWrap($content = '', $conf = [])
2248  {
2249  return $this->‪wrap($content, $conf['outerWrap'] ?? null);
2250  }
2251 
2259  public function ‪stdWrap_insertData($content = '')
2260  {
2261  return $this->‪insertData($content);
2262  }
2263 
2272  public function ‪stdWrap_postUserFunc($content = '', $conf = [])
2273  {
2274  return $this->‪callUserFunction($conf['postUserFunc'], $conf['postUserFunc.'] ?? [], $content);
2275  }
2276 
2286  public function ‪stdWrap_postUserFuncInt($content = '', $conf = [])
2287  {
2288  $substKey = 'INT_SCRIPT.' . $this->‪getTypoScriptFrontendController()->uniqueHash();
2289  $this->‪getTypoScriptFrontendController()->config['INTincScript'][$substKey] = [
2290  'content' => $content,
2291  'postUserFunc' => $conf['postUserFuncInt'],
2292  'conf' => $conf['postUserFuncInt.'],
2293  'type' => 'POSTUSERFUNC',
2294  'cObj' => serialize($this),
2295  ];
2296  $content = '<!--' . $substKey . '-->';
2297  return $content;
2298  }
2299 
2308  public function ‪stdWrap_prefixComment($content = '', $conf = [])
2309  {
2310  $typoScriptConfigArray = $this->‪getRequest()->getAttribute('frontend.typoscript')->getConfigArray();
2311  if (
2312  (!isset($typoScriptConfigArray['disablePrefixComment']) || !$typoScriptConfigArray['disablePrefixComment'])
2313  && !empty($conf['prefixComment'])
2314  ) {
2315  $content = $this->‪prefixComment($conf['prefixComment'], [], $content);
2316  }
2317  return $content;
2318  }
2319 
2320  public function ‪stdWrap_htmlSanitize(string $content = '', array $conf = []): string
2321  {
2322  $build = $conf['build'] ?? 'default';
2323  if (class_exists($build) && is_a($build, BuilderInterface::class, true)) {
2324  $builder = GeneralUtility::makeInstance($build);
2325  } else {
2326  $factory = GeneralUtility::makeInstance(SanitizerBuilderFactory::class);
2327  $builder = $factory->build($build);
2328  }
2329  $sanitizer = $builder->build();
2330  $initiator = $this->‪shallDebug()
2331  ? GeneralUtility::makeInstance(SanitizerInitiator::class, ‪DebugUtility::debugTrail())
2332  : null;
2333  return $sanitizer->sanitize($content, $initiator);
2334  }
2335 
2343  public function ‪stdWrap_cacheStore($content = '', $conf = []): ?string
2344  {
2345  if (!isset($conf['cache.'])) {
2346  return $content;
2347  }
2348  $key = $this->‪calculateCacheKey($conf['cache.']);
2349  if (empty($key)) {
2350  return $content;
2351  }
2352 
2353  $event = GeneralUtility::makeInstance(EventDispatcherInterface::class)->dispatch(
2354  new BeforeStdWrapContentStoredInCacheEvent(
2355  content: $content,
2356  tags: $this->‪calculateCacheTags($conf['cache.']),
2357  key: (string)$key,
2358  lifetime: $this->‪calculateCacheLifetime($conf['cache.']),
2359  configuration: $conf,
2360  contentObjectRenderer: $this
2361  )
2362  );
2363 
2364  GeneralUtility::makeInstance(CacheManager::class)
2365  ->getCache('hash')
2366  ->set(
2367  $event->getKey(),
2368  ['content' => $event->getContent(), 'cacheTags' => $event->getTags()],
2369  $event->getTags(),
2370  $event->getLifetime()
2371  );
2372  $this->‪getTypoScriptFrontendController()->addCacheTags($event->getTags());
2373  return $event->getContent();
2374  }
2375 
2383  public function ‪stdWrap_debug($content = '')
2384  {
2385  return '<pre>' . htmlspecialchars($content) . '</pre>';
2386  }
2387 
2396  public function ‪stdWrap_debugFunc($content = '', $conf = [])
2397  {
2398  ‪debug((int)$conf['debugFunc'] === 2 ? [$content] : $content);
2399  return $content;
2400  }
2401 
2409  public function ‪stdWrap_debugData($content = '')
2410  {
2411  ‪debug($this->data, '$cObj->data:');
2412  return $content;
2413  }
2414 
2424  public function ‪numRows($conf)
2425  {
2426  $conf['select.']['selectFields'] = 'count(*)';
2427  $statement = $this->‪exec_getQuery($conf['table'], $conf['select.']);
2428 
2429  return (int)$statement->fetchOne();
2430  }
2431 
2440  public function ‪listNum($content, $listNum, $delimeter = ',')
2441  {
2442  $delimeter = $delimeter ?: ',';
2444  $delimeter = chr((int)$delimeter);
2445  }
2446  $temp = explode($delimeter, $content);
2447  if ($temp === ['']) {
2448  return '';
2449  }
2450  $last = '' . (count($temp) - 1);
2451  // Take a random item if requested
2452  if ($listNum === 'rand') {
2453  $listNum = (string)random_int(0, count($temp) - 1);
2454  }
2455  $index = $this->‪calc(str_ireplace('last', $last, $listNum));
2456  return $temp[$index] ?? '';
2457  }
2458 
2465  public function ‪checkIf($conf): bool
2466  {
2467  if (!is_array($conf)) {
2468  return true;
2469  }
2470  if (isset($conf['directReturn'])) {
2471  return (bool)$conf['directReturn'];
2472  }
2473  $flag = true;
2474  if (isset($conf['isNull.'])) {
2475  $isNull = $this->‪stdWrap('', $conf['isNull.']);
2476  if ($isNull !== null) {
2477  $flag = false;
2478  }
2479  }
2480  if (isset($conf['isTrue']) || isset($conf['isTrue.'])) {
2481  $isTrue = trim((string)$this->‪stdWrapValue('isTrue', $conf));
2482  if (!$isTrue) {
2483  $flag = false;
2484  }
2485  }
2486  if (isset($conf['isFalse']) || isset($conf['isFalse.'])) {
2487  $isFalse = trim((string)$this->‪stdWrapValue('isFalse', $conf));
2488  if ($isFalse) {
2489  $flag = false;
2490  }
2491  }
2492  if (isset($conf['isPositive']) || isset($conf['isPositive.'])) {
2493  $number = $this->‪calc((string)$this->‪stdWrapValue('isPositive', $conf));
2494  if ($number < 1) {
2495  $flag = false;
2496  }
2497  }
2498  if ($flag) {
2499  $comparisonValue = trim((string)$this->‪stdWrapValue('value', $conf));
2500  if (isset($conf['isGreaterThan']) || isset($conf['isGreaterThan.'])) {
2501  $number = trim((string)$this->‪stdWrapValue('isGreaterThan', $conf));
2502  if ($number <= $comparisonValue) {
2503  $flag = false;
2504  }
2505  }
2506  if (isset($conf['isLessThan']) || isset($conf['isLessThan.'])) {
2507  $number = trim((string)$this->‪stdWrapValue('isLessThan', $conf));
2508  if ($number >= $comparisonValue) {
2509  $flag = false;
2510  }
2511  }
2512  if (isset($conf['equals']) || isset($conf['equals.'])) {
2513  $number = trim((string)$this->‪stdWrapValue('equals', $conf));
2514  if ($number != $comparisonValue) {
2515  $flag = false;
2516  }
2517  }
2518  if (isset($conf['contains']) || isset($conf['contains.'])) {
2519  $needle = trim((string)$this->‪stdWrapValue('contains', $conf));
2520  if (!str_contains($comparisonValue, $needle)) {
2521  $flag = false;
2522  }
2523  }
2524  if (isset($conf['startsWith']) || isset($conf['startsWith.'])) {
2525  $needle = trim((string)$this->‪stdWrapValue('startsWith', $conf));
2526  if (!str_starts_with($comparisonValue, $needle)) {
2527  $flag = false;
2528  }
2529  }
2530  if (isset($conf['endsWith']) || isset($conf['endsWith.'])) {
2531  $needle = trim((string)$this->‪stdWrapValue('endsWith', $conf));
2532  if (!str_ends_with($comparisonValue, $needle)) {
2533  $flag = false;
2534  }
2535  }
2536  if (isset($conf['isInList']) || isset($conf['isInList.'])) {
2537  $singleValueWhichNeedsToBeInList = trim((string)$this->‪stdWrapValue('isInList', $conf));
2538  if (!‪GeneralUtility::inList($comparisonValue, $singleValueWhichNeedsToBeInList)) {
2539  $flag = false;
2540  }
2541  }
2542  if (isset($conf['bitAnd']) || isset($conf['bitAnd.'])) {
2543  $number = (int)trim((string)$this->‪stdWrapValue('bitAnd', $conf));
2544  if ((new BitSet($number))->get($comparisonValue) === false) {
2545  $flag = false;
2546  }
2547  }
2548  }
2549  if ($conf['negate'] ?? false) {
2550  $flag = !$flag;
2551  }
2552  return $flag;
2553  }
2554 
2567  public function ‪HTMLparser_TSbridge($theValue, $conf)
2568  {
2569  $htmlParser = GeneralUtility::makeInstance(HtmlParser::class);
2570  $htmlParserCfg = $htmlParser->HTMLparserConfig($conf);
2571  return $htmlParser->HTMLcleaner($theValue, $htmlParserCfg[0], $htmlParserCfg[1], $htmlParserCfg[2], $htmlParserCfg[3]);
2572  }
2573 
2583  public function ‪dataWrap($content, $wrap)
2584  {
2585  return $this->‪wrap($content, $this->‪insertData($wrap));
2586  }
2603  public function ‪insertData($str)
2604  {
2605  $inside = 0;
2606  $newVal = '';
2607  $pointer = 0;
2608  $totalLen = strlen($str);
2609  do {
2610  if (!$inside) {
2611  $len = strcspn(substr($str, $pointer), '{');
2612  $newVal .= substr($str, $pointer, $len);
2613  $inside = true;
2614  if (substr($str, $pointer + $len + 1, 1) === '#') {
2615  $len2 = strcspn(substr($str, $pointer + $len), '}');
2616  $newVal .= substr($str, $pointer + $len, $len2);
2617  $len += $len2;
2618  $inside = false;
2619  }
2620  } else {
2621  $len = strcspn(substr($str, $pointer), '}') + 1;
2622  $newVal .= $this->‪getData(substr($str, $pointer + 1, $len - 2), $this->data);
2623  $inside = false;
2624  }
2625  $pointer += $len;
2626  } while ($pointer < $totalLen);
2627  return $newVal;
2628  }
2629 
2640  public function ‪prefixComment($str, $conf, $content)
2641  {
2642  if (empty($str)) {
2643  return $content;
2644  }
2645  $parts = explode('|', $str);
2646  $indent = (int)$parts[0];
2647  $comment = htmlspecialchars($this->‪insertData($parts[1]));
2648  $output = LF
2649  . str_pad('', $indent, "\t") . '<!-- ' . $comment . ' [begin] -->' . LF
2650  . str_pad('', $indent + 1, "\t") . $content . LF
2651  . str_pad('', $indent, "\t") . '<!-- ' . $comment . ' [end] -->' . LF
2652  . str_pad('', $indent + 1, "\t");
2653  return $output;
2654  }
2655 
2665  public function ‪substring($content, $options)
2666  {
2667  $options = ‪GeneralUtility::intExplode(',', $options . ',');
2668  if ($options[1]) {
2669  return mb_substr($content, $options[0], $options[1], 'utf-8');
2670  }
2671  return mb_substr($content, $options[0], null, 'utf-8');
2672  }
2673 
2683  public function ‪crop($content, $options)
2684  {
2685  $options = explode('|', $options);
2686  $numberOfChars = (int)$options[0];
2687  $replacementForEllipsis = trim($options[1] ?? '');
2688  $cropToSpace = trim($options[2] ?? '') === '1';
2689  return GeneralUtility::makeInstance(TextCropper::class)
2690  ->crop(
2691  content: $content,
2692  numberOfChars: $numberOfChars,
2693  replacementForEllipsis: $replacementForEllipsis,
2694  cropToSpace: $cropToSpace
2695  );
2696  }
2697 
2711  public function ‪cropHTML(string $content, string $options): string
2712  {
2713  $options = explode('|', $options);
2714  $numberOfChars = (int)$options[0];
2715  $replacementForEllipsis = trim($options[1] ?? '');
2716  $cropToSpace = trim($options[2] ?? '') === '1';
2717  return GeneralUtility::makeInstance(HtmlCropper::class)
2718  ->crop(
2719  content: $content,
2720  numberOfChars: $numberOfChars,
2721  replacementForEllipsis: $replacementForEllipsis,
2722  cropToSpace: $cropToSpace
2723  );
2724  }
2725 
2733  public function ‪calc($val)
2734  {
2735  $parts = GeneralUtility::splitCalc($val, '+-*/');
2736  $value = 0;
2737  foreach ($parts as $part) {
2738  $theVal = $part[1];
2739  $sign = $part[0];
2740  if ((string)(int)$theVal === (string)$theVal) {
2741  $theVal = (int)$theVal;
2742  } else {
2743  $theVal = 0;
2744  }
2745  if ($sign === '-') {
2746  $value -= $theVal;
2747  }
2748  if ($sign === '+') {
2749  $value += $theVal;
2750  }
2751  if ($sign === '/') {
2752  if ((int)$theVal) {
2753  $value /= (int)$theVal;
2754  }
2755  }
2756  if ($sign === '*') {
2757  $value *= $theVal;
2758  }
2759  }
2760  return $value;
2761  }
2762 
2775  public function ‪splitObj($value, $conf)
2776  {
2777  $conf['token'] = isset($conf['token.']) ? $this->‪stdWrap($conf['token'] ?? '', $conf['token.']) : $conf['token'] ?? '';
2778  if ($conf['token'] === '') {
2779  return $value;
2780  }
2781  $valArr = explode($conf['token'], $value);
2782 
2783  // return value directly by returnKey. No further processing
2784  if ($valArr !== [''] && (‪MathUtility::canBeInterpretedAsInteger($conf['returnKey'] ?? null) || ($conf['returnKey.'] ?? false))) {
2785  $key = (int)$this->‪stdWrapValue('returnKey', $conf ?? []);
2786  return $valArr[$key] ?? '';
2787  }
2788 
2789  // return the amount of elements. No further processing
2790  if ($valArr !== [''] && (($conf['returnCount'] ?? false) || ($conf['returnCount.'] ?? false))) {
2791  $returnCount = (bool)$this->‪stdWrapValue('returnCount', $conf ?? []);
2792  return $returnCount ? count($valArr) : 0;
2793  }
2794 
2795  // calculate splitCount
2796  $splitCount = count($valArr);
2797  $max = (int)$this->‪stdWrapValue('max', $conf ?? []);
2798  if ($max && $splitCount > $max) {
2799  $splitCount = $max;
2800  }
2801  $min = (int)$this->‪stdWrapValue('min', $conf ?? []);
2802  if ($min && $splitCount < $min) {
2803  $splitCount = $min;
2804  }
2805  $wrap = (string)$this->‪stdWrapValue('wrap', $conf ?? []);
2806  $cObjNumSplitConf = isset($conf['cObjNum.']) ? $this->‪stdWrap($conf['cObjNum'] ?? '', $conf['cObjNum.'] ?? []) : (string)($conf['cObjNum'] ?? '');
2807  $splitArr = [];
2808  if ($wrap !== '' || $cObjNumSplitConf !== '') {
2809  $splitArr['wrap'] = $wrap;
2810  $splitArr['cObjNum'] = $cObjNumSplitConf;
2811  $splitArr = GeneralUtility::makeInstance(TypoScriptService::class)
2812  ->explodeConfigurationForOptionSplit($splitArr, $splitCount);
2813  }
2814  $content = '';
2815  for ($a = 0; $a < $splitCount; $a++) {
2816  $this->‪getTypoScriptFrontendController()->register['SPLIT_COUNT'] = $a;
2817  $value = '' . $valArr[$a];
2818  $this->data[‪$this->currentValKey] = $value;
2819  if ($splitArr[$a]['cObjNum'] ?? false) {
2820  $objName = (int)$splitArr[$a]['cObjNum'];
2821  $value = (string)(isset($conf[$objName . '.'])
2822  ? $this->‪stdWrap($this->‪cObjGet($conf[$objName . '.'], $objName . '.'), $conf[$objName . '.'])
2823  : '');
2824  }
2825  $wrap = (string)$this->‪stdWrapValue('wrap', $splitArr[$a] ?? []);
2826  if ($wrap) {
2827  $value = $this->‪wrap($value, $wrap);
2828  }
2829  $content .= $value;
2830  }
2831  return $content;
2832  }
2833 
2841  protected function ‪replacement($content, array $configuration)
2842  {
2843  // Sorts actions in configuration by numeric index
2844  ksort($configuration, SORT_NUMERIC);
2845  foreach ($configuration as $index => $action) {
2846  // Checks whether we have a valid action and a numeric key ending with a dot ("10.")
2847  if (is_array($action) && substr($index, -1) === '.' && ‪MathUtility::canBeInterpretedAsInteger(substr($index, 0, -1))) {
2848  $content = $this->‪replacementSingle($content, $action);
2849  }
2850  }
2851  return $content;
2852  }
2853 
2861  protected function ‪replacementSingle($content, array $configuration)
2862  {
2863  if ((isset($configuration['search']) || isset($configuration['search.'])) && (isset($configuration['replace']) || isset($configuration['replace.']))) {
2864  // Gets the strings
2865  $search = (string)$this->‪stdWrapValue('search', $configuration ?? []);
2866  $replace = (string)$this->‪stdWrapValue('replace', $configuration, null);
2867 
2868  // Determines whether regular expression shall be used
2869  $useRegularExpression = (bool)$this->‪stdWrapValue('useRegExp', $configuration, false);
2870 
2871  // Determines whether replace-pattern uses option-split
2872  $useOptionSplitReplace = (bool)$this->‪stdWrapValue('useOptionSplitReplace', $configuration, false);
2873 
2874  // Performs a replacement by preg_replace()
2875  if ($useRegularExpression) {
2876  // Get separator-character which precedes the string and separates search-string from the modifiers
2877  $separator = $search[0];
2878  $startModifiers = strrpos($search, $separator);
2879  if ($separator !== false && $startModifiers > 0) {
2880  $modifiers = substr($search, $startModifiers + 1);
2881  // remove "e" (eval-modifier), which would otherwise allow to run arbitrary PHP-code
2882  $modifiers = str_replace('e', '', $modifiers);
2883  $search = substr($search, 0, $startModifiers + 1) . $modifiers;
2884  }
2885  if ($useOptionSplitReplace) {
2886  // init for replacement
2887  $splitCount = preg_match_all($search, $content);
2888  $typoScriptService = GeneralUtility::makeInstance(TypoScriptService::class);
2889  $replaceArray = $typoScriptService->explodeConfigurationForOptionSplit([$replace], $splitCount);
2890  $replaceCount = 0;
2891 
2892  $replaceCallback = static function ($match) use ($replaceArray, $search, &$replaceCount) {
2893  $replaceCount++;
2894  return preg_replace($search, $replaceArray[$replaceCount - 1][0], $match[0]);
2895  };
2896  $content = preg_replace_callback($search, $replaceCallback, $content);
2897  } else {
2898  $content = preg_replace($search, $replace, $content);
2899  }
2900  } elseif ($useOptionSplitReplace) {
2901  // turn search-string into a preg-pattern
2902  $searchPreg = '#' . preg_quote($search, '#') . '#';
2903 
2904  // init for replacement
2905  $splitCount = preg_match_all($searchPreg, $content);
2906  $typoScriptService = GeneralUtility::makeInstance(TypoScriptService::class);
2907  $replaceArray = $typoScriptService->explodeConfigurationForOptionSplit([$replace], $splitCount);
2908  $replaceCount = 0;
2909 
2910  $replaceCallback = static function () use ($replaceArray, &$replaceCount) {
2911  $replaceCount++;
2912  return $replaceArray[$replaceCount - 1][0];
2913  };
2914  $content = preg_replace_callback($searchPreg, $replaceCallback, $content);
2915  } else {
2916  $content = str_replace($search, $replace, $content);
2917  }
2918  }
2919  return $content;
2920  }
2921 
2930  protected function ‪round($content, array $conf = [])
2931  {
2932  $decimals = (int)$this->‪stdWrapValue('decimals', $conf, 0);
2933  $type = $this->‪stdWrapValue('roundType', $conf);
2934  $floatVal = (float)$content;
2935  switch ($type) {
2936  case 'ceil':
2937  $content = ceil($floatVal);
2938  break;
2939  case 'floor':
2940  $content = floor($floatVal);
2941  break;
2942  case 'round':
2943 
2944  default:
2945  $content = ‪round($floatVal, $decimals);
2946  }
2947  return $content;
2948  }
2949 
2958  public function ‪numberFormat($content, $conf)
2959  {
2960  $decimals = (int)$this->‪stdWrapValue('decimals', $conf, 0);
2961  $dec_point = (string)$this->‪stdWrapValue('dec_point', $conf, '.');
2962  $thousands_sep = (string)$this->‪stdWrapValue('thousands_sep', $conf, ',');
2963  return number_format((float)$content, $decimals, $dec_point, $thousands_sep);
2964  }
2965 
2984  public function ‪parseFunc($theValue, ?array $conf, ?string $ref = null)
2985  {
2986  // Fetch / merge reference, if any
2987  if (!empty($ref)) {
2988  $temp_conf = [
2989  'parseFunc' => $ref,
2990  'parseFunc.' => $conf ?? [],
2991  ];
2992  $temp_conf = $this->‪mergeTSRef($temp_conf, 'parseFunc');
2993  $conf = $temp_conf['parseFunc.'];
2994  }
2995  if (empty($conf)) {
2996  // `parseFunc` relies on configuration, either given in `$conf` or resolved from `$ref`
2997  throw new \LogicException('Invoked ContentObjectRenderer::parseFunc without any configuration', 1641989097);
2998  }
2999  // Handle HTML sanitizer invocation
3000  $conf['htmlSanitize'] = (bool)($conf['htmlSanitize'] ?? true);
3001  // Process:
3002  if ((string)($conf['externalBlocks'] ?? '') === '') {
3003  $result = $this->‪parseFuncInternal($theValue, $conf);
3004  if ($conf['htmlSanitize']) {
3005  $result = $this->‪stdWrap_htmlSanitize($result, $conf['htmlSanitize.'] ?? []);
3006  }
3007  return $result;
3008  }
3009  $tags = strtolower(implode(',', ‪GeneralUtility::trimExplode(',', $conf['externalBlocks'])));
3010  $htmlParser = GeneralUtility::makeInstance(HtmlParser::class);
3011  $parts = $htmlParser->splitIntoBlock($tags, $theValue);
3012  foreach ($parts as $k => $v) {
3013  if ($k % 2) {
3014  // font:
3015  $tagName = strtolower($htmlParser->getFirstTagName($v));
3016  $cfg = $conf['externalBlocks.'][$tagName . '.'] ?? [];
3017  if ($cfg === []) {
3018  continue;
3019  }
3020  if (($cfg['stripNLprev'] ?? false) || ($cfg['stripNL'] ?? false)) {
3021  $parts[$k - 1] = preg_replace('/' . CR . '?' . LF . '[ ]*$/', '', $parts[$k - 1]);
3022  }
3023  if (($cfg['stripNLnext'] ?? false) || ($cfg['stripNL'] ?? false)) {
3024  if (!isset($parts[$k + 1])) {
3025  $parts[$k + 1] = '';
3026  }
3027  $parts[$k + 1] = preg_replace('/^[ ]*' . CR . '?' . LF . '/', '', $parts[$k + 1]);
3028  }
3029  }
3030  }
3031  foreach ($parts as $k => $v) {
3032  if ($k % 2) {
3033  $tag = $htmlParser->getFirstTag($v);
3034  $tagName = strtolower($htmlParser->getFirstTagName($v));
3035  $cfg = $conf['externalBlocks.'][$tagName . '.'] ?? [];
3036  if ($cfg === []) {
3037  continue;
3038  }
3039  if ($cfg['callRecursive'] ?? false) {
3040  $parts[$k] = $this->‪parseFunc($htmlParser->removeFirstAndLastTag($v), $conf);
3041  if (!($cfg['callRecursive.']['dontWrapSelf'] ?? false)) {
3042  if ($cfg['callRecursive.']['alternativeWrap'] ?? false) {
3043  $parts[$k] = $this->‪wrap($parts[$k], $cfg['callRecursive.']['alternativeWrap']);
3044  } else {
3045  if (is_array($cfg['callRecursive.']['tagStdWrap.'] ?? false)) {
3046  $tag = $this->‪stdWrap($tag, $cfg['callRecursive.']['tagStdWrap.']);
3047  }
3048  $parts[$k] = $tag . $parts[$k] . '</' . $tagName . '>';
3049  }
3050  }
3051  } elseif ($cfg['HTMLtableCells'] ?? false) {
3052  $rowParts = $htmlParser->splitIntoBlock('tr', $parts[$k]);
3053  foreach ($rowParts as $kk => $vv) {
3054  if ($kk % 2) {
3055  $colParts = $htmlParser->splitIntoBlock('td,th', $vv);
3056  $cc = 0;
3057  foreach ($colParts as $kkk => $vvv) {
3058  if ($kkk % 2) {
3059  $cc++;
3060  $tag = $htmlParser->getFirstTag($vvv);
3061  $tagName = strtolower($htmlParser->getFirstTagName($vvv));
3062  $colParts[$kkk] = $htmlParser->removeFirstAndLastTag($vvv);
3063  if (($cfg['HTMLtableCells.'][$cc . '.']['callRecursive'] ?? false)
3064  || (!isset($cfg['HTMLtableCells.'][$cc . '.']['callRecursive']) && ($cfg['HTMLtableCells.']['default.']['callRecursive'] ?? false))) {
3065  if ($cfg['HTMLtableCells.']['addChr10BetweenParagraphs'] ?? false) {
3066  $colParts[$kkk] = str_replace(
3067  '</p><p>',
3068  '</p>' . LF . '<p>',
3069  $colParts[$kkk]
3070  );
3071  }
3072  $colParts[$kkk] = $this->‪parseFunc($colParts[$kkk], $conf);
3073  }
3074  $tagStdWrap = is_array($cfg['HTMLtableCells.'][$cc . '.']['tagStdWrap.'] ?? false)
3075  ? $cfg['HTMLtableCells.'][$cc . '.']['tagStdWrap.']
3076  : ($cfg['HTMLtableCells.']['default.']['tagStdWrap.'] ?? null);
3077  if (is_array($tagStdWrap)) {
3078  $tag = $this->‪stdWrap($tag, $tagStdWrap);
3079  }
3080  $stdWrap = is_array($cfg['HTMLtableCells.'][$cc . '.']['stdWrap.'] ?? false)
3081  ? $cfg['HTMLtableCells.'][$cc . '.']['stdWrap.']
3082  : ($cfg['HTMLtableCells.']['default.']['stdWrap.'] ?? null);
3083  if (is_array($stdWrap)) {
3084  $colParts[$kkk] = $this->‪stdWrap($colParts[$kkk], $stdWrap);
3085  }
3086  $colParts[$kkk] = $tag . $colParts[$kkk] . '</' . $tagName . '>';
3087  }
3088  }
3089  $rowParts[$kk] = implode('', $colParts);
3090  }
3091  }
3092  $parts[$k] = implode('', $rowParts);
3093  }
3094  if (is_array($cfg['stdWrap.'] ?? false)) {
3095  $parts[$k] = $this->‪stdWrap($parts[$k], $cfg['stdWrap.']);
3096  }
3097  } else {
3098  $parts[$k] = $this->‪parseFuncInternal($parts[$k], $conf);
3099  }
3100  }
3101  $result = implode('', $parts);
3102  if ($conf['htmlSanitize']) {
3103  $result = $this->‪stdWrap_htmlSanitize($result, $conf['htmlSanitize.'] ?? []);
3104  }
3105  return $result;
3106  }
3107 
3116  protected function ‪parseFuncInternal($theValue, $conf)
3117  {
3118  if (!empty($conf['if.']) && !$this->‪checkIf($conf['if.'])) {
3119  return $theValue;
3120  }
3121  // Indicates that the data is from within a tag.
3122  $inside = false;
3123  // Pointer to the total string position
3124  $pointer = 0;
3125  // Loaded with the current typo-tag if any.
3126  $currentTag = null;
3127  $stripNL = 0;
3128  $contentAccum = [];
3129  $contentAccumP = 0;
3130 
3131  $allowTags = ‪GeneralUtility::trimExplode(',', strtolower($conf['allowTags'] ?? ''), true);
3132  $denyTags = ‪GeneralUtility::trimExplode(',', strtolower($conf['denyTags'] ?? ''), true);
3133  $totalLen = strlen($theValue);
3134  do {
3135  if (!$inside) {
3136  if ($currentTag === null) {
3137  // These operations should only be performed on code outside the typotags...
3138  // data: this checks that we enter tags ONLY if the first char in the tag is alphanumeric OR '/'
3139  $len_p = 0;
3140  $c = 100;
3141  do {
3142  $len = strcspn(substr($theValue, $pointer + $len_p), '<');
3143  $len_p += $len + 1;
3144  $endChar = ord(strtolower(substr($theValue, $pointer + $len_p, 1)));
3145  $c--;
3146  } while ($c > 0 && $endChar && ($endChar < 97 || $endChar > 122) && $endChar != 47);
3147  $len = $len_p - 1;
3148  } else {
3149  $len = $this->‪getContentLengthOfCurrentTag($theValue, $pointer, (string)$currentTag[0]);
3150  }
3151  // $data is the content until the next <tag-start or end is detected.
3152  // In case of a currentTag set, this would mean all data between the start- and end-tags
3153  ‪$data = substr($theValue, $pointer, $len);
3154  if ($stripNL) {
3155  // If the previous tag was set to strip NewLines in the beginning of the next data-chunk.
3156  ‪$data = preg_replace('/^[ ]*' . CR . '?' . LF . '/', '', ‪$data);
3157  if (‪$data === null) {
3158  $this->logger->debug('Stripping new lines failed for "{data}"', ['data' => ‪$data]);
3159  ‪$data = '';
3160  }
3161  }
3162  // These operations should only be performed on code outside the tags...
3163  if (!is_array($currentTag)) {
3164  // Short
3165  if (isset($conf['short.']) && is_array($conf['short.'])) {
3166  $shortWords = $conf['short.'];
3167  krsort($shortWords);
3168  foreach ($shortWords as $key => $val) {
3169  if (is_string($val)) {
3170  ‪$data = str_replace($key, $val, ‪$data);
3171  }
3172  }
3173  }
3174  // stdWrap
3175  if (isset($conf['plainTextStdWrap.']) && is_array($conf['plainTextStdWrap.'])) {
3176  ‪$data = $this->‪stdWrap($data, $conf['plainTextStdWrap.']);
3177  }
3178  // userFunc
3179  if ($conf['userFunc'] ?? false) {
3180  ‪$data = $this->‪callUserFunction($conf['userFunc'], $conf['userFunc.'] ?? [], ‪$data);
3181  }
3182  }
3183  // Search for tags to process in current data and
3184  // call this method recursively if found
3185  if (str_contains(‪$data, '<') && isset($conf['tags.']) && is_array($conf['tags.'])) {
3186  // @todo probably use a DOM tree traversal for the whole stuff
3187  // This iterations basically re-processes the markup string, as
3188  // long as there are `<$tag ` or `<$tag>` "tags" found...
3189  foreach (array_keys($conf['tags.']) as $tag) {
3190  // only match tag `a` in `<a href"...">` but not in `<abbr>`
3191  if (preg_match('#<' . $tag . '[\s/>]#', ‪$data)) {
3192  ‪$data = $this->‪parseFuncInternal($data, $conf);
3193  break;
3194  }
3195  }
3196  }
3197  if (!is_array($currentTag) && ($conf['makelinks'] ?? false)) {
3198  ‪$data = $this->‪http_makelinks($data, $conf['makelinks.']['http.'] ?? []);
3199  ‪$data = $this->‪mailto_makelinks($data, $conf['makelinks.']['mailto.'] ?? []);
3200  }
3201  $contentAccum[$contentAccumP] = ($contentAccum[$contentAccumP] ?? '') . ‪$data;
3202  $inside = true;
3203  } else {
3204  // tags
3205  $len = strcspn(substr($theValue, $pointer), '>') + 1;
3206  ‪$data = substr($theValue, $pointer, $len);
3207  if (str_ends_with(‪$data, '/>') && !str_starts_with(‪$data, '<link ')) {
3208  $tagContent = substr(‪$data, 1, -2);
3209  } else {
3210  $tagContent = substr(‪$data, 1, -1);
3211  }
3212  $tag = explode(' ', trim($tagContent), 2);
3213  $tag[0] = strtolower($tag[0]);
3214  // end tag like </li>
3215  if (str_starts_with($tag[0], '/')) {
3216  $tag[0] = substr($tag[0], 1);
3217  $tag['out'] = 1;
3218  }
3219  if ($conf['tags.'][$tag[0]] ?? false) {
3220  $treated = false;
3221  $stripNL = false;
3222  // in-tag
3223  if (!$currentTag && (!isset($tag['out']) || !$tag['out'])) {
3224  // $currentTag (array!) is the tag we are currently processing
3225  $currentTag = $tag;
3226  $contentAccumP++;
3227  $treated = true;
3228  // in-out-tag: img and other empty tags
3229  if (preg_match('/^(area|base|br|col|hr|img|input|meta|param)$/i', (string)$tag[0])) {
3230  $tag['out'] = 1;
3231  }
3232  }
3233  // out-tag
3234  if (isset($currentTag[0], $tag['out']) && $currentTag[0] === $tag[0] && $tag['out']) {
3235  $theName = $conf['tags.'][$tag[0]];
3236  $theConf = $conf['tags.'][$tag[0] . '.'];
3237  // This flag indicates, that NL- (13-10-chars) should be stripped first and last.
3238  $stripNL = (bool)($theConf['stripNL'] ?? false);
3239  // This flag indicates, that this TypoTag section should NOT be included in the nonTypoTag content.
3240  $breakOut = (bool)($theConf['breakoutTypoTagContent'] ?? false);
3241  $this->parameters = [];
3242  if (isset($currentTag[1])) {
3243  // decode HTML entities in attributes, since they're processed
3244  $params = GeneralUtility::get_tag_attributes((string)$currentTag[1], true);
3245  foreach ($params as $option => $val) {
3246  // contains non-encoded values
3247  $this->parameters[strtolower($option)] = $val;
3248  }
3249  $this->parameters['allParams'] = trim((string)$currentTag[1]);
3250  }
3251  // Removes NL in the beginning and end of the tag-content AND at the end of the currentTagBuffer.
3252  // $stripNL depends on the configuration of the current tag
3253  if ($stripNL) {
3254  $contentAccum[$contentAccumP - 1] = preg_replace('/' . CR . '?' . LF . '[ ]*$/', '', $contentAccum[$contentAccumP - 1] ?? '');
3255  $contentAccum[$contentAccumP] = preg_replace('/^[ ]*' . CR . '?' . LF . '/', '', $contentAccum[$contentAccumP] ?? '');
3256  $contentAccum[$contentAccumP] = preg_replace('/' . CR . '?' . LF . '[ ]*$/', '', $contentAccum[$contentAccumP] ?? '');
3257  }
3258  $this->data[‪$this->currentValKey] = $contentAccum[$contentAccumP] ?? null;
3259  $newInput = $this->‪cObjGetSingle($theName, $theConf, '/parseFunc/.tags.' . $tag[0]);
3260  // fetch the content object
3261  $contentAccum[$contentAccumP] = $newInput;
3262  $contentAccumP++;
3263  // If the TypoTag section
3264  if (!$breakOut) {
3265  if (!isset($contentAccum[$contentAccumP - 2])) {
3266  $contentAccum[$contentAccumP - 2] = '';
3267  }
3268  $contentAccum[$contentAccumP - 2] .= ($contentAccum[$contentAccumP - 1] ?? '') . ($contentAccum[$contentAccumP] ?? '');
3269  unset($contentAccum[$contentAccumP]);
3270  unset($contentAccum[$contentAccumP - 1]);
3271  $contentAccumP -= 2;
3272  }
3273  $currentTag = null;
3274  $treated = true;
3275  }
3276  // other tags
3277  if (!$treated) {
3278  $contentAccum[$contentAccumP] .= ‪$data;
3279  }
3280  } else {
3281  $contentAccum[$contentAccumP] = $contentAccum[$contentAccumP] ?? '';
3282  // If a tag was not a typo tag, then it is just added to the content
3283  $stripNL = false;
3284  if (
3285  // Neither allowTags or denyTags set, thus everything is allowed
3286  ($denyTags === [] && $allowTags === [])
3287  // Explicitly allowed
3288  || ($allowTags !== [] && in_array((string)$tag[0], $allowTags, true))
3289  // Explicitly denied or everything "denied" (except for the explicitly allowed)
3290  || ($denyTags !== [] && $denyTags !== ['*'] && !in_array((string)$tag[0], $denyTags))
3291  // All tags are allowed, but not in the denied list above, so this is OK
3292  || ($allowTags === ['*'] && !in_array((string)$tag[0], $denyTags))
3293  ) {
3294  $contentAccum[$contentAccumP] .= ‪$data;
3295  } else {
3296  $contentAccum[$contentAccumP] .= htmlspecialchars(‪$data);
3297  }
3298  }
3299  $inside = false;
3300  }
3301  $pointer += $len;
3302  } while ($pointer < $totalLen);
3303  // Parsing nonTypoTag content (all even keys):
3304  reset($contentAccum);
3305  $contentAccumCount = count($contentAccum);
3306  for ($a = 0; $a < $contentAccumCount; $a++) {
3307  if ($a % 2 != 1) {
3308  // stdWrap
3309  if (isset($conf['nonTypoTagStdWrap.']) && is_array($conf['nonTypoTagStdWrap.'])) {
3310  $contentAccum[$a] = $this->‪stdWrap((string)($contentAccum[$a] ?? ''), $conf['nonTypoTagStdWrap.']);
3311  }
3312  // userFunc
3313  if (!empty($conf['nonTypoTagUserFunc'])) {
3314  $contentAccum[$a] = $this->‪callUserFunction($conf['nonTypoTagUserFunc'], $conf['nonTypoTagUserFunc.'] ?? [], (string)($contentAccum[$a] ?? ''));
3315  }
3316  }
3317  }
3318  return implode('', $contentAccum);
3319  }
3320 
3329  public function ‪encaps_lineSplit($theValue, $conf)
3330  {
3331  if ((string)$theValue === '') {
3332  return '';
3333  }
3334  $lParts = explode(LF, $theValue);
3335 
3336  // When the last element is an empty linebreak we need to remove it, otherwise we will have a duplicate empty line.
3337  $lastPartIndex = count($lParts) - 1;
3338  if ($lParts[$lastPartIndex] === '' && trim($lParts[$lastPartIndex - 1], CR) === '') {
3339  array_pop($lParts);
3340  }
3341 
3342  $encapTags = ‪GeneralUtility::trimExplode(',', strtolower($conf['encapsTagList'] ?? ''), true);
3343  $defaultAlign = trim((string)$this->‪stdWrapValue('defaultAlign', $conf ?? []));
3344 
3345  $str_content = '';
3346  foreach ($lParts as $k => $l) {
3347  $sameBeginEnd = false;
3348  $emptyTag = false;
3349  $l = trim($l);
3350  $attrib = [];
3351  $nonWrapped = false;
3352  $tagName = '';
3353  if (isset($l[0]) && $l[0] === '<' && str_ends_with($l, '>')) {
3354  $fwParts = explode('>', substr($l, 1), 2);
3355  [$tagName] = explode(' ', $fwParts[0], 2);
3356  if (!$fwParts[1]) {
3357  if (str_ends_with($tagName, '/')) {
3358  $tagName = substr($tagName, 0, -1);
3359  }
3360  if (str_ends_with($fwParts[0], '/')) {
3361  $sameBeginEnd = true;
3362  $emptyTag = true;
3363  // decode HTML entities, they're encoded later again
3364  $attrib = GeneralUtility::get_tag_attributes('<' . substr($fwParts[0], 0, -1) . '>', true);
3365  }
3366  } else {
3367  $backParts = ‪GeneralUtility::revExplode('<', substr($fwParts[1], 0, -1), 2);
3368  // decode HTML entities, they're encoded later again
3369  $attrib = GeneralUtility::get_tag_attributes('<' . $fwParts[0] . '>', true);
3370  $str_content = $backParts[0];
3371  // Ensure that $backParts could be exploded into 2 items
3372  if (isset($backParts[1])) {
3373  $sameBeginEnd = strtolower(substr($backParts[1], 1, strlen($tagName))) === strtolower($tagName);
3374  }
3375  }
3376  }
3377  if ($sameBeginEnd && in_array(strtolower($tagName), $encapTags)) {
3378  $uTagName = strtoupper($tagName);
3379  $uTagName = strtoupper($conf['remapTag.'][$uTagName] ?? $uTagName);
3380  } else {
3381  $uTagName = strtoupper($conf['nonWrappedTag'] ?? '');
3382  // The line will be wrapped: $uTagName should not be an empty tag
3383  $emptyTag = false;
3384  $str_content = $lParts[$k];
3385  $nonWrapped = true;
3386  $attrib = [];
3387  }
3388  // Wrapping all inner-content:
3389  if (is_array($conf['innerStdWrap_all.'] ?? null)) {
3390  $str_content = (string)$this->‪stdWrap($str_content, $conf['innerStdWrap_all.']);
3391  }
3392  if ($uTagName) {
3393  // Setting common attributes
3394  if (isset($conf['addAttributes.'][$uTagName . '.']) && is_array($conf['addAttributes.'][$uTagName . '.'])) {
3395  foreach ($conf['addAttributes.'][$uTagName . '.'] as $kk => $vv) {
3396  if (!is_array($vv)) {
3397  if ((string)($conf['addAttributes.'][$uTagName . '.'][$kk . '.']['setOnly'] ?? '') === 'blank') {
3398  if ((string)($attrib[$kk] ?? '') === '') {
3399  $attrib[$kk] = $vv;
3400  }
3401  } elseif ((string)($conf['addAttributes.'][$uTagName . '.'][$kk . '.']['setOnly'] ?? '') === 'exists') {
3402  if (!isset($attrib[$kk])) {
3403  $attrib[$kk] = $vv;
3404  }
3405  } else {
3406  $attrib[$kk] = $vv;
3407  }
3408  }
3409  }
3410  }
3411  // Wrapping all inner-content:
3412  if (isset($conf['encapsLinesStdWrap.'][$uTagName . '.']) && is_array($conf['encapsLinesStdWrap.'][$uTagName . '.'])) {
3413  $str_content = (string)$this->‪stdWrap($str_content, $conf['encapsLinesStdWrap.'][$uTagName . '.']);
3414  }
3415  // Default align
3416  if ((!isset($attrib['align']) || !$attrib['align']) && $defaultAlign) {
3417  $attrib['align'] = $defaultAlign;
3418  }
3419  // implode (insecure) attributes, that's why `htmlspecialchars` is used here
3420  $params = GeneralUtility::implodeAttributes($attrib, true);
3421  if (!isset($conf['removeWrapping']) || !$conf['removeWrapping'] || ($emptyTag && $conf['removeWrapping.']['keepSingleTag'])) {
3422  $selfClosingTagList = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
3423  if ($emptyTag && in_array(strtolower($uTagName), $selfClosingTagList, true)) {
3424  $str_content = '<' . strtolower($uTagName) . (trim($params) ? ' ' . trim($params) : '') . ' />';
3425  } else {
3426  $str_content = '<' . strtolower($uTagName) . (trim($params) ? ' ' . trim($params) : '') . '>' . $str_content . '</' . strtolower($uTagName) . '>';
3427  }
3428  }
3429  }
3430  if ($nonWrapped && isset($conf['wrapNonWrappedLines']) && $conf['wrapNonWrappedLines']) {
3431  $str_content = $this->‪wrap($str_content, $conf['wrapNonWrappedLines']);
3432  }
3433  $lParts[$k] = $str_content;
3434  }
3435  return implode(LF, $lParts);
3436  }
3437 
3450  protected function ‪http_makelinks(string ‪$data, array $conf): string
3451  {
3452  $parts = [];
3453  foreach (['http://', 'https://'] as $scheme) {
3454  $textpieces = explode($scheme, ‪$data);
3455  $pieces = count($textpieces);
3456  $textstr = $textpieces[0];
3457  for ($i = 1; $i < $pieces; $i++) {
3458  $len = strcspn($textpieces[$i], chr(32) . "\t" . CRLF);
3459  if (!(trim(substr($textstr, -1)) === '' && $len)) {
3460  $textstr .= $scheme . $textpieces[$i];
3461  continue;
3462  }
3463  $lastChar = substr($textpieces[$i], $len - 1, 1);
3464  if (!preg_match('/[A-Za-z0-9\\/#_-]/', $lastChar)) {
3465  $len--;
3466  }
3467  // Included '\/' 3/12
3468  $parts[0] = substr($textpieces[$i], 0, $len);
3469  $parts[1] = substr($textpieces[$i], $len);
3470  $keep = $conf['keep'] ?? '';
3471  $linkParts = parse_url($scheme . $parts[0]);
3472  // Check if link couldn't be parsed properly
3473  if (!is_array($linkParts)) {
3474  $textstr .= $scheme . $textpieces[$i];
3475  continue;
3476  }
3477  $linktxt = '';
3478  if (str_contains($keep, 'scheme')) {
3479  $linktxt = $scheme;
3480  }
3481  $linktxt .= $linkParts['host'] ?? '';
3482  if (str_contains($keep, 'path')) {
3483  $linktxt .= ($linkParts['path'] ?? '');
3484  // Added $linkParts['query'] 3/12
3485  if (str_contains($keep, 'query') && $linkParts['query']) {
3486  $linktxt .= '?' . $linkParts['query'];
3487  } elseif (($linkParts['path'] ?? '') === '/') {
3488  $linktxt = substr($linktxt, 0, -1);
3489  }
3490  }
3491  $typolinkConfiguration = $conf;
3492  $typolinkConfiguration['parameter'] = $scheme . $parts[0];
3493  $textstr .= $this->‪typoLink($linktxt, $typolinkConfiguration) . $parts[1];
3494  }
3495  ‪$data = $textstr;
3496  }
3497  return $textstr;
3498  }
3499 
3511  protected function ‪mailto_makelinks(string ‪$data, array $conf): string
3512  {
3513  $conf = (array)$conf;
3514  $parts = [];
3515  // split by mailto logic
3516  $textpieces = explode('mailto:', ‪$data);
3517  $pieces = count($textpieces);
3518  $textstr = $textpieces[0] ?? '';
3519  for ($i = 1; $i < $pieces; $i++) {
3520  $len = strcspn($textpieces[$i], chr(32) . "\t" . CRLF);
3521  if (trim(substr($textstr, -1)) === '' && $len) {
3522  $lastChar = substr($textpieces[$i], $len - 1, 1);
3523  if (!preg_match('/[A-Za-z0-9]/', $lastChar)) {
3524  $len--;
3525  }
3526  $parts[0] = substr($textpieces[$i], 0, $len);
3527  $parts[1] = substr($textpieces[$i], $len);
3528  $linktxt = (string)preg_replace('/\\?.*/', '', $parts[0]);
3529  $typolinkConfiguration = $conf;
3530  $typolinkConfiguration['parameter'] = 'mailto:' . $parts[0];
3531  $textstr .= (string)$this->‪typoLink($linktxt, $typolinkConfiguration) . $parts[1];
3532  } else {
3533  $textstr .= 'mailto:' . $textpieces[$i];
3534  }
3535  }
3536  return $textstr;
3537  }
3538 
3564  public function ‪getImgResource($file, $fileArray)
3565  {
3566  $importedFile = null;
3567  $fileReference = null;
3568  if (empty($file) && empty($fileArray)) {
3569  return null;
3570  }
3571  if (!is_array($fileArray)) {
3572  $fileArray = (array)$fileArray;
3573  }
3574  $imageResource = null;
3575  if ($file === 'GIFBUILDER') {
3576  $gifBuilder = GeneralUtility::makeInstance(GifBuilder::class);
3577  $gifBuilder->start($fileArray, $this->data);
3578  $imageResource = $gifBuilder->gifBuild();
3579  } else {
3580  if ($file instanceof File) {
3581  $fileObject = $file;
3582  } elseif ($file instanceof FileReference) {
3583  $fileReference = $file;
3584  $fileObject = $file->getOriginalFile();
3585  } else {
3586  try {
3587  if (isset($fileArray['import.']) && $fileArray['import.']) {
3588  $importedFile = trim((string)$this->‪stdWrap('', $fileArray['import.']));
3589  if (!empty($importedFile)) {
3590  $file = $importedFile;
3591  }
3592  }
3593 
3595  $treatIdAsReference = $this->‪stdWrapValue('treatIdAsReference', $fileArray);
3596  if (!empty($treatIdAsReference)) {
3597  $fileReference = $this->‪getResourceFactory()->getFileReferenceObject((int)$file);
3598  $fileObject = $fileReference->getOriginalFile();
3599  } else {
3600  $fileObject = $this->‪getResourceFactory()->getFileObject((int)$file);
3601  }
3602  } elseif (preg_match('/^(0|[1-9][0-9]*):/', $file)) { // combined identifier
3603  $fileObject = $this->‪getResourceFactory()->retrieveFileOrFolderObject($file);
3604  } else {
3605  if ($importedFile && !empty($fileArray['import'])) {
3606  $file = $fileArray['import'] . $file;
3607  }
3608  $fileObject = $this->‪getResourceFactory()->retrieveFileOrFolderObject($file);
3609  }
3610  } catch (Exception $exception) {
3611  $this->logger->warning('The image "{file}" could not be found and won\'t be included in frontend output', [
3612  'file' => $file,
3613  'exception' => $exception,
3614  ]);
3615  return null;
3616  }
3617  }
3618  if ($fileObject instanceof File) {
3619  $processingConfiguration['width'] = $this->‪stdWrapValue('width', $fileArray);
3620  $processingConfiguration['height'] = $this->‪stdWrapValue('height', $fileArray);
3621  $processingConfiguration['fileExtension'] = $this->‪stdWrapValue('ext', $fileArray);
3622  $processingConfiguration['maxWidth'] = (int)$this->‪stdWrapValue('maxW', $fileArray);
3623  $processingConfiguration['maxHeight'] = (int)$this->‪stdWrapValue('maxH', $fileArray);
3624  $processingConfiguration['minWidth'] = (int)$this->‪stdWrapValue('minW', $fileArray);
3625  $processingConfiguration['minHeight'] = (int)$this->‪stdWrapValue('minH', $fileArray);
3626  $processingConfiguration['noScale'] = $this->‪stdWrapValue('noScale', $fileArray);
3627  $processingConfiguration['sample'] = (bool)$this->‪stdWrapValue('sample', $fileArray);
3628  $processingConfiguration['additionalParameters'] = $this->‪stdWrapValue('params', $fileArray);
3629  $processingConfiguration['frame'] = (int)$this->‪stdWrapValue('frame', $fileArray);
3630  if ($fileReference === null) {
3631  $processingConfiguration['crop'] = $this->‪getCropAreaFromFromTypoScriptSettings($fileObject, $fileArray);
3632  } else {
3633  $processingConfiguration['crop'] = $this->‪getCropAreaFromFileReference($fileReference, $fileArray);
3634  }
3635 
3636  // Possibility to cancel/force profile extraction
3637  // see $GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_stripColorProfileParameters']
3638  if (isset($fileArray['stripProfile'])) {
3639  $processingConfiguration['stripProfile'] = $fileArray['stripProfile'];
3640  }
3641  // Check if we can handle this type of file for editing
3642  if ($fileObject->isImage()) {
3643  $maskArray = $fileArray['m.'] ?? false;
3644  // Must render mask images and include in hash-calculating
3645  // - otherwise we cannot be sure the filename is unique for the setup!
3646  if (is_array($maskArray)) {
3647  $processingConfiguration['maskImages']['maskImage'] = $this->‪getImgResource($maskArray['mask'] ?? '', $maskArray['mask.'] ?? [])?->getProcessedFile();
3648  $processingConfiguration['maskImages']['backgroundImage'] = $this->‪getImgResource($maskArray['bgImg'] ?? '', $maskArray['bgImg.'] ?? [])?->getProcessedFile();
3649  $processingConfiguration['maskImages']['maskBottomImage'] = $this->‪getImgResource($maskArray['bottomImg'] ?? '', $maskArray['bottomImg.'] ?? [])?->getProcessedFile();
3650  $processingConfiguration['maskImages']['maskBottomImageMask'] = $this->‪getImgResource($maskArray['bottomImg_mask'] ?? '', $maskArray['bottomImg_mask.'] ?? [])?->getProcessedFile();
3651  }
3652  $processedFileObject = $fileObject->process(‪ProcessedFile::CONTEXT_IMAGECROPSCALEMASK, $processingConfiguration);
3653  if ($processedFileObject->isProcessed()) {
3654  $imageResource = ImageResource::createFromProcessedFile($processedFileObject);
3655  }
3656  }
3657  } elseif ($fileObject instanceof ProcessedFile) {
3658  $imageResource = ImageResource::createFromProcessedFile($fileObject);
3659  }
3660  }
3661 
3662  return GeneralUtility::makeInstance(EventDispatcherInterface::class)->dispatch(
3663  new AfterImageResourceResolvedEvent($file, $fileArray, $imageResource)
3664  )->getImageResource();
3665  }
3666 
3684  protected function ‪getCropAreaFromFileReference(FileReference $fileReference, array $fileArray)
3685  {
3686  // Use cropping area from file reference if nothing is configured in TypoScript.
3687  if (!isset($fileArray['crop']) && !isset($fileArray['crop.'])) {
3688  // Set crop variant from TypoScript settings. If not set, use default.
3689  $cropVariant = $fileArray['cropVariant'] ?? 'default';
3690  $fileCropArea = $this->‪createCropAreaFromJsonString((string)$fileReference->getProperty('crop'), $cropVariant);
3691  return $fileCropArea->isEmpty() ? null : $fileCropArea->makeAbsoluteBasedOnFile($fileReference);
3692  }
3693 
3694  return $this->‪getCropAreaFromFromTypoScriptSettings($fileReference, $fileArray);
3695  }
3696 
3703  protected function ‪getCropAreaFromFromTypoScriptSettings(FileInterface $file, array $fileArray)
3704  {
3706  $cropArea = null;
3707  // Resolve TypoScript configured cropping.
3708  $cropSettings = isset($fileArray['crop.'])
3709  ? $this->‪stdWrap($fileArray['crop'] ?? '', $fileArray['crop.'])
3710  : ($fileArray['crop'] ?? null);
3711 
3712  if (is_string($cropSettings)) {
3713  // Set crop variant from TypoScript settings. If not set, use default.
3714  $cropVariant = $fileArray['cropVariant'] ?? 'default';
3715  // Get cropArea from CropVariantCollection, if cropSettings is a valid json.
3716  // CropVariantCollection::create does json_decode.
3717  $jsonCropArea = $this->‪createCropAreaFromJsonString($cropSettings, $cropVariant);
3718  $cropArea = $jsonCropArea->isEmpty() ? null : $jsonCropArea->makeAbsoluteBasedOnFile($file);
3719 
3720  // Cropping is configured in TypoScript in the following way: file.crop = 50,50,100,100
3721  if ($jsonCropArea->isEmpty() && preg_match('/^[0-9]+,[0-9]+,[0-9]+,[0-9]+$/', $cropSettings)) {
3722  $cropSettings = explode(',', $cropSettings);
3723  if (count($cropSettings) === 4) {
3724  $cropSettings = array_map(floatval(...), $cropSettings);
3725  $stringCropArea = GeneralUtility::makeInstance(
3726  Area::class,
3727  ...$cropSettings
3728  );
3729  $cropArea = $stringCropArea->isEmpty() ? null : $stringCropArea;
3730  }
3731  }
3732  }
3733 
3734  return $cropArea;
3735  }
3736 
3741  protected function ‪createCropAreaFromJsonString(string $cropSettings, string $cropVariant): ‪Area
3742  {
3743  return ‪CropVariantCollection::create($cropSettings)->getCropArea($cropVariant);
3744  }
3745 
3746  /***********************************************
3747  *
3748  * Data retrieval etc.
3749  *
3750  ***********************************************/
3757  public function ‪getFieldVal($field)
3758  {
3759  if (!str_contains($field, '//')) {
3760  return $this->data[trim($field)] ?? null;
3761  }
3762  $sections = ‪GeneralUtility::trimExplode('//', $field, true);
3763  foreach ($sections as $k) {
3764  if ((string)($this->data[$k] ?? '') !== '') {
3765  return $this->data[$k];
3766  }
3767  }
3768 
3769  return '';
3770  }
3771 
3783  public function ‪getData($string, $fieldArray = null)
3784  {
3785  if (!is_array($fieldArray)) {
3786  $fieldArray = $this->‪getRequest()->getAttribute('frontend.page.information')->getPageRecord();
3787  }
3788  $retVal = '';
3789  // @todo: getData should not be called with non-string as $string. example trigger:
3790  // SecureHtmlRenderingTest htmlViewHelperAvoidsCrossSiteScripting set #07 PHP 8
3791  $sections = is_string($string) ? explode('//', $string) : [];
3792  foreach ($sections as $secVal) {
3793  if ($retVal) {
3794  break;
3795  }
3796  $parts = explode(':', $secVal, 2);
3797  $type = strtolower(trim($parts[0]));
3798  $typesWithOutParameters = ['level', 'date', 'current', 'pagelayout', 'applicationcontext'];
3799  $key = trim($parts[1] ?? '');
3800  if (($key != '') || in_array($type, $typesWithOutParameters)) {
3801  switch ($type) {
3802  case 'gp':
3803  // Merge GET and POST and get $key out of the merged array
3804  $requestParameters = $this->‪getRequest()->getQueryParams();
3805  $requestParameters = array_replace_recursive($requestParameters, (array)$this->‪getRequest()->getParsedBody());
3806  $retVal = $this->‪getGlobal($key, $requestParameters);
3807  break;
3808  case 'request':
3809  $retVal = $this->‪getValueFromRecursiveData(‪GeneralUtility::trimExplode('|', $key), $this->‪getRequest());
3810  break;
3811  case 'tsfe':
3812  // @todo: This needs a bigger cleanup / deprecation when TypoScriptFrontendController continues to remove properties.
3813  $valueParts = ‪GeneralUtility::trimExplode('|', $key);
3814  if (($valueParts[0] ?? '') === 'fe_user') {
3815  $frontendUser = $this->‪getRequest()->getAttribute('frontend.user');
3816  array_shift($valueParts);
3817  $retVal = $this->‪getValueFromRecursiveData($valueParts, $frontendUser);
3818  } elseif (($valueParts[0] ?? '') === 'linkVars') {
3819  $typoScriptConfigArray = $this->‪getRequest()->getAttribute('frontend.typoscript')->getConfigArray();
3820  $typoScriptConfigLinkVars = (string)($typoScriptConfigArray['linkVars'] ?? '');
3821  $retVal = GeneralUtility::makeInstance(LinkVarsCalculator::class)
3822  ->getAllowedLinkVarsFromRequest(
3823  $typoScriptConfigLinkVars,
3824  $this->‪getRequest()->getQueryParams(),
3825  GeneralUtility::makeInstance(Context::class)
3826  );
3827  } else {
3828  $retVal = $this->‪getValueFromRecursiveData($valueParts, $this->‪getTypoScriptFrontendController());
3829  }
3830  break;
3831  case 'getenv':
3832  $retVal = getenv($key);
3833  break;
3834  case 'getindpenv':
3835  $retVal = $this->‪getEnvironmentVariable($key);
3836  break;
3837  case 'field':
3838  $retVal = $this->‪getGlobal($key, $fieldArray);
3839  break;
3840  case 'file':
3841  $retVal = $this->‪getFileDataKey($key);
3842  break;
3843  case 'asset':
3844  $absoluteFilePath = GeneralUtility::getFileAbsFileName($key);
3845  if ($absoluteFilePath === '') {
3846  throw new \RuntimeException('Asset "' . $key . '" not found', 1670713983);
3847  }
3848  $retVal = GeneralUtility::createVersionNumberedFilename(‪PathUtility::getAbsoluteWebPath($absoluteFilePath));
3849  break;
3850  case 'parameters':
3851  $retVal = $this->parameters[$key] ?? null;
3852  break;
3853  case 'register':
3854  $tsfe = $this->‪getTypoScriptFrontendController();
3855  $retVal = $tsfe->register[$key] ?? null;
3856  break;
3857  case 'global':
3858  $retVal = $this->‪getGlobal($key);
3859  break;
3860  case 'level':
3861  $localRootLine = $this->‪getRequest()->getAttribute('frontend.page.information')->getLocalRootLine();
3862  $retVal = count($localRootLine) - 1;
3863  break;
3864  case 'leveltitle':
3865  $keyParts = ‪GeneralUtility::trimExplode(',', $key);
3866  $pointer = (int)($keyParts[0] ?? 0);
3867  $slide = $keyParts[1] ?? '';
3868  $localRootLine = $this->‪getRequest()->getAttribute('frontend.page.information')->getLocalRootLine();
3869  $numericKey = $this->‪getKey($pointer, $localRootLine);
3870  $retVal = $this->‪rootLineValue($numericKey, 'title', strtolower($slide) === 'slide');
3871  break;
3872  case 'levelmedia':
3873  $keyParts = ‪GeneralUtility::trimExplode(',', $key);
3874  $pointer = (int)($keyParts[0] ?? 0);
3875  $slide = $keyParts[1] ?? '';
3876  $localRootLine = $this->‪getRequest()->getAttribute('frontend.page.information')->getLocalRootLine();
3877  $numericKey = $this->‪getKey($pointer, $localRootLine);
3878  $retVal = $this->‪rootLineValue($numericKey, 'media', strtolower($slide) === 'slide');
3879  break;
3880  case 'leveluid':
3881  $localRootLine = $this->‪getRequest()->getAttribute('frontend.page.information')->getLocalRootLine();
3882  $numericKey = $this->‪getKey((int)$key, $localRootLine);
3883  $retVal = $this->‪rootLineValue($numericKey, 'uid');
3884  break;
3885  case 'levelfield':
3886  $keyParts = ‪GeneralUtility::trimExplode(',', $key);
3887  $pointer = (int)($keyParts[0] ?? 0);
3888  $field = $keyParts[1] ?? '';
3889  $slide = $keyParts[2] ?? '';
3890  $localRootLine = $this->‪getRequest()->getAttribute('frontend.page.information')->getLocalRootLine();
3891  $numericKey = $this->‪getKey($pointer, $localRootLine);
3892  $retVal = $this->‪rootLineValue($numericKey, $field, strtolower($slide) === 'slide');
3893  break;
3894  case 'fullrootline':
3895  $keyParts = ‪GeneralUtility::trimExplode(',', $key);
3896  $pointer = (int)($keyParts[0] ?? 0);
3897  $field = $keyParts[1] ?? '';
3898  $slide = $keyParts[2] ?? '';
3899  $rootLine = $this->‪getRequest()->getAttribute('frontend.page.information')->getRootLine();
3900  $localRootLine = $this->‪getRequest()->getAttribute('frontend.page.information')->getLocalRootLine();
3901  $fullKey = $pointer - count($localRootLine) + count($rootLine);
3902  if ($fullKey >= 0) {
3903  $retVal = $this->‪rootLineValue($fullKey, $field, stristr($slide, 'slide') !== false, $rootLine);
3904  }
3905  break;
3906  case 'date':
3907  if (!$key) {
3908  $key = 'd/m Y';
3909  }
3910  $retVal = date($key, ‪$GLOBALS['EXEC_TIME']);
3911  break;
3912  case 'page':
3913  $pageRecord = $this->‪getRequest()->getAttribute('frontend.page.information')->getPageRecord();
3914  $retVal = $pageRecord[$key] ?? '';
3915  break;
3916  case 'pagelayout':
3917  $pageInformation = $this->‪getRequest()->getAttribute('frontend.page.information');
3918  $pageLayoutResolver = GeneralUtility::makeInstance(PageLayoutResolver::class);
3919  $retVal = $pageLayoutResolver->getLayoutIdentifierForPage($pageInformation->getPageRecord(), $pageInformation->getRootLine());
3920  break;
3921  case 'current':
3922  $retVal = $this->data[‪$this->currentValKey] ?? null;
3923  break;
3924  case 'db':
3925  $selectParts = ‪GeneralUtility::trimExplode(':', $key, true);
3926  if (!isset($selectParts[1])) {
3927  break;
3928  }
3929  $pageRepository = $this->‪getPageRepository();
3930  $dbRecord = $pageRepository->getRawRecord($selectParts[0], (int)$selectParts[1]);
3931  if (is_array($dbRecord) && isset($selectParts[2])) {
3932  $retVal = $dbRecord[$selectParts[2]] ?? '';
3933  }
3934  break;
3935  case 'lll':
3936  // @todo: Check when/if there are scenarios where attribute 'language' is not yet set in $request.
3937  $language = $this->‪getRequest()->getAttribute('language') ?? $this->‪getRequest()->getAttribute('site')->getDefaultLanguage();
3938  $languageService = GeneralUtility::makeInstance(LanguageServiceFactory::class)->createFromSiteLanguage($language);
3939  $retVal = $languageService->sL('LLL:' . $key);
3940  break;
3941  case 'path':
3942  try {
3943  $retVal = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($key);
3944  } catch (Exception) {
3945  // do nothing in case the file path is invalid
3946  $retVal = null;
3947  }
3948  break;
3949  case 'cobj':
3950  switch ($key) {
3951  case 'parentRecordNumber':
3952  $retVal = ‪$this->parentRecordNumber;
3953  break;
3954  }
3955  break;
3956  case 'debug':
3957  switch ($key) {
3958  case 'rootLine':
3959  $retVal = ‪DebugUtility::viewArray($this->‪getRequest()->getAttribute('frontend.page.information')->getLocalRootLine());
3960  break;
3961  case 'fullRootLine':
3962  $retVal = ‪DebugUtility::viewArray($this->‪getRequest()->getAttribute('frontend.page.information')->getRootLine());
3963  break;
3964  case 'data':
3965  $retVal = ‪DebugUtility::viewArray($this->data);
3966  break;
3967  case 'register':
3968  $tsfe = $this->‪getTypoScriptFrontendController();
3969  $retVal = ‪DebugUtility::viewArray($tsfe->register);
3970  break;
3971  case 'page':
3972  $retVal = ‪DebugUtility::viewArray($this->‪getRequest()->getAttribute('frontend.page.information')->getPageRecord());
3973  break;
3974  }
3975  break;
3976  case 'flexform':
3977  $keyParts = ‪GeneralUtility::trimExplode(':', $key, true);
3978  if (count($keyParts) === 2 && isset($this->data[$keyParts[0]])) {
3979  $flexFormContent = $this->data[$keyParts[0]];
3980  if (!empty($flexFormContent)) {
3981  $flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
3982  $flexFormKey = str_replace('.', '|', $keyParts[1]);
3983  $settings = $flexFormService->convertFlexFormContentToArray($flexFormContent);
3984  $retVal = $this->‪getGlobal($flexFormKey, $settings);
3985  }
3986  }
3987  break;
3988  case 'session':
3989  $keyParts = ‪GeneralUtility::trimExplode('|', $key, true);
3990  $sessionKey = array_shift($keyParts);
3991  $retVal = $this->‪getRequest()->getAttribute('frontend.user')->getSessionData($sessionKey);
3992  foreach ($keyParts as $keyPart) {
3993  if (is_object($retVal)) {
3994  $retVal = $retVal->{$keyPart};
3995  } elseif (is_array($retVal)) {
3996  $retVal = $retVal[$keyPart];
3997  } else {
3998  $retVal = '';
3999  break;
4000  }
4001  }
4002  if (!is_scalar($retVal)) {
4003  $retVal = '';
4004  }
4005  break;
4006  case 'context':
4007  $context = GeneralUtility::makeInstance(Context::class);
4008  [$aspectName, $propertyName] = ‪GeneralUtility::trimExplode(':', $key, true, 2);
4009  $retVal = $context->getPropertyFromAspect($aspectName, $propertyName, '');
4010  if (is_array($retVal)) {
4011  $retVal = implode(',', $retVal);
4012  }
4013  if (!is_scalar($retVal)) {
4014  $retVal = '';
4015  }
4016  break;
4017  case 'site':
4018  $site = $this->‪getRequest()->getAttribute('site');
4019  if ($key === 'identifier') {
4020  $retVal = $site->getIdentifier();
4021  } elseif ($key === 'base') {
4022  $retVal = $site->getBase();
4023  } else {
4024  try {
4025  $retVal = ‪ArrayUtility::getValueByPath($site->getConfiguration(), $key, '.');
4026  } catch (MissingArrayPathException $exception) {
4027  $this->logger->notice('Configuration "{key}" is not defined for site "{site}"', ['key' => $key, 'site' => $site->getIdentifier(), 'exception' => $exception]);
4028  }
4029  }
4030  break;
4031  case 'sitelanguage':
4032  // @todo: Check when/if there are scenarios where attribute 'language' is not yet set in $request.
4033  $siteLanguage = $this->‪getRequest()->getAttribute('language') ?? $this->‪getRequest()->getAttribute('site')->getDefaultLanguage();
4034  if ($key === 'twoLetterIsoCode') {
4035  $key = 'locale:languageCode';
4036  }
4037  if ($key === 'hreflang') {
4038  $key = 'locale:full';
4039  }
4040  // Harmonizing the namings from the site configuration value with the TypoScript setting
4041  if ($key === 'flag') {
4042  $key = 'flagIdentifier';
4043  }
4044  // Special handling for the locale object
4045  if (str_starts_with($key, 'locale')) {
4046  $localeObject = $siteLanguage->getLocale();
4047  if ($key === 'locale') {
4048  // backwards-compatibility
4049  $retVal = $localeObject->posixFormatted();
4050  } else {
4051  $keyParts = explode(':', $key, 2);
4052  switch ($keyParts[1] ?? '') {
4053  case 'languageCode':
4054  $retVal = $localeObject->getLanguageCode();
4055  break;
4056  case 'countryCode':
4057  $retVal = $localeObject->getCountryCode();
4058  break;
4059  case 'full':
4060  default:
4061  $retVal = $localeObject->getName();
4062  }
4063  }
4064  } else {
4065  $config = $siteLanguage->toArray();
4066  if (isset($config[$key])) {
4067  $retVal = $config[$key] ?? '';
4068  }
4069  }
4070  break;
4071  case 'sitesettings':
4072  $siteSettings = $this->‪getRequest()->getAttribute('site')->getSettings();
4073  $retVal = $siteSettings->get($key, '');
4074  break;
4075  case 'applicationcontext':
4076  $retVal = ‪Environment::getContext()->__toString();
4077  break;
4078  }
4079  }
4080  }
4081 
4082  return GeneralUtility::makeInstance(EventDispatcherInterface::class)->dispatch(
4083  new ‪AfterGetDataResolvedEvent($string, $fieldArray, $retVal, $this)
4084  )->getResult();
4085  }
4086 
4096  protected function getFileDataKey($key)
4097  {
4098  [$fileUidOrCurrentKeyword, $requestedFileInformationKey] = ‪GeneralUtility::trimExplode(':', $key, false, 3);
4099  try {
4100  if ($fileUidOrCurrentKeyword === 'current') {
4101  $fileObject = $this->getCurrentFile();
4102  } elseif (‪MathUtility::canBeInterpretedAsInteger($fileUidOrCurrentKeyword)) {
4103  $fileFactory = GeneralUtility::makeInstance(ResourceFactory::class);
4104  $fileObject = $fileFactory->getFileObject((int)$fileUidOrCurrentKeyword);
4105  } else {
4106  $fileObject = null;
4107  }
4108  } catch (Exception $exception) {
4109  $this->logger->warning('The file "{uid}" could not be found and won\'t be included in frontend output', ['uid' => $fileUidOrCurrentKeyword, 'exception' => $exception]);
4110  $fileObject = null;
4111  }
4112 
4113  if ($fileObject instanceof FileInterface) {
4114  // All properties of the \TYPO3\CMS\Core\Resource\FileInterface are available here:
4115  switch ($requestedFileInformationKey) {
4116  case 'name':
4117  return $fileObject->getName();
4118  case 'uid':
4119  if (method_exists($fileObject, 'getUid')) {
4120  return $fileObject->getUid();
4121  }
4122  return 0;
4123  case 'originalUid':
4124  if ($fileObject instanceof FileReference) {
4125  return $fileObject->getOriginalFile()->getUid();
4126  }
4127  return null;
4128  case 'size':
4129  return $fileObject->getSize();
4130  case 'sha1':
4131  return $fileObject->getSha1();
4132  case 'extension':
4133  return $fileObject->getExtension();
4134  case 'mimetype':
4135  return $fileObject->getMimeType();
4136  case 'contents':
4137  return $fileObject->getContents();
4138  case 'publicUrl':
4139  return $fileObject->getPublicUrl();
4140  default:
4141  // Generic alternative here
4142  return $fileObject->getProperty($requestedFileInformationKey);
4143  }
4144  } else {
4145  // @todo fail silently as is common in tslib_content
4146  return 'Error: no file object';
4147  }
4148  }
4149 
4161  protected function rootLineValue($key, $field, $slideBack = false, $altRootLine = ''): string
4162  {
4163  if (is_array($altRootLine)) {
4164  $rootLine = $altRootLine;
4165  } else {
4166  $rootLine = $this->getRequest()->getAttribute('frontend.page.information')->getLocalRootLine();
4167  }
4168  if (!$slideBack) {
4169  return $rootLine[$key][$field] ?? '';
4170  }
4171  for ($a = $key; $a >= 0; $a--) {
4172  $val = $rootLine[$a][$field] ?? '';
4173  if ($val) {
4174  return $val;
4175  }
4176  }
4177  return '';
4178  }
4179 
4189  public function getGlobal($keyString, $source = null)
4190  {
4191  $keys = ‪GeneralUtility::trimExplode('|', $keyString);
4192  // remove the first key, as this is only used for finding the original value
4193  $rootKey = array_shift($keys);
4194  $value = isset($source) ? ($source[$rootKey] ?? '') : (‪$GLOBALS[$rootKey] ?? '');
4195  return $this->getValueFromRecursiveData($keys, $value);
4196  }
4197 
4204  protected function getValueFromRecursiveData(array $keys, mixed $startValue): int|float|string
4205  {
4206  $value = $startValue;
4207  $numberOfLevels = count($keys);
4208  for ($i = 0; $i < $numberOfLevels && isset($value); $i++) {
4209  $currentKey = $keys[$i];
4210  if (is_object($value)) {
4211  // getter method
4212  if (method_exists($value, 'get' . ucfirst($currentKey))) {
4213  $getterMethod = 'get' . ucfirst($currentKey);
4214  $value = $value->$getterMethod(...)();
4215  // server request attribute, such as "routing"
4216  } elseif ($value instanceof ServerRequestInterface) {
4217  $value = $value->getAttribute($currentKey);
4218  } else {
4219  // Public property
4220  $value = $value->{$currentKey};
4221  }
4222  } elseif (is_array($value)) {
4223  $value = $value[$currentKey] ?? '';
4224  } else {
4225  $value = '';
4226  break;
4227  }
4228  }
4229  if (!is_scalar($value)) {
4230  $value = '';
4231  }
4232  return $value;
4233  }
4234 
4245  public function getKey($key, $arr)
4246  {
4247  $key = (int)$key;
4248  if (is_array($arr)) {
4249  if ($key < 0) {
4250  $key = count($arr) + $key;
4251  }
4252  if ($key < 0) {
4253  $key = 0;
4254  }
4255  }
4256  return $key;
4257  }
4258 
4259  /***********************************************
4260  *
4261  * Link functions (typolink)
4262  *
4263  ***********************************************/
4264 
4283  public function typoLink(string $linkText, array $conf)
4284  {
4285  try {
4286  $linkResult = $this->createLink($linkText, $conf);
4287  } catch (UnableToLinkException $e) {
4288  return $e->getLinkText();
4289  }
4290 
4291  // If flag "returnLast" set, then just return the latest URL / url / target that was built.
4292  // This returns the information without being wrapped in a "LinkResult" object.
4293  switch ($conf['returnLast'] ?? null) {
4294  case 'url':
4295  return $linkResult->getUrl();
4296  case 'target':
4297  return $linkResult->getTarget();
4298  case 'result':
4299  // kept for backwards-compatibility, as this was added in TYPO3 v11
4300  return LinkResult::adapt($linkResult, LinkResult::STRING_CAST_JSON);
4301  }
4302 
4303  $wrap = (string)$this->stdWrapValue('wrap', $conf);
4304  if ($conf['ATagBeforeWrap'] ?? false) {
4305  $linkResult = $linkResult->withLinkText($this->wrap((string)$linkResult->getLinkText(), $wrap));
4306  return LinkResult::adapt($linkResult)->getHtml();
4307  }
4308  $result = LinkResult::adapt($linkResult)->getHtml();
4309  return $this->wrap($result, $wrap);
4310  }
4311 
4329  public function createLink(string $linkText, array $conf): LinkResultInterface
4330  {
4331  $this->lastTypoLinkResult = null;
4332  try {
4333  $linkResult = GeneralUtility::makeInstance(LinkFactory::class)->create($linkText, $conf, $this);
4334  } catch (UnableToLinkException $e) {
4335  // URL could not be generated
4336  throw $e;
4337  }
4338 
4339  $this->lastTypoLinkResult = $linkResult;
4340  return $linkResult;
4341  }
4342 
4352  public function createUrl(array $conf): string
4353  {
4354  try {
4355  return $this->createLink('', $conf)->getUrl();
4356  } catch (‪UnableToLinkException $e) {
4357  // URL could not be generated
4358  return '';
4359  }
4360  }
4361 
4369  public function typoLink_URL($conf)
4370  {
4371  return $this->createUrl($conf ?? []);
4372  }
4373 
4374  /***********************************************
4375  *
4376  * Miscellaneous functions, stand alone
4377  *
4378  ***********************************************/
4390  public function wrap($content, $wrap, $char = '|')
4391  {
4392  if ($wrap) {
4393  $wrapArr = explode($char, $wrap);
4394  $content = trim($wrapArr[0] ?? '') . $content . trim($wrapArr[1] ?? '');
4395  }
4396  return $content;
4397  }
4398 
4409  public function noTrimWrap($content, $wrap, $char = '|')
4410  {
4411  if ($wrap) {
4412  // expects to be wrapped with (at least) 3 characters (before, middle, after)
4413  // anything else is not taken into account
4414  $wrapArr = explode($char, $wrap, 4);
4415  $content = ($wrapArr[1] ?? '') . $content . ($wrapArr[2] ?? '');
4416  }
4417  return $content;
4418  }
4419 
4429  public function callUserFunction($funcName, $conf, $content)
4430  {
4431  // Split parts
4432  $parts = explode('->', $funcName);
4433  if (count($parts) === 2) {
4434  // Check whether PHP class is available
4435  if (class_exists($parts[0])) {
4436  if ($this->container && $this->container->has($parts[0])) {
4437  $classObj = $this->container->get($parts[0]);
4438  } else {
4439  $classObj = GeneralUtility::makeInstance($parts[0]);
4440  }
4441  $methodName = (string)$parts[1];
4442  $callable = [$classObj, $methodName];
4443 
4444  if (is_object($classObj) && method_exists($classObj, $parts[1]) && is_callable($callable)) {
4445  if (method_exists($classObj, 'setContentObjectRenderer') && is_callable([$classObj, 'setContentObjectRenderer'])) {
4446  $classObj->setContentObjectRenderer($this);
4447  }
4448  $content = $callable($content, $conf, $this->getRequest()->withAttribute('currentContentObject', $this));
4449  } else {
4450  $this->getTimeTracker()->setTSlogMessage('Method "' . $parts[1] . '" did not exist in class "' . $parts[0] . '"', LogLevel::ERROR);
4451  }
4452  } else {
4453  $this->getTimeTracker()->setTSlogMessage('Class "' . $parts[0] . '" did not exist', LogLevel::ERROR);
4454  }
4455  } elseif (function_exists($funcName)) {
4456  $content = $funcName($content, $conf, $this->getRequest()->withAttribute('currentContentObject', $this));
4457  } else {
4458  $this->getTimeTracker()->setTSlogMessage('Function "' . $funcName . '" did not exist', LogLevel::ERROR);
4459  }
4460  return $content;
4461  }
4462 
4469  public function keywords($content)
4470  {
4471  $listArr = preg_split('/[,;' . LF . ']/', $content);
4472  if ($listArr === false) {
4473  return '';
4474  }
4475  foreach ($listArr as $k => $v) {
4476  $listArr[$k] = trim($v);
4477  }
4478  return implode(',', $listArr);
4479  }
4480 
4489  public function caseshift($theValue, $case)
4490  {
4491  switch (strtolower($case)) {
4492  case 'upper':
4493  $theValue = mb_strtoupper($theValue, 'utf-8');
4494  break;
4495  case 'lower':
4496  $theValue = mb_strtolower($theValue, 'utf-8');
4497  break;
4498  case 'capitalize':
4499  $theValue = mb_convert_case($theValue, MB_CASE_TITLE, 'utf-8');
4500  break;
4501  case 'ucfirst':
4502  $firstChar = mb_substr($theValue, 0, 1, 'utf-8');
4503  $firstChar = mb_strtoupper($firstChar, 'utf-8');
4504  $remainder = mb_substr($theValue, 1, null, 'utf-8');
4505  $theValue = $firstChar . $remainder;
4506  break;
4507  case 'lcfirst':
4508  $firstChar = mb_substr($theValue, 0, 1, 'utf-8');
4509  $firstChar = mb_strtolower($firstChar, 'utf-8');
4510  $remainder = mb_substr($theValue, 1, null, 'utf-8');
4511  $theValue = $firstChar . $remainder;
4512  break;
4513  case 'uppercamelcase':
4514  $theValue = GeneralUtility::underscoredToUpperCamelCase($theValue);
4515  break;
4516  case 'lowercamelcase':
4517  $theValue = GeneralUtility::underscoredToLowerCamelCase($theValue);
4518  break;
4519  }
4520  return $theValue;
4521  }
4522 
4531  public function HTMLcaseshift($theValue, $case)
4532  {
4533  $inside = 0;
4534  $newVal = '';
4535  $pointer = 0;
4536  $totalLen = strlen($theValue);
4537  do {
4538  if (!$inside) {
4539  $len = strcspn(substr($theValue, $pointer), '<');
4540  $newVal .= $this->caseshift(substr($theValue, $pointer, $len), $case);
4541  $inside = 1;
4542  } else {
4543  $len = strcspn(substr($theValue, $pointer), '>') + 1;
4544  $newVal .= substr($theValue, $pointer, $len);
4545  $inside = 0;
4546  }
4547  $pointer += $len;
4548  } while ($pointer < $totalLen);
4549  return $newVal;
4550  }
4551 
4559  public function calcAge($seconds, $labels = null)
4560  {
4561  if ($labels === null || MathUtility::canBeInterpretedAsInteger($labels)) {
4562  $labels = ' min| hrs| days| yrs| min| hour| day| year';
4563  } else {
4564  $labels = str_replace('"', '', $labels);
4565  }
4566  $labelArr = explode('|', $labels);
4567  if (count($labelArr) === 4) {
4568  $labelArr = array_merge($labelArr, $labelArr);
4569  }
4570  $absSeconds = abs($seconds);
4571  $sign = $seconds > 0 ? 1 : -1;
4572  if ($absSeconds < 3600) {
4573  $val = round($absSeconds / 60);
4574  $seconds = $sign * $val . ($val == 1 ? $labelArr[4] : $labelArr[0]);
4575  } elseif ($absSeconds < 24 * 3600) {
4576  $val = round($absSeconds / 3600);
4577  $seconds = $sign * $val . ($val == 1 ? $labelArr[5] : $labelArr[1]);
4578  } elseif ($absSeconds < 365 * 24 * 3600) {
4579  $val = round($absSeconds / (24 * 3600));
4580  $seconds = $sign * $val . ($val == 1 ? $labelArr[6] : $labelArr[2]);
4581  } else {
4582  $val = round($absSeconds / (365 * 24 * 3600));
4583  $seconds = $sign * $val . ($val == 1 ? ($labelArr[7] ?? null) : ($labelArr[3] ?? null));
4584  }
4585  return $seconds;
4586  }
4587 
4606  public function mergeTSRef(array $typoScriptArray, string $propertyName): array
4607  {
4608  if (!isset($typoScriptArray[$propertyName]) || !str_starts_with($typoScriptArray[$propertyName], '<')) {
4609  return $typoScriptArray;
4610  }
4611  $frontendTypoScript = $this->getRequest()->getAttribute('frontend.typoscript');
4612  if (!$frontendTypoScript || !$frontendTypoScript->hasSetup()) {
4613  return $typoScriptArray;
4614  }
4615  $fullTypoScriptArray = $frontendTypoScript->getSetupArray();
4616  $dottedSourceIdentifier = trim(substr($typoScriptArray[$propertyName], 1));
4617  $dottedSourceIdentifierArray = StringUtility::explodeEscaped('.', $dottedSourceIdentifier);
4618  $overrideConfig = $typoScriptArray[$propertyName . '.'] ?? [];
4619  $resolvedValue = $dottedSourceIdentifier;
4620  $resolvedConfig = $fullTypoScriptArray;
4621  foreach ($dottedSourceIdentifierArray as $identifierPart) {
4622  if (!isset($resolvedConfig[$identifierPart . '.'])) {
4623  $resolvedValue = $dottedSourceIdentifier;
4624  $resolvedConfig = $overrideConfig;
4625  break;
4626  }
4627  $resolvedValue = $resolvedConfig[$identifierPart] ?? $resolvedValue;
4628  $resolvedConfig = $resolvedConfig[$identifierPart . '.'];
4629  }
4630  $resolvedConfig = array_replace_recursive($resolvedConfig, $overrideConfig);
4631  $typoScriptArray[$propertyName] = $resolvedValue;
4632  $typoScriptArray[$propertyName . '.'] = $resolvedConfig;
4633  if (!isset($typoScriptArray[$propertyName]) || !str_starts_with($typoScriptArray[$propertyName], '<')) {
4634  return $typoScriptArray;
4635  }
4636  // Call recursive to resolve a nested =< operator
4637  return $this->mergeTSRef($typoScriptArray, $propertyName);
4638  }
4640  /***********************************************
4641  *
4642  * Database functions, making of queries
4643  *
4644  ***********************************************/
4645 
4655  public function searchWhere($searchWords, $searchFieldList, $searchTable)
4656  {
4657  if (!$searchWords) {
4658  return '';
4659  }
4660 
4661  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
4662  ->getQueryBuilderForTable($searchTable);
4663 
4664  $prefixTableName = $searchTable ? $searchTable . '.' : '';
4665 
4666  $where = $queryBuilder->expr()->and();
4667  $searchFields = explode(',', $searchFieldList);
4668  $searchWords = preg_split('/[ ,]/', $searchWords);
4669  foreach ($searchWords as $searchWord) {
4670  $searchWord = trim($searchWord);
4671  if (strlen($searchWord) < 3) {
4672  continue;
4673  }
4674  $searchWordConstraint = $queryBuilder->expr()->or();
4675  $searchWord = $queryBuilder->escapeLikeWildcards($searchWord);
4676  foreach ($searchFields as $field) {
4677  $searchWordConstraint = $searchWordConstraint->with(
4678  $queryBuilder->expr()->like($prefixTableName . $field, $queryBuilder->quote('%' . $searchWord . '%'))
4679  );
4680  }
4681 
4682  if ($searchWordConstraint->count()) {
4683  $where = $where->with($searchWordConstraint);
4684  }
4685  }
4686 
4687  if ((string)$where === '') {
4688  return '';
4689  }
4690 
4691  return ' AND (' . (string)$where . ')';
4692  }
4693 
4703  public function exec_getQuery($table, $conf)
4704  {
4705  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
4706  $statement = $this->getQuery($connection, $table, $conf);
4707 
4708  return $connection->executeQuery($statement);
4709  }
4710 
4720  public function getRecords($tableName, array $queryConfiguration)
4721  {
4722  $records = [];
4723 
4724  $statement = $this->exec_getQuery($tableName, $queryConfiguration);
4725 
4726  $pageRepository = $this->getPageRepository();
4727  while ($row = $statement->fetchAssociative()) {
4728  // Versioning preview:
4729  $pageRepository->versionOL($tableName, $row, true);
4730 
4731  // Language overlay:
4732  if (is_array($row)) {
4733  $row = $pageRepository->getLanguageOverlay($tableName, $row);
4734  }
4735 
4736  // Might be unset in the language overlay
4737  if (is_array($row)) {
4738  $records[] = $row;
4739  }
4740  }
4741 
4742  return $records;
4743  }
4744 
4758  public function getQuery(‪Connection $connection, string $table, array $conf): string
4759  {
4760  // Resolve stdWrap in these properties first
4761  $properties = [
4762  'pidInList',
4763  'uidInList',
4764  'languageField',
4765  'selectFields',
4766  'max',
4767  'begin',
4768  'groupBy',
4769  'orderBy',
4770  'join',
4771  'leftjoin',
4772  'rightjoin',
4773  'recursive',
4774  'where',
4775  ];
4776  foreach ($properties as $property) {
4777  $conf[$property] = trim(
4778  isset($conf[$property . '.'])
4779  ? (string)$this->stdWrap($conf[$property] ?? '', $conf[$property . '.'] ?? [])
4780  : (string)($conf[$property] ?? '')
4781  );
4782  if ($conf[$property] === '') {
4783  unset($conf[$property]);
4784  } elseif (in_array($property, ['languageField', 'selectFields', 'join', 'leftjoin', 'rightjoin', 'where'], true)) {
4785  $conf[$property] = QueryHelper::quoteDatabaseIdentifiers($connection, $conf[$property]);
4786  }
4787  if (isset($conf[$property . '.'])) {
4788  // stdWrapping already done, so remove the sub-array
4789  unset($conf[$property . '.']);
4790  }
4791  }
4792  // Handle PDO-style named parameter markers first
4793  $queryMarkers = $this->getQueryMarkers($connection, $conf);
4794  // Replace the markers in the non-stdWrap properties
4795  foreach ($queryMarkers as $marker => $markerValue) {
4796  $properties = [
4797  'uidInList',
4798  'selectFields',
4799  'where',
4800  'max',
4801  'begin',
4802  'groupBy',
4803  'orderBy',
4804  'join',
4805  'leftjoin',
4806  'rightjoin',
4807  ];
4808  foreach ($properties as $property) {
4809  if ($conf[$property] ?? false) {
4810  $conf[$property] = str_replace('###' . $marker . '###', $markerValue, $conf[$property]);
4811  }
4812  }
4813  }
4814 
4815  // Construct WHERE clause:
4816  // Handle recursive function for the pidInList
4817  if (isset($conf['recursive'])) {
4818  $conf['recursive'] = (int)$conf['recursive'];
4819  if ($conf['recursive'] > 0) {
4820  $pidList = GeneralUtility::trimExplode(',', $conf['pidInList'], true);
4821  array_walk($pidList, function (&$storagePid) {
4822  if ($storagePid === 'this') {
4823  $storagePid = $this->getRequest()->getAttribute('frontend.page.information')->getId();
4824  }
4825  });
4826  $pageRepository = $this->getPageRepository();
4827  $expandedPidList = $pageRepository->getPageIdsRecursive($pidList, $conf['recursive']);
4828  $conf['pidInList'] = implode(',', $expandedPidList);
4829  }
4830  }
4831  if ((string)($conf['pidInList'] ?? '') === '') {
4832  $conf['pidInList'] = 'this';
4833  }
4834 
4835  $queryParts = $this->getQueryConstraints($connection, $table, $conf);
4836 
4837  $queryBuilder = $connection->‪createQueryBuilder();
4838  // @todo Check against getQueryConstraints, can probably use FrontendRestrictions
4839  // @todo here and remove enableFields there.
4840  $queryBuilder->getRestrictions()->removeAll();
4841  $queryBuilder->select('*')->from($table);
4842 
4843  if ($queryParts['where'] ?? false) {
4844  $queryBuilder->where($queryParts['where']);
4845  }
4846 
4847  if ($queryParts['groupBy'] ?? false) {
4848  $queryBuilder->groupBy(...$queryParts['groupBy']);
4849  }
4850 
4851  if (is_array($queryParts['orderBy'] ?? false)) {
4852  foreach ($queryParts['orderBy'] as $orderBy) {
4853  $queryBuilder->addOrderBy(...$orderBy);
4854  }
4855  }
4856 
4857  // Fields:
4858  if ($conf['selectFields'] ?? false) {
4859  $queryBuilder->selectLiteral($this->sanitizeSelectPart($connection, $conf['selectFields'], $table));
4860  }
4861 
4862  // Setting LIMIT:
4863  if (($conf['max'] ?? false) || ($conf['begin'] ?? false)) {
4864  // Finding the total number of records, if used:
4865  if (str_contains(strtolower(($conf['begin'] ?? '') . ($conf['max'] ?? '')), 'total')) {
4866  $countQueryBuilder = $connection->‪createQueryBuilder();
4867  $countQueryBuilder->getRestrictions()->removeAll();
4868  $countQueryBuilder->count('*')
4869  ->from($table)
4870  ->where($queryParts['where']);
4871 
4872  if ($queryParts['groupBy']) {
4873  $countQueryBuilder->groupBy(...$queryParts['groupBy']);
4874  }
4875 
4876  try {
4877  $count = $countQueryBuilder->executeQuery()->fetchOne();
4878  if (isset($conf['max'])) {
4879  $conf['max'] = str_ireplace('total', $count, (string)$conf['max']);
4880  }
4881  if (isset($conf['begin'])) {
4882  $conf['begin'] = str_ireplace('total', $count, (string)$conf['begin']);
4883  }
4884  } catch (DBALException $e) {
4885  $this->getTimeTracker()->setTSlogMessage($e->getPrevious()->getMessage());
4886  return '';
4887  }
4888  }
4889 
4890  if (isset($conf['begin']) && $conf['begin'] > 0) {
4891  $conf['begin'] = MathUtility::forceIntegerInRange((int)ceil($this->calc($conf['begin'])), 0);
4892  $queryBuilder->setFirstResult($conf['begin']);
4893  }
4894  if (isset($conf['max'])) {
4895  $conf['max'] = MathUtility::forceIntegerInRange((int)ceil($this->calc($conf['max'])), 0);
4896  $queryBuilder->setMaxResults($conf['max'] ?: 100000);
4897  }
4898  }
4899 
4900  // Setting up tablejoins:
4901  if ($conf['join'] ?? false) {
4902  $joinParts = QueryHelper::parseJoin($conf['join']);
4903  $queryBuilder->join(
4904  $table,
4905  $joinParts['tableName'],
4906  $joinParts['tableAlias'],
4907  $joinParts['joinCondition']
4908  );
4909  } elseif ($conf['leftjoin'] ?? false) {
4910  $joinParts = QueryHelper::parseJoin($conf['leftjoin']);
4911  $queryBuilder->leftJoin(
4912  $table,
4913  $joinParts['tableName'],
4914  $joinParts['tableAlias'],
4915  $joinParts['joinCondition']
4916  );
4917  } elseif ($conf['rightjoin'] ?? false) {
4918  $joinParts = QueryHelper::parseJoin($conf['rightjoin']);
4919  $queryBuilder->rightJoin(
4920  $table,
4921  $joinParts['tableName'],
4922  $joinParts['tableAlias'],
4923  $joinParts['joinCondition']
4924  );
4925  }
4926 
4927  // Convert the QueryBuilder object into a SQL statement.
4928  $query = $queryBuilder->getSQL();
4929 
4930  // Replace the markers in the queryParts to handle stdWrap enabled properties
4931  foreach ($queryMarkers as $marker => $markerValue) {
4932  // @todo Ugly hack that needs to be cleaned up, with the current architecture
4933  // @todo for exec_Query / getQuery it's the best we can do.
4934  $query = str_replace('###' . $marker . '###', $markerValue, $query);
4935  }
4936  return $query;
4937  }
4938 
4948  protected function getQueryConstraints(Connection $connection, string $table, array $conf): array
4949  {
4950  $queryBuilder = $connection->createQueryBuilder();
4951  $expressionBuilder = $queryBuilder->expr();
4952  $request = $this->getRequest();
4953  $contentPid = $request->getAttribute('frontend.page.information')->getContentFromPid();
4954  $constraints = [];
4955  $pid_uid_flag = 0;
4956  $enableFieldsIgnore = [];
4957  $queryParts = [
4958  'where' => null,
4959  'groupBy' => null,
4960  'orderBy' => null,
4961  ];
4962 
4963  $isInWorkspace = GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('workspace', 'isOffline');
4964  $considerMovePointers = (
4965  $isInWorkspace && $table !== 'pages'
4966  && !empty(‪$GLOBALS['TCA'][$table]['ctrl']['versioningWS'])
4967  );
4968 
4969  if (trim($conf['uidInList'] ?? '')) {
4970  $listArr = GeneralUtility::intExplode(',', str_replace('this', (string)$contentPid, $conf['uidInList']));
4971 
4972  // If moved records shall be considered, select via t3ver_oid
4973  if ($considerMovePointers) {
4974  $constraints[] = (string)$expressionBuilder->or(
4975  $expressionBuilder->in($table . '.uid', $listArr),
4976  $expressionBuilder->and(
4977  $expressionBuilder->eq(
4978  $table . '.t3ver_state',
4979  VersionState::MOVE_POINTER->value
4980  ),
4981  $expressionBuilder->in($table . '.t3ver_oid', $listArr)
4982  )
4983  );
4984  } else {
4985  $constraints[] = (string)$expressionBuilder->in($table . '.uid', $listArr);
4986  }
4987  $pid_uid_flag++;
4988  }
4989 
4990  // Static_* tables are allowed to be fetched from root page
4991  if (str_starts_with($table, 'static_')) {
4992  $pid_uid_flag++;
4993  }
4994 
4995  if (trim($conf['pidInList'])) {
4996  $listArr = GeneralUtility::intExplode(',', str_replace('this', (string)$contentPid, $conf['pidInList']));
4997  // Removes all pages which are not visible for the user!
4998  $listArr = $this->checkPidArray($listArr);
4999  if (GeneralUtility::inList($conf['pidInList'], 'root')) {
5000  $listArr[] = 0;
5001  }
5002  if (GeneralUtility::inList($conf['pidInList'], '-1')) {
5003  $listArr[] = -1;
5004  $enableFieldsIgnore['pid'] = true;
5005  }
5006  if (!empty($listArr)) {
5007  $constraints[] = $expressionBuilder->in($table . '.pid', array_map('intval', $listArr));
5008  $pid_uid_flag++;
5009  } else {
5010  // If not uid and not pid then uid is set to 0 - which results in nothing!!
5011  $pid_uid_flag = 0;
5012  }
5013  }
5014 
5015  // If not uid and not pid then uid is set to 0 - which results in nothing!!
5016  if (!$pid_uid_flag) {
5017  $constraints[] = $expressionBuilder->eq($table . '.uid', 0);
5018  }
5019 
5020  $where = trim((string)$this->stdWrapValue('where', $conf));
5021  if ($where) {
5022  $constraints[] = QueryHelper::stripLogicalOperatorPrefix($where);
5023  }
5024 
5025  // Check if the default language should be fetched (= doing overlays), or if only the records of a language should be fetched
5026  // but only do this for TCA tables that have languages enabled
5027  $languageConstraint = $this->getLanguageRestriction($expressionBuilder, $table, $conf, GeneralUtility::makeInstance(Context::class));
5028  if ($languageConstraint !== null) {
5029  $constraints[] = $languageConstraint;
5030  }
5031 
5032  // default constraints from TCA
5033  $pageRepository = $this->getPageRepository();
5034  $constraints = array_merge(
5035  $constraints,
5036  array_values($pageRepository->getDefaultConstraints($table, $enableFieldsIgnore))
5037  );
5038 
5039  // MAKE WHERE:
5040  if ($constraints !== []) {
5041  $queryParts['where'] = $expressionBuilder->and(...$constraints);
5042  }
5043  // GROUP BY
5044  $groupBy = trim((string)$this->stdWrapValue('groupBy', $conf));
5045  if ($groupBy) {
5046  $queryParts['groupBy'] = QueryHelper::parseGroupBy($groupBy);
5047  }
5048 
5049  // ORDER BY
5050  $orderByString = trim((string)$this->stdWrapValue('orderBy', $conf));
5051  if ($orderByString) {
5052  $queryParts['orderBy'] = QueryHelper::parseOrderBy($orderByString);
5053  }
5054 
5055  // Return result:
5056  return $queryParts;
5057  }
5058 
5081  protected function getLanguageRestriction(ExpressionBuilder $expressionBuilder, string $table, array $conf, Context $context)
5082  {
5083  $languageField = '';
5084  $localizationParentField = ‪$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] ?? null;
5085  // Check if the table is translatable, and set the language field by default from the TCA information
5086  if (!empty($conf['languageField']) || !isset($conf['languageField'])) {
5087  if (isset($conf['languageField']) && !empty(‪$GLOBALS['TCA'][$table]['columns'][$conf['languageField']])) {
5088  $languageField = $conf['languageField'];
5089  } elseif (!empty(‪$GLOBALS['TCA'][$table]['ctrl']['languageField']) && !empty($localizationParentField)) {
5090  $languageField = $table . '.' . ‪$GLOBALS['TCA'][$table]['ctrl']['languageField'];
5091  }
5092  }
5093 
5094  // No language restriction enabled explicitly or available via TCA
5095  if (empty($languageField)) {
5096  return null;
5097  }
5098 
5100  $languageAspect = $context->getAspect('language');
5101  if ($languageAspect->doOverlays() && !empty($localizationParentField)) {
5102  // Sys language content is set to zero/-1 - and it is expected that whatever routine processes the output will
5103  // OVERLAY the records with localized versions!
5104  $languageQuery = $expressionBuilder->in($languageField, [0, -1]);
5105  // Use this option to include records that don't have a default language counterpart ("free mode")
5106  // (originalpointerfield is 0 and the language field contains the requested language)
5107  if (isset($conf['includeRecordsWithoutDefaultTranslation']) || !empty($conf['includeRecordsWithoutDefaultTranslation.'])) {
5108  $includeRecordsWithoutDefaultTranslation = isset($conf['includeRecordsWithoutDefaultTranslation.'])
5109  ? $this->stdWrap($conf['includeRecordsWithoutDefaultTranslation'], $conf['includeRecordsWithoutDefaultTranslation.'])
5110  : $conf['includeRecordsWithoutDefaultTranslation'];
5111  $includeRecordsWithoutDefaultTranslation = trim((string)$includeRecordsWithoutDefaultTranslation);
5112  $includeRecordsWithoutDefaultTranslation = $includeRecordsWithoutDefaultTranslation !== '' && $includeRecordsWithoutDefaultTranslation !== '0';
5113  } else {
5114  // Option was not explicitly set, check what's in for the language overlay type.
5115  $includeRecordsWithoutDefaultTranslation = $languageAspect->getOverlayType() === $languageAspect::OVERLAYS_ON_WITH_FLOATING;
5116  }
5117  if ($includeRecordsWithoutDefaultTranslation) {
5118  $languageQuery = $expressionBuilder->or(
5119  $languageQuery,
5120  $expressionBuilder->and(
5121  $expressionBuilder->eq($table . '.' . $localizationParentField, 0),
5122  $expressionBuilder->eq($languageField, $languageAspect->getContentId())
5123  )
5124  );
5125  }
5126  return $languageQuery;
5127  }
5128  // No overlays = only fetch records given for the requested language and "all languages"
5129  return $expressionBuilder->in($languageField, [$languageAspect->getContentId(), -1]);
5130  }
5131 
5142  protected function sanitizeSelectPart(Connection $connection, string $selectPart, string $table)
5143  {
5144  // Pattern matching parts
5145  $matchStart = '/(^\\s*|,\\s*|' . $table . '\\.)';
5146  $matchEnd = '(\\s*,|\\s*$)/';
5147  $necessaryFields = ['uid', 'pid'];
5148  $wsFields = ['t3ver_state'];
5149  $languageField = ‪$GLOBALS['TCA'][$table]['ctrl']['languageField'] ?? false;
5150  if (isset(‪$GLOBALS['TCA'][$table]) && !preg_match($matchStart . '\\*' . $matchEnd, $selectPart) && !preg_match('/(count|max|min|avg|sum)\\([^\\)]+\\)|distinct/i', $selectPart)) {
5151  foreach ($necessaryFields as $field) {
5152  $match = $matchStart . $field . $matchEnd;
5153  if (!preg_match($match, $selectPart)) {
5154  $selectPart .= ', ' . $connection->quoteIdentifier($table . '.' . $field) . ' AS ' . $connection->quoteIdentifier($field);
5155  }
5156  }
5157  if (is_string($languageField)) {
5158  $match = $matchStart . $languageField . $matchEnd;
5159  if (!preg_match($match, $selectPart)) {
5160  $selectPart .= ', ' . $connection->quoteIdentifier($table . '.' . $languageField) . ' AS ' . $connection->quoteIdentifier($languageField);
5161  }
5162  }
5163  if (‪$GLOBALS['TCA'][$table]['ctrl']['versioningWS'] ?? false) {
5164  foreach ($wsFields as $field) {
5165  $match = $matchStart . $field . $matchEnd;
5166  if (!preg_match($match, $selectPart)) {
5167  $selectPart .= ', ' . $connection->quoteIdentifier($table . '.' . $field) . ' AS ' . $connection->quoteIdentifier($field);
5168  }
5169  }
5170  }
5171  }
5172  return $selectPart;
5173  }
5174 
5182  public function checkPidArray($pageIds)
5183  {
5184  if (!is_array($pageIds) || empty($pageIds)) {
5185  return [];
5186  }
5187 
5188  if ($pageIds === [$this->getRequest()->getAttribute('frontend.page.information')->getId()]) {
5189  // Middlewares already checked access to the current page and made sure the current doktype
5190  // is a doktype whose content should be rendered, so there is no need to check that again.
5191  return $pageIds;
5192  }
5193  $pageRepository = $this->getPageRepository();
5194  $restrictionContainer = GeneralUtility::makeInstance(FrontendRestrictionContainer::class);
5195  if ($this->checkPid_badDoktypeList) {
5196  $restrictionContainer->add(GeneralUtility::makeInstance(
5197  DocumentTypeExclusionRestriction::class,
5198  // @todo this functionality should be streamlined with a default FrontendRestriction or a "LinkRestrictionContainer"
5199  GeneralUtility::intExplode(',', (string)$this->checkPid_badDoktypeList, true)
5200  ));
5201  }
5202  return $pageRepository->filterAccessiblePageIds($pageIds, $restrictionContainer);
5203  }
5204 
5214  public function getQueryMarkers(Connection $connection, $conf)
5215  {
5216  if (!isset($conf['markers.']) || !is_array($conf['markers.'])) {
5217  return [];
5218  }
5219  $markerValues = [];
5220  foreach ($conf['markers.'] as $dottedMarker => $dummy) {
5221  $marker = rtrim($dottedMarker, '.');
5222  if ($dottedMarker != $marker . '.') {
5223  continue;
5224  }
5225  // Parse definition
5226  // todo else value is always null
5227  $tempValue = isset($conf['markers.'][$dottedMarker])
5228  ? $this->stdWrap($conf['markers.'][$dottedMarker]['value'] ?? '', $conf['markers.'][$dottedMarker])
5229  : $conf['markers.'][$dottedMarker]['value'];
5230  // Quote/escape if needed
5231  if (is_numeric($tempValue)) {
5232  if ((int)$tempValue == $tempValue) {
5233  // Handle integer
5234  $markerValues[$marker] = (int)$tempValue;
5235  } else {
5236  // Handle float
5237  $markerValues[$marker] = (float)$tempValue;
5238  }
5239  } elseif ($tempValue === null) {
5240  // It represents NULL
5241  $markerValues[$marker] = 'NULL';
5242  } elseif (!empty($conf['markers.'][$dottedMarker]['commaSeparatedList'])) {
5243  // See if it is really a comma separated list of values
5244  $explodeValues = GeneralUtility::trimExplode(',', $tempValue);
5245  if (count($explodeValues) > 1) {
5246  // Handle each element of list separately
5247  $tempArray = [];
5248  foreach ($explodeValues as $listValue) {
5249  if (is_numeric($listValue)) {
5250  if ((int)$listValue == $listValue) {
5251  $tempArray[] = (int)$listValue;
5252  } else {
5253  $tempArray[] = (float)$listValue;
5254  }
5255  } else {
5256  // If quoted, remove quotes before
5257  // escaping.
5258  if (preg_match('/^\'([^\']*)\'$/', $listValue, $matches)) {
5259  $listValue = $matches[1];
5260  } elseif (preg_match('/^\\"([^\\"]*)\\"$/', $listValue, $matches)) {
5261  $listValue = $matches[1];
5262  }
5263  $tempArray[] = $connection->quote($listValue);
5264  }
5265  }
5266  $markerValues[$marker] = implode(',', $tempArray);
5267  } else {
5268  // Handle remaining values as string
5269  $markerValues[$marker] = $connection->quote($tempValue);
5270  }
5271  } else {
5272  // Handle remaining values as string
5273  $markerValues[$marker] = $connection->quote($tempValue);
5274  }
5275  }
5276  return $markerValues;
5277  }
5278 
5279  protected function getResourceFactory(): ResourceFactory
5280  {
5281  return GeneralUtility::makeInstance(ResourceFactory::class);
5282  }
5283 
5284  protected function getPageRepository(): ‪PageRepository
5285  {
5286  return GeneralUtility::makeInstance(PageRepository::class);
5287  }
5288 
5296  protected function getEnvironmentVariable($key)
5297  {
5298  if ($key === 'REQUEST_URI') {
5299  return $this->getRequest()->getAttribute('normalizedParams')->getRequestUri();
5300  }
5301  return GeneralUtility::getIndpEnv($key);
5302  }
5303 
5311  protected function getFromCache(array $configuration)
5312  {
5313  if (!$this->getRequest()->getAttribute('frontend.cache.instruction')->isCachingAllowed()) {
5314  return false;
5315  }
5316  $cacheKey = $this->calculateCacheKey($configuration);
5317  if (empty($cacheKey)) {
5318  return false;
5319  }
5320 
5321  $cacheFrontend = GeneralUtility::makeInstance(CacheManager::class)->getCache('hash');
5322  $cachedData = $cacheFrontend->get($cacheKey);
5323  if ($cachedData === false) {
5324  return false;
5325  }
5326  $this->getTypoScriptFrontendController()->addCacheTags($cachedData['cacheTags'] ?? []);
5327  return $cachedData['content'] ?? false;
5328  }
5329 
5335  protected function calculateCacheLifetime(array $configuration)
5336  {
5337  $configuration['lifetime'] = $configuration['lifetime'] ?? '';
5338  $lifetimeConfiguration = (string)$this->stdWrapValue('lifetime', $configuration);
5339 
5340  $lifetime = null; // default lifetime
5341  if (strtolower($lifetimeConfiguration) === 'unlimited') {
5342  $lifetime = 0; // unlimited
5343  } elseif ($lifetimeConfiguration > 0) {
5344  $lifetime = (int)$lifetimeConfiguration; // lifetime in seconds
5345  }
5346  return $lifetime;
5347  }
5348 
5354  protected function calculateCacheTags(array $configuration)
5355  {
5356  $configuration['tags'] = $configuration['tags'] ?? '';
5357  $tags = (string)$this->stdWrapValue('tags', $configuration);
5358  return empty($tags) ? [] : GeneralUtility::trimExplode(',', $tags);
5359  }
5360 
5366  protected function calculateCacheKey(array $configuration)
5367  {
5368  $configuration['key'] = $configuration['key'] ?? '';
5369  return $this->stdWrapValue('key', $configuration);
5370  }
5371 
5375  protected function getTimeTracker()
5376  {
5377  return GeneralUtility::makeInstance(TimeTracker::class);
5378  }
5383  public function getTypoScriptFrontendController(): ?‪TypoScriptFrontendController
5384  {
5385  return $this->typoScriptFrontendController ?: ‪$GLOBALS['TSFE'] ?? null;
5386  }
5387 
5395  protected function getContentLengthOfCurrentTag(string $theValue, int $pointer, string $currentTag): int
5396  {
5397  $tempContent = strtolower(substr($theValue, $pointer));
5398  $startTag = '<' . $currentTag;
5399  $endTag = '</' . $currentTag . '>';
5400  $offsetCount = 0;
5401 
5402  // Take care for nested tags
5403  do {
5404  $nextMatchingEndTagPosition = strpos($tempContent, $endTag);
5405  // only match tag `a` in `<a href"...">` but not in `<abbr>`
5406  $nextSameTypeTagPosition = preg_match(
5407  '#' . $startTag . '[\s/>]#',
5408  $tempContent,
5409  $nextSameStartTagMatches,
5410  PREG_OFFSET_CAPTURE
5411  ) ? $nextSameStartTagMatches[0][1] : false;
5412 
5413  // filter out nested tag contents to help getting the correct closing tag
5414  if ($nextMatchingEndTagPosition !== false && $nextSameTypeTagPosition !== false && $nextSameTypeTagPosition < $nextMatchingEndTagPosition) {
5415  $lastOpeningTagStartPosition = (int)strrpos(substr($tempContent, 0, $nextMatchingEndTagPosition), $startTag);
5416  $closingTagEndPosition = $nextMatchingEndTagPosition + strlen($endTag);
5417  $offsetCount += $closingTagEndPosition - $lastOpeningTagStartPosition;
5418 
5419  // replace content from latest tag start to latest tag end
5420  $tempContent = substr($tempContent, 0, $lastOpeningTagStartPosition) . substr($tempContent, $closingTagEndPosition);
5421  }
5422  } while (
5423  ($nextMatchingEndTagPosition !== false && $nextSameTypeTagPosition !== false) &&
5424  $nextSameTypeTagPosition < $nextMatchingEndTagPosition
5425  );
5426 
5427  // if no closing tag is found we use length of the whole content
5428  $endingOffset = strlen($tempContent);
5429  if ($nextMatchingEndTagPosition !== false) {
5430  $endingOffset = $nextMatchingEndTagPosition + $offsetCount;
5431  }
5432 
5433  return $endingOffset;
5434  }
5435 
5436  protected function shallDebug(): bool
5437  {
5438  $typoScriptConfigArray = $this->getRequest()->getAttribute('frontend.typoscript')->getConfigArray();
5439  if (isset($typoScriptConfigArray['debug'])) {
5440  return (bool)($typoScriptConfigArray['debug']);
5441  }
5442  return !empty(‪$GLOBALS['TYPO3_CONF_VARS']['FE']['debug']);
5443  }
5444 
5462  public function getRequest(): ServerRequestInterface
5463  {
5464  if ($this->request instanceof ServerRequestInterface) {
5465  return $this->request;
5466  }
5467  if ((‪$GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface) {
5468  // @todo: We may want to deprecate this fallback and force consumers
5469  // to setRequest() after object instantiation / unserialization instead.
5470  return ‪$GLOBALS['TYPO3_REQUEST'];
5471  }
5472  throw new ContentRenderingException(
5473  'PSR-7 request is missing in ContentObjectRenderer. Inject with start(), setRequest() or provide via $GLOBALS[\'TYPO3_REQUEST\'].',
5474  1607172972
5475  );
5476  }
5477 }
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_noTrimWrap
‪string stdWrap_noTrimWrap($content='', $conf=[])
Definition: ContentObjectRenderer.php:2114
‪TYPO3\CMS\Core\Localization\LanguageServiceFactory
Definition: LanguageServiceFactory.php:25
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$parentRecordNumber
‪int $parentRecordNumber
Definition: ContentObjectRenderer.php:307
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\http_makelinks
‪string http_makelinks(string $data, array $conf)
Definition: ContentObjectRenderer.php:3434
‪TYPO3\CMS\Core\Resource\FileReference\getProperty
‪getProperty(string $key)
Definition: FileReference.php:108
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\mergeTSRef
‪array mergeTSRef(array $typoScriptArray, string $propertyName)
Definition: ContentObjectRenderer.php:4590
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_case
‪string stdWrap_case($content='', $conf=[])
Definition: ContentObjectRenderer.php:1819
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_htmlSpecialChars
‪string stdWrap_htmlSpecialChars($content='', $conf=[])
Definition: ContentObjectRenderer.php:1909
‪TYPO3\CMS\Core\Database\Query\Restriction\DocumentTypeExclusionRestriction
Definition: DocumentTypeExclusionRestriction.php:27
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\shallDebug
‪shallDebug()
Definition: ContentObjectRenderer.php:5420
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\setCurrentFile
‪setCurrentFile($fileObject)
Definition: ContentObjectRenderer.php:1016
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_expandList
‪string stdWrap_expandList($content='')
Definition: ContentObjectRenderer.php:1708
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getFileDataKey
‪string int getFileDataKey($key)
Definition: ContentObjectRenderer.php:4080
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\OBJECTTYPE_USER
‪const OBJECTTYPE_USER
Definition: ContentObjectRenderer.php:366
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_cacheRead
‪string stdWrap_cacheRead($content='', $conf=[])
Definition: ContentObjectRenderer.php:1168
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getCurrentTable
‪string getCurrentTable()
Definition: ContentObjectRenderer.php:456
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\determineExceptionHandlerClassName
‪determineExceptionHandlerClassName(array $configuration)
Definition: ContentObjectRenderer.php:684
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\listNum
‪string listNum($content, $listNum, $delimeter=',')
Definition: ContentObjectRenderer.php:2424
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\in
‪in(string $fieldName, $value)
Definition: ExpressionBuilder.php:227
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_ifNull
‪string stdWrap_ifNull($content='', $conf=[])
Definition: ContentObjectRenderer.php:1371
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:27
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder
Definition: ExpressionBuilder.php:40
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_insertData
‪string stdWrap_insertData($content='')
Definition: ContentObjectRenderer.php:2243
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\cObjGetSeparated
‪list< string > cObjGetSeparated(?array $setup, string $addKey='')
Definition: ContentObjectRenderer.php:529
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getUserObjectType
‪mixed getUserObjectType()
Definition: ContentObjectRenderer.php:729
‪TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection\create
‪static create(string $jsonString, array $tcaConfig=[])
Definition: CropVariantCollection.php:37
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_orderedStdWrap
‪string stdWrap_orderedStdWrap($content='', $conf=[])
Definition: ContentObjectRenderer.php:2214
‪TYPO3\CMS\Core\Resource\FileInterface
Definition: FileInterface.php:26
‪TYPO3\CMS\Core\Utility\DebugUtility\debugTrail
‪static string debugTrail(bool $prependFileNames=false)
Definition: DebugUtility.php:64
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_csConv
‪string stdWrap_csConv($content='', $conf=[])
Definition: ContentObjectRenderer.php:1544
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\round
‪string round($content, array $conf=[])
Definition: ContentObjectRenderer.php:2914
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\encaps_lineSplit
‪string encaps_lineSplit($theValue, $conf)
Definition: ContentObjectRenderer.php:3313
‪TYPO3\CMS\Core\Html\HtmlParser
Definition: HtmlParser.php:26
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\start
‪start($data, $table='')
Definition: ContentObjectRenderer.php:437
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\imageLinkWrap
‪string imageLinkWrap($string, $imageFile, $conf)
Definition: ContentObjectRenderer.php:851
‪debug
‪debug(mixed $variable='', ?string $title=null)
Definition: GlobalDebugFunctions.php:21
‪TYPO3\CMS\Core\Context\Context\getAspect
‪getAspect(string $name)
Definition: Context.php:76
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\substring
‪string substring($content, $options)
Definition: ContentObjectRenderer.php:2649
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_listNum
‪string stdWrap_listNum($content='', $conf=[])
Definition: ContentObjectRenderer.php:1420
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\or
‪or(CompositeExpression|\Doctrine\DBAL\Query\Expression\CompositeExpression|string|null ... $expressions)
Definition: ExpressionBuilder.php:59
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_prefixComment
‪string stdWrap_prefixComment($content='', $conf=[])
Definition: ContentObjectRenderer.php:2292
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\setUserObjectType
‪setUserObjectType($userObjectType)
Definition: ContentObjectRenderer.php:739
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_wrap
‪string stdWrap_wrap($content='', $conf=[])
Definition: ContentObjectRenderer.php:2096
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getQuery
‪string getQuery(Connection $connection, string $table, array $conf)
Definition: ContentObjectRenderer.php:4742
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_replacement
‪string stdWrap_replacement($content='', $conf=[])
Definition: ContentObjectRenderer.php:1606
‪TYPO3\CMS\Core\Versioning\VersionState
‪VersionState
Definition: VersionState.php:22
‪TYPO3\CMS\Core\Imaging\ImageManipulation\Area
Definition: Area.php:23
‪TYPO3\CMS\Core\Resource\ProcessedFile\CONTEXT_IMAGECROPSCALEMASK
‪const CONTEXT_IMAGECROPSCALEMASK
Definition: ProcessedFile.php:61
‪TYPO3\CMS\Core\Utility\Exception\MissingArrayPathException
Definition: MissingArrayPathException.php:27
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$currentRecord
‪string $currentRecord
Definition: ContentObjectRenderer.php:295
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$doConvertToUserIntObject
‪bool $doConvertToUserIntObject
Definition: ContentObjectRenderer.php:329
‪TYPO3\CMS\Frontend\ContentObject\Event\AfterContentObjectRendererInitializedEvent
Definition: AfterContentObjectRendererInitializedEvent.php:26
‪TYPO3\CMS\Frontend\ContentObject
Definition: AbstractContentObject.php:18
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\cropHTML
‪string cropHTML(string $content, string $options)
Definition: ContentObjectRenderer.php:2695
‪TYPO3\CMS\Core\Utility\MathUtility\calculateWithParentheses
‪static string calculateWithParentheses(string $string)
Definition: MathUtility.php:172
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\parseFuncInternal
‪string parseFuncInternal($theValue, $conf)
Definition: ContentObjectRenderer.php:3100
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\setParent
‪setParent($data, $currentRecord)
Definition: ContentObjectRenderer.php:469
‪TYPO3\CMS\Frontend\Resource\FilePathSanitizer
Definition: FilePathSanitizer.php:39
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_prepend
‪string stdWrap_prepend($content='', $conf=[])
Definition: ContentObjectRenderer.php:2170
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_stdWrap
‪string stdWrap_stdWrap($content='', $conf=[])
Definition: ContentObjectRenderer.php:1476
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\eq
‪eq(string $fieldName, $value)
Definition: ExpressionBuilder.php:84
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getTypoScriptFrontendController
‪getTypoScriptFrontendController()
Definition: ContentObjectRenderer.php:5367
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\setCurrentVal
‪setCurrentVal($value)
Definition: ContentObjectRenderer.php:501
‪TYPO3\CMS\Frontend\ContentObject\Event\AfterImageResourceResolvedEvent
Definition: AfterImageResourceResolvedEvent.php:28
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\parseFunc
‪string parseFunc($theValue, ?array $conf, ?string $ref=null)
Definition: ContentObjectRenderer.php:2968
‪TYPO3\CMS\Core\Page\PageLayoutResolver
Definition: PageLayoutResolver.php:46
‪TYPO3\CMS\Core\Resource\FileReference
Definition: FileReference.php:37
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getQueryConstraints
‪array getQueryConstraints(Connection $connection, string $table, array $conf)
Definition: ContentObjectRenderer.php:4932
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\HTMLcaseshift
‪string HTMLcaseshift($theValue, $case)
Definition: ContentObjectRenderer.php:4515
‪TYPO3\CMS\Core\Utility\DebugUtility\viewArray
‪static string viewArray(mixed $array_in)
Definition: DebugUtility.php:113
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getContentLengthOfCurrentTag
‪getContentLengthOfCurrentTag(string $theValue, int $pointer, string $currentTag)
Definition: ContentObjectRenderer.php:5379
‪TYPO3\CMS\Frontend\ContentObject\Exception\ExceptionHandlerInterface
Definition: ExceptionHandlerInterface.php:24
‪TYPO3\CMS\Core\Localization\Locales
Definition: Locales.php:36
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_round
‪string stdWrap_round($content='', $conf=[])
Definition: ContentObjectRenderer.php:1683
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$currentRecordNumber
‪int $currentRecordNumber
Definition: ContentObjectRenderer.php:301
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\__construct
‪__construct(?TypoScriptFrontendController $typoScriptFrontendController=null, ?ContainerInterface $container=null)
Definition: ContentObjectRenderer.php:368
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getCurrentFile
‪File FileReference Folder FileInterface FolderInterface string null getCurrentFile()
Definition: ContentObjectRenderer.php:1026
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_stripHtml
‪string stdWrap_stripHtml($content='')
Definition: ContentObjectRenderer.php:1870
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_field
‪string null stdWrap_field($content='', $conf=[])
Definition: ContentObjectRenderer.php:1273
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_HTMLparser
‪string stdWrap_HTMLparser($content='', $conf=[])
Definition: ContentObjectRenderer.php:1576
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_lang
‪string stdWrap_lang($content='', $conf=[])
Definition: ContentObjectRenderer.php:1229
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getValueFromRecursiveData
‪getValueFromRecursiveData(array $keys, mixed $startValue)
Definition: ContentObjectRenderer.php:4188
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_br
‪string stdWrap_br($content='')
Definition: ContentObjectRenderer.php:1952
‪TYPO3\CMS\Frontend\ContentObject\Exception\ContentRenderingException
Definition: ContentRenderingException.php:23
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_wrapAlign
‪string stdWrap_wrapAlign($content='', $conf=[])
Definition: ContentObjectRenderer.php:2060
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getEnvironmentVariable
‪string getEnvironmentVariable($key)
Definition: ContentObjectRenderer.php:5280
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getCropAreaFromFileReference
‪Area null getCropAreaFromFileReference(FileReference $fileReference, array $fileArray)
Definition: ContentObjectRenderer.php:3668
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_split
‪string stdWrap_split($content='', $conf=[])
Definition: ContentObjectRenderer.php:1593
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:54
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getResourceFactory
‪getResourceFactory()
Definition: ContentObjectRenderer.php:5263
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_numRows
‪string stdWrap_numRows($content='', $conf=[])
Definition: ContentObjectRenderer.php:1315
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\cObjGetSingle
‪string cObjGetSingle(string $name, $conf, $TSkey='__')
Definition: ContentObjectRenderer.php:555
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_if
‪string stdWrap_if($content='', $conf=[])
Definition: ContentObjectRenderer.php:1507
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$currentFile
‪File FileReference Folder FolderInterface FileInterface string null $currentFile
Definition: ContentObjectRenderer.php:324
‪TYPO3\CMS\Core\Text\TextCropper
Definition: TextCropper.php:21
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\checkIf
‪checkIf($conf)
Definition: ContentObjectRenderer.php:2449
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrapValue
‪string int bool null stdWrapValue($key, array $config, $defaultValue='')
Definition: ContentObjectRenderer.php:1145
‪TYPO3\CMS\Core\Service\FlexFormService
Definition: FlexFormService.php:25
‪TYPO3\CMS\Core\Localization\DateFormatter
Definition: DateFormatter.php:27
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\wrap
‪string wrap($content, $wrap, $char='|')
Definition: ContentObjectRenderer.php:4374
‪TYPO3\CMS\Core\Utility\ArrayUtility\getValueByPath
‪static getValueByPath(array $array, array|string $path, string $delimiter='/')
Definition: ArrayUtility.php:176
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\exec_getQuery
‪Result exec_getQuery($table, $conf)
Definition: ContentObjectRenderer.php:4687
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getLanguageRestriction
‪string TYPO3 CMS Core Database Query Expression CompositeExpression null getLanguageRestriction(ExpressionBuilder $expressionBuilder, string $table, array $conf, Context $context)
Definition: ContentObjectRenderer.php:5065
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$userObjectType
‪int bool $userObjectType
Definition: ContentObjectRenderer.php:336
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_brTag
‪string stdWrap_brTag($content='', $conf=[])
Definition: ContentObjectRenderer.php:1966
‪TYPO3\CMS\Core\Utility\PathUtility\getAbsoluteWebPath
‪static string getAbsoluteWebPath(string $targetPath, bool $prefixWithSitePath=true)
Definition: PathUtility.php:52
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_rawUrlEncode
‪string stdWrap_rawUrlEncode($content='')
Definition: ContentObjectRenderer.php:1895
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger(mixed $var)
Definition: MathUtility.php:74
‪TYPO3\CMS\Core\Type\BitSet
Definition: BitSet.php:66
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_wrap3
‪string stdWrap_wrap3($content='', $conf=[])
Definition: ContentObjectRenderer.php:2197
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_formattedDate
‪string stdWrap_formattedDate(string $content, array $conf)
Definition: ContentObjectRenderer.php:1778
‪TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression
Definition: CompositeExpression.php:27
‪TYPO3\CMS\Core\Page\PageRenderer
Definition: PageRenderer.php:45
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_preIfEmptyListNum
‪string stdWrap_preIfEmptyListNum($content='', $conf=[])
Definition: ContentObjectRenderer.php:1358
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\caseshift
‪string caseshift($theValue, $case)
Definition: ContentObjectRenderer.php:4473
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$parentRecord
‪array $parentRecord
Definition: ContentObjectRenderer.php:313
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_date
‪string stdWrap_date($content='', $conf=[])
Definition: ContentObjectRenderer.php:1722
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\mergeExceptionHandlerConfiguration
‪mergeExceptionHandlerConfiguration(array $configuration)
Definition: ContentObjectRenderer.php:708
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_htmlSanitize
‪stdWrap_htmlSanitize(string $content='', array $conf=[])
Definition: ContentObjectRenderer.php:2304
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_keywords
‪string stdWrap_keywords($content='')
Definition: ContentObjectRenderer.php:1992
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_preCObject
‪string stdWrap_preCObject($content='', $conf=[])
Definition: ContentObjectRenderer.php:2033
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_required
‪string stdWrap_required($content='')
Definition: ContentObjectRenderer.php:1489
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_current
‪string stdWrap_current($content='', $conf=[])
Definition: ContentObjectRenderer.php:1287
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\__sleep
‪array __sleep()
Definition: ContentObjectRenderer.php:386
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_setContentToCurrent
‪string stdWrap_setContentToCurrent($content='')
Definition: ContentObjectRenderer.php:1201
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap
‪string null stdWrap($content='', $conf=[])
Definition: ContentObjectRenderer.php:1045
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\cObjGet
‪string cObjGet($setup, $addKey='')
Definition: ContentObjectRenderer.php:515
‪TYPO3\CMS\Core\Database\Query\QueryHelper
Definition: QueryHelper.php:32
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_numberFormat
‪string stdWrap_numberFormat($content='', $conf=[])
Definition: ContentObjectRenderer.php:1696
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_setCurrent
‪string stdWrap_setCurrent($content='', $conf=[])
Definition: ContentObjectRenderer.php:1215
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\convertToUserIntObject
‪convertToUserIntObject()
Definition: ContentObjectRenderer.php:747
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_intval
‪string stdWrap_intval($content='')
Definition: ContentObjectRenderer.php:1652
‪TYPO3\CMS\Core\Utility\GeneralUtility\expandList
‪static string expandList($list)
Definition: GeneralUtility.php:434
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\insertData
‪string insertData($str)
Definition: ContentObjectRenderer.php:2587
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_ifEmpty
‪string stdWrap_ifEmpty($content='', $conf=[])
Definition: ContentObjectRenderer.php:1385
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\createUrl
‪string createUrl(array $conf)
Definition: ContentObjectRenderer.php:4336
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_parseFunc
‪string stdWrap_parseFunc($content='', $conf=[])
Definition: ContentObjectRenderer.php:1562
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_hash
‪string stdWrap_hash($content='', array $conf=[])
Definition: ContentObjectRenderer.php:1665
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$data
‪array $data
Definition: ContentObjectRenderer.php:274
‪TYPO3\CMS\Core\Resource\Folder
Definition: Folder.php:38
‪TYPO3\CMS\Core\Resource\ResourceFactory
Definition: ResourceFactory.php:42
‪TYPO3\CMS\Core\Database\Connection\createQueryBuilder
‪createQueryBuilder()
Definition: Connection.php:114
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\__wakeup
‪__wakeup()
Definition: ContentObjectRenderer.php:405
‪TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException
Definition: ResourceDoesNotExistException.php:23
‪$name
‪$name
Definition: phpIntegrityChecker.php:235
‪TYPO3\CMS\Core\Resource\File
Definition: File.php:26
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_outerWrap
‪string stdWrap_outerWrap($content='', $conf=[])
Definition: ContentObjectRenderer.php:2231
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\numberFormat
‪string numberFormat($content, $conf)
Definition: ContentObjectRenderer.php:2942
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\keywords
‪string keywords($content)
Definition: ContentObjectRenderer.php:4453
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\typoLink
‪string LinkResult typoLink(string $linkText, array $conf)
Definition: ContentObjectRenderer.php:4267
‪TYPO3\CMS\Core\Html\SanitizerInitiator
Definition: SanitizerInitiator.php:28
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\noTrimWrap
‪string noTrimWrap($content, $wrap, $char='|')
Definition: ContentObjectRenderer.php:4393
‪TYPO3\CMS\Core\Database\Connection\quoteIdentifier
‪string quoteIdentifier(string $identifier)
Definition: Connection.php:129
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:36
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getFieldVal
‪string null getFieldVal($field)
Definition: ContentObjectRenderer.php:3741
‪TYPO3\CMS\Core\Page\DefaultJavaScriptAssetTrait
Definition: DefaultJavaScriptAssetTrait.php:30
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\HTMLparser_TSbridge
‪string HTMLparser_TSbridge($theValue, $conf)
Definition: ContentObjectRenderer.php:2551
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$currentValKey
‪string $currentValKey
Definition: ContentObjectRenderer.php:288
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\createCropAreaFromJsonString
‪createCropAreaFromJsonString(string $cropSettings, string $cropVariant)
Definition: ContentObjectRenderer.php:3725
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_postCObject
‪string stdWrap_postCObject($content='', $conf=[])
Definition: ContentObjectRenderer.php:2046
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\dataWrap
‪string dataWrap($content, $wrap)
Definition: ContentObjectRenderer.php:2567
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getRecords
‪array getRecords($tableName, array $queryConfiguration)
Definition: ContentObjectRenderer.php:4704
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_strftime
‪string stdWrap_strftime($content='', $conf=[])
Definition: ContentObjectRenderer.php:1739
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\calculateCacheTags
‪array calculateCacheTags(array $configuration)
Definition: ContentObjectRenderer.php:5338
‪TYPO3\CMS\Frontend\ContentObject\AbstractContentObject
Definition: AbstractContentObject.php:31
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_substring
‪string stdWrap_substring($content='', $conf=[])
Definition: ContentObjectRenderer.php:1845
‪TYPO3\CMS\Core\Context\LanguageAspect
Definition: LanguageAspect.php:57
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\mailto_makelinks
‪string mailto_makelinks(string $data, array $conf)
Definition: ContentObjectRenderer.php:3495
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_innerWrap2
‪string stdWrap_innerWrap2($content='', $conf=[])
Definition: ContentObjectRenderer.php:2020
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_ifBlank
‪string stdWrap_ifBlank($content='', $conf=[])
Definition: ContentObjectRenderer.php:1402
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getContentObject
‪getContentObject($name)
Definition: ContentObjectRenderer.php:585
‪TYPO3\CMS\Core\Utility\DebugUtility
Definition: DebugUtility.php:27
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$lastTypoLinkResult
‪LinkResultInterface $lastTypoLinkResult
Definition: ContentObjectRenderer.php:320
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\createExceptionHandler
‪createExceptionHandler(array $configuration)
Definition: ContentObjectRenderer.php:667
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$parameters
‪array $parameters
Definition: ContentObjectRenderer.php:284
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_debug
‪string stdWrap_debug($content='')
Definition: ContentObjectRenderer.php:2367
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getRequest
‪getRequest()
Definition: ContentObjectRenderer.php:5446
‪TYPO3\CMS\Frontend\Imaging\GifBuilder
Definition: GifBuilder.php:58
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getPageRepository
‪getPageRepository()
Definition: ContentObjectRenderer.php:5268
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$request
‪ServerRequestInterface $request
Definition: ContentObjectRenderer.php:353
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_typolink
‪string stdWrap_typolink($content='', $conf=[])
Definition: ContentObjectRenderer.php:2079
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_dataWrap
‪string stdWrap_dataWrap($content='', $conf=[])
Definition: ContentObjectRenderer.php:2157
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$stdWrapRecursionLevel
‪int $stdWrapRecursionLevel
Definition: ContentObjectRenderer.php:344
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$stopRendering
‪array $stopRendering
Definition: ContentObjectRenderer.php:340
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\createLink
‪createLink(string $linkText, array $conf)
Definition: ContentObjectRenderer.php:4313
‪TYPO3\CMS\Core\Resource\ProcessedFile
Definition: ProcessedFile.php:47
‪TYPO3\CMS\Core\TypoScript\TypoScriptService
Definition: TypoScriptService.php:27
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\calculateCacheLifetime
‪int null calculateCacheLifetime(array $configuration)
Definition: ContentObjectRenderer.php:5319
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$container
‪ContainerInterface null $container
Definition: ContentObjectRenderer.php:109
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_encapsLines
‪string stdWrap_encapsLines($content='', $conf=[])
Definition: ContentObjectRenderer.php:1980
‪TYPO3\CMS\Core\Resource\Exception
Definition: Exception.php:21
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:41
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\calc
‪int calc($val)
Definition: ContentObjectRenderer.php:2717
‪TYPO3\CMS\Webhooks\Message\$url
‪identifier readonly UriInterface $url
Definition: LoginErrorOccurredMessage.php:36
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_append
‪string stdWrap_append($content='', $conf=[])
Definition: ContentObjectRenderer.php:2183
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\render
‪render(AbstractContentObject $contentObject, $configuration=[])
Definition: ContentObjectRenderer.php:608
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_bytes
‪string stdWrap_bytes($content='', $conf=[])
Definition: ContentObjectRenderer.php:1832
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_crop
‪string stdWrap_crop($content='', $conf=[])
Definition: ContentObjectRenderer.php:1883
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getData
‪string getData($string, $fieldArray=null)
Definition: ContentObjectRenderer.php:3767
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$stdWrapOrder
‪array $stdWrapOrder
Definition: ContentObjectRenderer.php:117
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:58
‪TYPO3\CMS\Webhooks\Message\$uid
‪identifier readonly int $uid
Definition: PageModificationMessage.php:35
‪TYPO3\CMS\Frontend\ContentObject\Event\BeforeStdWrapFunctionsInitializedEvent
Definition: BeforeStdWrapFunctionsInitializedEvent.php:23
‪TYPO3\CMS\Core\TimeTracker\TimeTracker\setTSlogMessage
‪setTSlogMessage(string $content, string $logLevel=LogLevel::INFO)
Definition: TimeTracker.php:143
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:26
‪TYPO3\CMS\Frontend\ContentObject\Event\BeforeStdWrapFunctionsExecutedEvent
Definition: BeforeStdWrapFunctionsExecutedEvent.php:23
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_debugData
‪string stdWrap_debugData($content='')
Definition: ContentObjectRenderer.php:2393
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\and
‪and(CompositeExpression|\Doctrine\DBAL\Query\Expression\CompositeExpression|string|null ... $expressions,)
Definition: ExpressionBuilder.php:50
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_wrap2
‪string stdWrap_wrap2($content='', $conf=[])
Definition: ContentObjectRenderer.php:2139
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getCropAreaFromFromTypoScriptSettings
‪Area null getCropAreaFromFromTypoScriptSettings(FileInterface $file, array $fileArray)
Definition: ContentObjectRenderer.php:3687
‪TYPO3\CMS\Core\Log\LogManager
Definition: LogManager.php:33
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:41
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\crop
‪string crop($content, $options)
Definition: ContentObjectRenderer.php:2667
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_cObject
‪string stdWrap_cObject($content='', $conf=[])
Definition: ContentObjectRenderer.php:1301
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_prioriCalc
‪string stdWrap_prioriCalc($content='', $conf=[])
Definition: ContentObjectRenderer.php:1620
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\sanitizeSelectPart
‪string sanitizeSelectPart(Connection $connection, string $selectPart, string $table)
Definition: ContentObjectRenderer.php:5126
‪TYPO3\CMS\Core\Utility\GeneralUtility\revExplode
‪static list< string > revExplode(string $delimiter, string $string, int $limit=0)
Definition: GeneralUtility.php:787
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\replacementSingle
‪string replacementSingle($content, array $configuration)
Definition: ContentObjectRenderer.php:2845
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\lastChanged
‪lastChanged($tstamp)
Definition: ContentObjectRenderer.php:996
‪TYPO3\CMS\Core\Resource\FolderInterface
Definition: FolderInterface.php:24
‪TYPO3\CMS\Core\Html\HtmlCropper
Definition: HtmlCropper.php:24
‪TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection
Definition: CropVariantCollection.php:23
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_char
‪string stdWrap_char($content='', $conf=[])
Definition: ContentObjectRenderer.php:1640
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:24
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
Definition: ContentObjectRenderer.php:103
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\numRows
‪int numRows($conf)
Definition: ContentObjectRenderer.php:2408
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$typoScriptFrontendController
‪TypoScriptFrontendController null $typoScriptFrontendController
Definition: ContentObjectRenderer.php:348
‪TYPO3\CMS\Core\Utility\GeneralUtility\inList
‪static bool inList($list, $item)
Definition: GeneralUtility.php:422
‪TYPO3\CMS\Core\Utility\StringUtility\multibyteStringPad
‪static multibyteStringPad(string $string, int $length, string $pad_string=' ', int $pad_type=STR_PAD_RIGHT, string $encoding='UTF-8')
Definition: StringUtility.php:131
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\setRequest
‪setRequest(ServerRequestInterface $request)
Definition: ContentObjectRenderer.php:374
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_debugFunc
‪string stdWrap_debugFunc($content='', $conf=[])
Definition: ContentObjectRenderer.php:2380
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getTimeTracker
‪TimeTracker getTimeTracker()
Definition: ContentObjectRenderer.php:5359
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\rootLineValue
‪string rootLineValue($key, $field, $slideBack=false, $altRootLine='')
Definition: ContentObjectRenderer.php:4145
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\calcAge
‪string calcAge($seconds, $labels=null)
Definition: ContentObjectRenderer.php:4543
‪TYPO3\CMS\Core\Domain\Repository\PageRepository
Definition: PageRepository.php:69
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\prefixComment
‪string prefixComment($str, $conf, $content)
Definition: ContentObjectRenderer.php:2624
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\searchWhere
‪string searchWhere($searchWords, $searchFieldList, $searchTable)
Definition: ContentObjectRenderer.php:4639
‪TYPO3\CMS\Frontend\ContentObject\Event\AfterStdWrapFunctionsInitializedEvent
Definition: AfterStdWrapFunctionsInitializedEvent.php:24
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\callUserFunction
‪mixed callUserFunction($funcName, $conf, $content)
Definition: ContentObjectRenderer.php:4413
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_data
‪string stdWrap_data($_='', $conf=[])
Definition: ContentObjectRenderer.php:1260
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_override
‪string stdWrap_override($content='', $conf=[])
Definition: ContentObjectRenderer.php:1341
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getQueryMarkers
‪array getQueryMarkers(Connection $connection, $conf)
Definition: ContentObjectRenderer.php:5198
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\readFlexformIntoConf
‪readFlexformIntoConf($flexData, &$conf, $recursive=false)
Definition: ContentObjectRenderer.php:768
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_innerWrap
‪string stdWrap_innerWrap($content='', $conf=[])
Definition: ContentObjectRenderer.php:2006
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getSlidePids
‪string getSlidePids($pidList, $pidConf)
Definition: ContentObjectRenderer.php:814
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_age
‪string stdWrap_age($content='', $conf=[])
Definition: ContentObjectRenderer.php:1805
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:24
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$table
‪string $table
Definition: ContentObjectRenderer.php:278
‪TYPO3\CMS\Frontend\ContentObject\Event\AfterStdWrapFunctionsExecutedEvent
Definition: AfterStdWrapFunctionsExecutedEvent.php:23
‪TYPO3\CMS\Frontend\ContentObject\Event\AfterGetDataResolvedEvent
Definition: AfterGetDataResolvedEvent.php:26
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getImgResource
‪ImageResource null getImgResource($file, $fileArray)
Definition: ContentObjectRenderer.php:3548
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_cropHTML
‪string stdWrap_cropHTML($content='', $conf=[])
Definition: ContentObjectRenderer.php:1858
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getCurrentVal
‪mixed getCurrentVal()
Definition: ContentObjectRenderer.php:490
‪TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer
Definition: FrontendRestrictionContainer.php:30
‪TYPO3\CMS\Core\Crypto\HashService
Definition: HashService.php:27
‪TYPO3\CMS\Core\Utility\GeneralUtility\intExplode
‪static list< int > intExplode(string $delimiter, string $string, bool $removeEmptyValues=false)
Definition: GeneralUtility.php:756
‪TYPO3\CMS\Core\TimeTracker\TimeTracker
Definition: TimeTracker.php:34
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\checkPidArray
‪array checkPidArray($pageIds)
Definition: ContentObjectRenderer.php:5166
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getFromCache
‪string bool getFromCache(array $configuration)
Definition: ContentObjectRenderer.php:5295
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_addPageCacheTags
‪string stdWrap_addPageCacheTags($content='', $conf=[])
Definition: ContentObjectRenderer.php:1184
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_strtotime
‪string stdWrap_strtotime($content='', $conf=[])
Definition: ContentObjectRenderer.php:1761
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\OBJECTTYPE_USER_INT
‪const OBJECTTYPE_USER_INT
Definition: ContentObjectRenderer.php:360
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_trim
‪string stdWrap_trim($content='')
Definition: ContentObjectRenderer.php:1432
‪TYPO3\CMS\Core\Core\Environment\getContext
‪static getContext()
Definition: Environment.php:128
‪TYPO3\CMS\Core\Resource\Exception
Definition: AbstractFileOperationException.php:16
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_preUserFunc
‪string stdWrap_preUserFunc($content='', $conf=[])
Definition: ContentObjectRenderer.php:1328
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\calculateCacheKey
‪string calculateCacheKey(array $configuration)
Definition: ContentObjectRenderer.php:5350
‪TYPO3\CMS\Core\Utility\GeneralUtility\xml2array
‪static array string xml2array(string $string, string $NSprefix='', bool $reportDocTag=false)
Definition: GeneralUtility.php:1264
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getKey
‪int getKey($key, $arr)
Definition: ContentObjectRenderer.php:4229
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_postUserFuncInt
‪string stdWrap_postUserFuncInt($content='', $conf=[])
Definition: ContentObjectRenderer.php:2270
‪TYPO3\CMS\Core\Html\SanitizerBuilderFactory
Definition: SanitizerBuilderFactory.php:37
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_doubleBrTag
‪string stdWrap_doubleBrTag($content='', $conf=[])
Definition: ContentObjectRenderer.php:1939
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\typoLink_URL
‪string typoLink_URL($conf)
Definition: ContentObjectRenderer.php:4353
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\splitObj
‪string splitObj($value, $conf)
Definition: ContentObjectRenderer.php:2759
‪TYPO3\CMS\Frontend\ContentObject\Exception\ProductionExceptionHandler
Definition: ProductionExceptionHandler.php:35
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_strPad
‪string stdWrap_strPad($content='', $conf=[])
Definition: ContentObjectRenderer.php:1445
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode(string $delim, string $string, bool $removeEmptyValues=false, int $limit=0)
Definition: GeneralUtility.php:822
‪TYPO3\CMS\Frontend\ContentObject\AbstractContentObject\render
‪string render($conf=[])
‪TYPO3\CMS\Webhooks\Message\$identifier
‪identifier readonly string $identifier
Definition: FileAddedMessage.php:37
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_encodeForJavaScriptValue
‪string stdWrap_encodeForJavaScriptValue($content='')
Definition: ContentObjectRenderer.php:1926
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$checkPid_badDoktypeList
‪string int null $checkPid_badDoktypeList
Definition: ContentObjectRenderer.php:318
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\replacement
‪string replacement($content, array $configuration)
Definition: ContentObjectRenderer.php:2825
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_fieldRequired
‪string stdWrap_fieldRequired($content='', $conf=[])
Definition: ContentObjectRenderer.php:1525
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_postUserFunc
‪string stdWrap_postUserFunc($content='', $conf=[])
Definition: ContentObjectRenderer.php:2256
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getGlobal
‪mixed getGlobal($keyString, $source=null)
Definition: ContentObjectRenderer.php:4173
‪TYPO3\CMS\Frontend\ContentObject\Event\BeforeStdWrapContentStoredInCacheEvent
Definition: BeforeStdWrapContentStoredInCacheEvent.php:30
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_cacheStore
‪string null stdWrap_cacheStore($content='', $conf=[])
Definition: ContentObjectRenderer.php:2327