‪TYPO3CMS  9.5
MarkerBasedTemplateService.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
19 
25 {
35  public function ‪getSubpart($content, $marker)
36  {
37  $start = strpos($content, $marker);
38  if ($start === false) {
39  return '';
40  }
41  $start += strlen($marker);
42  $stop = strpos($content, $marker, $start);
43  // Q: What shall get returned if no stop marker is given
44  // Everything till the end or nothing?
45  if ($stop === false) {
46  return '';
47  }
48  $content = substr($content, $start, $stop - $start);
49  $matches = [];
50  if (preg_match('/^([^\\<]*\\-\\-\\>)(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $content, $matches) === 1) {
51  return $matches[2];
52  }
53  // Resetting $matches
54  $matches = [];
55  if (preg_match('/(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $content, $matches) === 1) {
56  return $matches[1];
57  }
58  // Resetting $matches
59  $matches = [];
60  if (preg_match('/^([^\\<]*\\-\\-\\>)(.*)$/s', $content, $matches) === 1) {
61  return $matches[2];
62  }
63 
64  return $content;
65  }
66 
78  public function ‪substituteSubpart($content, $marker, $subpartContent, $recursive = true, $keepMarker = false)
79  {
80  $start = strpos($content, $marker);
81  if ($start === false) {
82  return $content;
83  }
84  $startAM = $start + strlen($marker);
85  $stop = strpos($content, $marker, $startAM);
86  if ($stop === false) {
87  return $content;
88  }
89  $stopAM = $stop + strlen($marker);
90  $before = substr($content, 0, $start);
91  $after = substr($content, $stopAM);
92  $between = substr($content, $startAM, $stop - $startAM);
93  if ($recursive) {
94  $after = $this->‪substituteSubpart($after, $marker, $subpartContent, $recursive, $keepMarker);
95  }
96  if ($keepMarker) {
97  $matches = [];
98  if (preg_match('/^([^\\<]*\\-\\-\\>)(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $between, $matches) === 1) {
99  $before .= $marker . $matches[1];
100  $between = $matches[2];
101  $after = $matches[3] . $marker . $after;
102  } elseif (preg_match('/^(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $between, $matches) === 1) {
103  $before .= $marker;
104  $between = $matches[1];
105  $after = $matches[2] . $marker . $after;
106  } elseif (preg_match('/^([^\\<]*\\-\\-\\>)(.*)$/s', $between, $matches) === 1) {
107  $before .= $marker . $matches[1];
108  $between = $matches[2];
109  $after = $marker . $after;
110  } else {
111  $before .= $marker;
112  $after = $marker . $after;
113  }
114  } else {
115  $matches = [];
116  if (preg_match('/^(.*)\\<\\!\\-\\-[^\\>]*$/s', $before, $matches) === 1) {
117  $before = $matches[1];
118  }
119  if (is_array($subpartContent)) {
120  $matches = [];
121  if (preg_match('/^([^\\<]*\\-\\-\\>)(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $between, $matches) === 1) {
122  $between = $matches[2];
123  } elseif (preg_match('/^(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $between, $matches) === 1) {
124  $between = $matches[1];
125  } elseif (preg_match('/^([^\\<]*\\-\\-\\>)(.*)$/s', $between, $matches) === 1) {
126  $between = $matches[2];
127  }
128  }
129  $matches = [];
130  // resetting $matches
131  if (preg_match('/^[^\\<]*\\-\\-\\>(.*)$/s', $after, $matches) === 1) {
132  $after = $matches[1];
133  }
134  }
135  if (is_array($subpartContent)) {
136  $between = $subpartContent[0] . $between . $subpartContent[1];
137  } else {
138  $between = $subpartContent;
139  }
140 
141  return $before . $between . $after;
142  }
143 
152  public function ‪substituteSubpartArray($content, array $subpartsContent)
153  {
154  foreach ($subpartsContent as $subpartMarker => $subpartContent) {
155  $content = $this->‪substituteSubpart($content, $subpartMarker, $subpartContent);
156  }
157 
158  return $content;
159  }
160 
172  public function ‪substituteMarker($content, $marker, $markContent)
173  {
174  return str_replace($marker, $markContent, $content);
175  }
176 
196  public function ‪substituteMarkerArray($content, $markContentArray, $wrap = '', $uppercase = false, $deleteUnused = false)
197  {
198  if (is_array($markContentArray)) {
199  $wrapArr = GeneralUtility::trimExplode('|', $wrap);
200  $search = [];
201  $replace = [];
202  foreach ($markContentArray as $marker => $markContent) {
203  if ($uppercase) {
204  // use strtr instead of strtoupper to avoid locale problems with Turkish
205  $marker = strtr($marker, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
206  }
207  if (isset($wrapArr[0], $wrapArr[1])) {
208  $marker = $wrapArr[0] . $marker . $wrapArr[1];
209  }
210  $search[] = $marker;
211  $replace[] = $markContent;
212  }
213  $content = str_replace($search, $replace, $content);
214  unset($search, $replace);
215  if ($deleteUnused) {
216  if (empty($wrap)) {
217  $wrapArr = ['###', '###'];
218  }
219  $content = preg_replace('/' . preg_quote($wrapArr[0], '/') . '([A-Z0-9_|\\-]*)' . preg_quote($wrapArr[1], '/') . '/is', '', $content);
220  }
221  }
222 
223  return $content;
224  }
225 
261  public function ‪substituteMarkerAndSubpartArrayRecursive($content, array $markersAndSubparts, $wrap = '', $uppercase = false, $deleteUnused = false)
262  {
263  $wraps = GeneralUtility::trimExplode('|', $wrap);
264  $singleItems = [];
265  $compoundItems = [];
266  // Split markers and subparts into separate arrays
267  foreach ($markersAndSubparts as $markerName => $markerContent) {
268  if (is_array($markerContent)) {
269  $compoundItems[] = $markerName;
270  } else {
271  $singleItems[$markerName] = $markerContent;
272  }
273  }
274  $subTemplates = [];
275  $subpartSubstitutes = [];
276  // Build a cache for the sub template
277  foreach ($compoundItems as $subpartMarker) {
278  if ($uppercase) {
279  // Use strtr instead of strtoupper to avoid locale problems with Turkish
280  $subpartMarker = strtr($subpartMarker, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
281  }
282  if (isset($wraps[0], $wraps[1])) {
283  $subpartMarker = $wraps[0] . $subpartMarker . $wraps[1];
284  }
285  $subTemplates[$subpartMarker] = $this->‪getSubpart($content, $subpartMarker);
286  }
287  // Replace the subpart contents recursively
288  foreach ($compoundItems as $subpartMarker) {
289  $completeMarker = $subpartMarker;
290  if ($uppercase) {
291  // use strtr instead of strtoupper to avoid locale problems with Turkish
292  $completeMarker = strtr($completeMarker, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
293  }
294  if (isset($wraps[0], $wraps[1])) {
295  $completeMarker = $wraps[0] . $completeMarker . $wraps[1];
296  }
297  if (!empty($markersAndSubparts[$subpartMarker])) {
298  $subpartSubstitutes[$completeMarker] = '';
299  foreach ($markersAndSubparts[$subpartMarker] as $partialMarkersAndSubparts) {
300  $subpartSubstitutes[$completeMarker] .= $this->‪substituteMarkerAndSubpartArrayRecursive(
301  $subTemplates[$completeMarker],
302  $partialMarkersAndSubparts,
303  $wrap,
304  $uppercase,
305  $deleteUnused
306  );
307  }
308  } else {
309  $subpartSubstitutes[$completeMarker] = '';
310  }
311  }
312  // Substitute the single markers and subparts
313  $result = $this->‪substituteSubpartArray($content, $subpartSubstitutes);
314  $result = $this->‪substituteMarkerArray($result, $singleItems, $wrap, $uppercase, $deleteUnused);
315 
316  return $result;
317  }
318 
351  public function ‪substituteMarkerArrayCached($content, array $markContentArray = null, array $subpartContentArray = null, array $wrappedSubpartContentArray = null)
352  {
353  $runtimeCache = $this->‪getRuntimeCache();
354  // If not arrays then set them
355  if ($markContentArray === null) {
356  // Plain markers
357  $markContentArray = [];
358  }
359  if ($subpartContentArray === null) {
360  // Subparts being directly substituted
361  $subpartContentArray = [];
362  }
363  if ($wrappedSubpartContentArray === null) {
364  // Subparts being wrapped
365  $wrappedSubpartContentArray = [];
366  }
367  // Finding keys and check hash:
368  $sPkeys = array_keys($subpartContentArray);
369  $wPkeys = array_keys($wrappedSubpartContentArray);
370  $keysToReplace = array_merge(array_keys($markContentArray), $sPkeys, $wPkeys);
371  if (empty($keysToReplace)) {
372  return $content;
373  }
374  asort($keysToReplace);
375  $storeKey = md5('substituteMarkerArrayCached_storeKey:' . serialize([$content, $keysToReplace]));
376  $fromCache = $runtimeCache->get($storeKey);
377  if ($fromCache) {
378  $storeArr = $fromCache;
379  } else {
380  $cache = $this->‪getCache();
381  $storeArrDat = $cache->get($storeKey);
382  if (is_array($storeArrDat)) {
383  $storeArr = $storeArrDat;
384  // Setting the data in the first level cache
385  $runtimeCache->set($storeKey, $storeArr);
386  } else {
387  // Finding subparts and substituting them with the subpart as a marker
388  foreach ($sPkeys as $sPK) {
389  $content = $this->‪substituteSubpart($content, $sPK, $sPK);
390  }
391  // Finding subparts and wrapping them with markers
392  foreach ($wPkeys as $wPK) {
393  $content = $this->‪substituteSubpart($content, $wPK, [
394  $wPK,
395  $wPK
396  ]);
397  }
398 
399  $storeArr = [];
400  // search all markers in the content
401  $result = preg_match_all('/###([^#](?:[^#]*+|#{1,2}[^#])+)###/', $content, $markersInContent);
402  if ($result !== false && !empty($markersInContent[1])) {
403  $keysToReplaceFlipped = array_flip($keysToReplace);
404  $regexKeys = [];
405  $wrappedKeys = [];
406  // Traverse keys and quote them for reg ex.
407  foreach ($markersInContent[1] as $key) {
408  if (isset($keysToReplaceFlipped['###' . $key . '###'])) {
409  $regexKeys[] = preg_quote($key, '/');
410  $wrappedKeys[] = '###' . $key . '###';
411  }
412  }
413  $regex = '/###(?:' . implode('|', $regexKeys) . ')###/';
414  $storeArr['c'] = preg_split($regex, $content); // contains all content parts around markers
415  $storeArr['k'] = $wrappedKeys; // contains all markers incl. ###
416  // Setting the data inside the second-level cache
417  $runtimeCache->set($storeKey, $storeArr);
418  // Storing the cached data permanently
419  $cache->set($storeKey, $storeArr, ['substMarkArrayCached'], 0);
420  }
421  }
422  }
423  if (!empty($storeArr['k']) && is_array($storeArr['k'])) {
424  // Substitution/Merging:
425  // Merging content types together, resetting
426  $valueArr = array_merge($markContentArray, $subpartContentArray, $wrappedSubpartContentArray);
427  $wSCA_reg = [];
428  $content = '';
429  // Traversing the keyList array and merging the static and dynamic content
430  foreach ($storeArr['k'] as $n => $keyN) {
431  // add content before marker
432  $content .= $storeArr['c'][$n];
433  if (!is_array($valueArr[$keyN])) {
434  // fetch marker replacement from $markContentArray or $subpartContentArray
435  $content .= $valueArr[$keyN];
436  } else {
437  if (!isset($wSCA_reg[$keyN])) {
438  $wSCA_reg[$keyN] = 0;
439  }
440  // fetch marker replacement from $wrappedSubpartContentArray
441  $content .= $valueArr[$keyN][$wSCA_reg[$keyN] % 2];
442  $wSCA_reg[$keyN]++;
443  }
444  }
445  // add remaining content
446  $content .= $storeArr['c'][count($storeArr['k'])];
447  }
448  return $content;
449  }
450 
459  public function ‪substituteMarkerInObject(&$tree, array $markContentArray)
460  {
461  if (is_array($tree)) {
462  foreach ($tree as $key => $value) {
463  $this->‪substituteMarkerInObject($tree[$key], $markContentArray);
464  }
465  } else {
466  $tree = $this->‪substituteMarkerArray($tree, $markContentArray);
467  }
468  return $tree;
469  }
470 
484  public function ‪fillInMarkerArray(array $markContentArray, array $row, $fieldList = '', $nl2br = true, $prefix = 'FIELD_', $htmlSpecialCharsValue = false, $respectXhtml = false)
485  {
486  if ($fieldList) {
487  $fArr = GeneralUtility::trimExplode(',', $fieldList, true);
488  foreach ($fArr as $field) {
489  $markContentArray['###' . $prefix . $field . '###'] = $nl2br ? nl2br($row[$field], $respectXhtml) : $row[$field];
490  }
491  } else {
492  if (is_array($row)) {
493  foreach ($row as $field => $value) {
495  if ($htmlSpecialCharsValue) {
496  $value = htmlspecialchars($value);
497  }
498  $markContentArray['###' . $prefix . $field . '###'] = $nl2br ? nl2br($value, $respectXhtml) : $value;
499  }
500  }
501  }
502  }
503  return $markContentArray;
504  }
505 
511  protected function ‪getCache()
512  {
513  return GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_hash');
514  }
515 
521  protected function ‪getRuntimeCache()
522  {
523  return GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_runtime');
524  }
525 }
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\substituteMarkerInObject
‪mixed substituteMarkerInObject(&$tree, array $markContentArray)
Definition: MarkerBasedTemplateService.php:459
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger($var)
Definition: MathUtility.php:73
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\getRuntimeCache
‪TYPO3 CMS Core Cache Frontend FrontendInterface getRuntimeCache()
Definition: MarkerBasedTemplateService.php:521
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\substituteMarkerAndSubpartArrayRecursive
‪string substituteMarkerAndSubpartArrayRecursive($content, array $markersAndSubparts, $wrap='', $uppercase=false, $deleteUnused=false)
Definition: MarkerBasedTemplateService.php:261
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\substituteMarkerArray
‪string substituteMarkerArray($content, $markContentArray, $wrap='', $uppercase=false, $deleteUnused=false)
Definition: MarkerBasedTemplateService.php:196
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\substituteMarker
‪string substituteMarker($content, $marker, $markContent)
Definition: MarkerBasedTemplateService.php:172
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\substituteMarkerArrayCached
‪string substituteMarkerArrayCached($content, array $markContentArray=null, array $subpartContentArray=null, array $wrappedSubpartContentArray=null)
Definition: MarkerBasedTemplateService.php:351
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\substituteSubpartArray
‪string substituteSubpartArray($content, array $subpartsContent)
Definition: MarkerBasedTemplateService.php:152
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\fillInMarkerArray
‪array fillInMarkerArray(array $markContentArray, array $row, $fieldList='', $nl2br=true, $prefix='FIELD_', $htmlSpecialCharsValue=false, $respectXhtml=false)
Definition: MarkerBasedTemplateService.php:484
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\substituteSubpart
‪string substituteSubpart($content, $marker, $subpartContent, $recursive=true, $keepMarker=false)
Definition: MarkerBasedTemplateService.php:78
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:34
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\getCache
‪TYPO3 CMS Core Cache Frontend FrontendInterface getCache()
Definition: MarkerBasedTemplateService.php:511
‪TYPO3\CMS\Core\Service
Definition: AbstractService.php:2
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:21
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\getSubpart
‪string getSubpart($content, $marker)
Definition: MarkerBasedTemplateService.php:35
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService
Definition: MarkerBasedTemplateService.php:25
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45