‪TYPO3CMS  11.5
MarkerBasedTemplateService.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 
21 
27 {
37  public function ‪getSubpart($content, $marker)
38  {
39  $start = strpos($content, $marker);
40  if ($start === false) {
41  return '';
42  }
43  $start += strlen($marker);
44  $stop = strpos($content, $marker, $start);
45  // Q: What shall get returned if no stop marker is given
46  // Everything till the end or nothing?
47  if ($stop === false) {
48  return '';
49  }
50  $content = substr($content, $start, $stop - $start);
51  $matches = [];
52  if (preg_match('/^([^\\<]*\\-\\-\\>)(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $content, $matches) === 1) {
53  return $matches[2];
54  }
55  // Resetting $matches
56  $matches = [];
57  if (preg_match('/(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $content, $matches) === 1) {
58  return $matches[1];
59  }
60  // Resetting $matches
61  $matches = [];
62  if (preg_match('/^([^\\<]*\\-\\-\\>)(.*)$/s', $content, $matches) === 1) {
63  return $matches[2];
64  }
65 
66  return $content;
67  }
68 
80  public function ‪substituteSubpart($content, $marker, $subpartContent, $recursive = true, $keepMarker = false)
81  {
82  $start = strpos($content, $marker);
83  if ($start === false) {
84  return $content;
85  }
86  $startAM = $start + strlen($marker);
87  $stop = strpos($content, $marker, $startAM);
88  if ($stop === false) {
89  return $content;
90  }
91  $stopAM = $stop + strlen($marker);
92  $before = substr($content, 0, $start);
93  $after = substr($content, $stopAM);
94  $between = substr($content, $startAM, $stop - $startAM);
95  if ($recursive) {
96  $after = $this->‪substituteSubpart($after, $marker, $subpartContent, $recursive, $keepMarker);
97  }
98  if ($keepMarker) {
99  $matches = [];
100  if (preg_match('/^([^\\<]*\\-\\-\\>)(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $between, $matches) === 1) {
101  $before .= $marker . $matches[1];
102  $between = $matches[2];
103  $after = $matches[3] . $marker . $after;
104  } elseif (preg_match('/^(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $between, $matches) === 1) {
105  $before .= $marker;
106  $between = $matches[1];
107  $after = $matches[2] . $marker . $after;
108  } elseif (preg_match('/^([^\\<]*\\-\\-\\>)(.*)$/s', $between, $matches) === 1) {
109  $before .= $marker . $matches[1];
110  $between = $matches[2];
111  $after = $marker . $after;
112  } else {
113  $before .= $marker;
114  $after = $marker . $after;
115  }
116  } else {
117  $matches = [];
118  if (preg_match('/^(.*)\\<\\!\\-\\-[^\\>]*$/s', $before, $matches) === 1) {
119  $before = $matches[1];
120  }
121  if (is_array($subpartContent)) {
122  $matches = [];
123  if (preg_match('/^([^\\<]*\\-\\-\\>)(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $between, $matches) === 1) {
124  $between = $matches[2];
125  } elseif (preg_match('/^(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $between, $matches) === 1) {
126  $between = $matches[1];
127  } elseif (preg_match('/^([^\\<]*\\-\\-\\>)(.*)$/s', $between, $matches) === 1) {
128  $between = $matches[2];
129  }
130  }
131  $matches = [];
132  // resetting $matches
133  if (preg_match('/^[^\\<]*\\-\\-\\>(.*)$/s', $after, $matches) === 1) {
134  $after = $matches[1];
135  }
136  }
137  if (is_array($subpartContent)) {
138  $between = $subpartContent[0] . $between . $subpartContent[1];
139  } else {
140  $between = $subpartContent;
141  }
142 
143  return $before . $between . $after;
144  }
145 
154  public function ‪substituteSubpartArray($content, array $subpartsContent)
155  {
156  foreach ($subpartsContent as $subpartMarker => $subpartContent) {
157  $content = $this->‪substituteSubpart($content, $subpartMarker, $subpartContent);
158  }
159 
160  return $content;
161  }
162 
174  public function ‪substituteMarker($content, $marker, $markContent)
175  {
176  return str_replace($marker, $markContent, $content);
177  }
178 
199  public function ‪substituteMarkerArray($content, $markContentArray, $wrap = '', $uppercase = false, $deleteUnused = false)
200  {
201  if (is_array($markContentArray)) {
202  $wrapArr = ‪GeneralUtility::trimExplode('|', $wrap);
203  $search = [];
204  $replace = [];
205  foreach ($markContentArray as $marker => $markContent) {
206  if ($uppercase) {
207  // use strtr instead of strtoupper to avoid locale problems with Turkish
208  $marker = strtr($marker, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
209  }
210  if (isset($wrapArr[0], $wrapArr[1])) {
211  $marker = $wrapArr[0] . $marker . $wrapArr[1];
212  }
213  $search[] = $marker;
214  $replace[] = $markContent;
215  }
216  $content = str_replace($search, $replace, $content);
217  unset($search, $replace);
218  if ($deleteUnused) {
219  if (empty($wrap)) {
220  $wrapArr = ['###', '###'];
221  }
222  $content = preg_replace('/' . preg_quote($wrapArr[0], '/') . '([A-Z0-9_|\\-]*)' . preg_quote($wrapArr[1], '/') . '/is', '', $content);
223  }
224  }
225 
226  return $content;
227  }
228 
264  public function ‪substituteMarkerAndSubpartArrayRecursive($content, array $markersAndSubparts, $wrap = '', $uppercase = false, $deleteUnused = false)
265  {
266  $wraps = ‪GeneralUtility::trimExplode('|', $wrap);
267  $singleItems = [];
268  $compoundItems = [];
269  // Split markers and subparts into separate arrays
270  foreach ($markersAndSubparts as $markerName => $markerContent) {
271  if (is_array($markerContent)) {
272  $compoundItems[] = $markerName;
273  } else {
274  $singleItems[$markerName] = $markerContent;
275  }
276  }
277  $subTemplates = [];
278  $subpartSubstitutes = [];
279  // Build a cache for the sub template
280  foreach ($compoundItems as $subpartMarker) {
281  if ($uppercase) {
282  // Use strtr instead of strtoupper to avoid locale problems with Turkish
283  $subpartMarker = strtr($subpartMarker, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
284  }
285  if (isset($wraps[0], $wraps[1])) {
286  $subpartMarker = $wraps[0] . $subpartMarker . $wraps[1];
287  }
288  $subTemplates[$subpartMarker] = $this->‪getSubpart($content, $subpartMarker);
289  }
290  // Replace the subpart contents recursively
291  foreach ($compoundItems as $subpartMarker) {
292  $completeMarker = $subpartMarker;
293  if ($uppercase) {
294  // use strtr instead of strtoupper to avoid locale problems with Turkish
295  $completeMarker = strtr($completeMarker, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
296  }
297  if (isset($wraps[0], $wraps[1])) {
298  $completeMarker = $wraps[0] . $completeMarker . $wraps[1];
299  }
300  if (!empty($markersAndSubparts[$subpartMarker])) {
301  $subpartSubstitutes[$completeMarker] = '';
302  foreach ($markersAndSubparts[$subpartMarker] as $partialMarkersAndSubparts) {
303  $subpartSubstitutes[$completeMarker] .= $this->‪substituteMarkerAndSubpartArrayRecursive(
304  $subTemplates[$completeMarker],
305  $partialMarkersAndSubparts,
306  $wrap,
307  $uppercase,
308  $deleteUnused
309  );
310  }
311  } else {
312  $subpartSubstitutes[$completeMarker] = '';
313  }
314  }
315  // Substitute the single markers and subparts
316  $result = $this->‪substituteSubpartArray($content, $subpartSubstitutes);
317  $result = $this->‪substituteMarkerArray($result, $singleItems, $wrap, $uppercase, $deleteUnused);
318 
319  return $result;
320  }
321 
356  public function ‪substituteMarkerArrayCached($content, array $markContentArray = null, array $subpartContentArray = null, array $wrappedSubpartContentArray = null)
357  {
358  $runtimeCache = $this->‪getRuntimeCache();
359  // If not arrays then set them
360  if ($markContentArray === null) {
361  // Plain markers
362  $markContentArray = [];
363  }
364  if ($subpartContentArray === null) {
365  // Subparts being directly substituted
366  $subpartContentArray = [];
367  }
368  if ($wrappedSubpartContentArray === null) {
369  // Subparts being wrapped
370  $wrappedSubpartContentArray = [];
371  }
372  // Finding keys and check hash:
373  $sPkeys = array_keys($subpartContentArray);
374  $wPkeys = array_keys($wrappedSubpartContentArray);
375  $keysToReplace = array_merge(array_keys($markContentArray), $sPkeys, $wPkeys);
376  if (empty($keysToReplace)) {
377  return $content;
378  }
379  asort($keysToReplace);
380  $storeKey = md5('substituteMarkerArrayCached_storeKey:' . serialize([$content, $keysToReplace]));
381  $fromCache = $runtimeCache->get($storeKey);
382  if ($fromCache) {
383  $storeArr = $fromCache;
384  } else {
385  $cache = $this->‪getCache();
386  $storeArrDat = $cache->get($storeKey);
387  if (is_array($storeArrDat)) {
388  $storeArr = $storeArrDat;
389  // Setting the data in the first level cache
390  $runtimeCache->set($storeKey, $storeArr);
391  } else {
392  // Finding subparts and substituting them with the subpart as a marker
393  foreach ($sPkeys as $sPK) {
394  $content = $this->‪substituteSubpart($content, $sPK, $sPK);
395  }
396  // Finding subparts and wrapping them with markers
397  foreach ($wPkeys as $wPK) {
398  $content = $this->‪substituteSubpart($content, $wPK, [
399  $wPK,
400  $wPK,
401  ]);
402  }
403 
404  $storeArr = [];
405  // search all markers in the content
406  $result = preg_match_all('/###([^#](?:[^#]*+|#{1,2}[^#])+)###/', $content, $markersInContent);
407  if ($result !== false && !empty($markersInContent[1])) {
408  $keysToReplaceFlipped = array_flip($keysToReplace);
409  $regexKeys = [];
410  $wrappedKeys = [];
411  // Traverse keys and quote them for reg ex.
412  foreach ($markersInContent[1] as $key) {
413  if (isset($keysToReplaceFlipped['###' . $key . '###'])) {
414  $regexKeys[] = preg_quote($key, '/');
415  $wrappedKeys[] = '###' . $key . '###';
416  }
417  }
418  $regex = '/###(?:' . implode('|', $regexKeys) . ')###/';
419  $storeArr['c'] = preg_split($regex, $content); // contains all content parts around markers
420  $storeArr['k'] = $wrappedKeys; // contains all markers incl. ###
421  // Setting the data inside the second-level cache
422  $runtimeCache->set($storeKey, $storeArr);
423  // Storing the cached data permanently
424  $cache->set($storeKey, $storeArr, ['substMarkArrayCached'], 0);
425  }
426  }
427  }
428  if (!empty($storeArr['k']) && is_array($storeArr['k'])) {
429  // Substitution/Merging:
430  // Merging content types together, resetting
431  $valueArr = array_merge($markContentArray, $subpartContentArray, $wrappedSubpartContentArray);
432  $wSCA_reg = [];
433  $content = '';
434  // Traversing the keyList array and merging the static and dynamic content
435  foreach ($storeArr['k'] as $n => $keyN) {
436  // add content before marker
437  $content .= $storeArr['c'][$n];
438  if (!is_array($valueArr[$keyN])) {
439  // fetch marker replacement from $markContentArray or $subpartContentArray
440  $content .= $valueArr[$keyN];
441  } else {
442  if (!isset($wSCA_reg[$keyN])) {
443  $wSCA_reg[$keyN] = 0;
444  }
445  // fetch marker replacement from $wrappedSubpartContentArray
446  $content .= $valueArr[$keyN][$wSCA_reg[$keyN] % 2];
447  $wSCA_reg[$keyN]++;
448  }
449  }
450  // add remaining content
451  $content .= $storeArr['c'][count($storeArr['k'])];
452  }
453  return $content;
454  }
455 
464  public function ‪substituteMarkerInObject(&$tree, array $markContentArray)
465  {
466  if (is_array($tree)) {
467  foreach ($tree as $key => $value) {
468  $this->‪substituteMarkerInObject($tree[$key], $markContentArray);
469  }
470  } else {
471  $tree = $this->‪substituteMarkerArray($tree, $markContentArray);
472  }
473  return $tree;
474  }
475 
489  public function ‪fillInMarkerArray(array $markContentArray, array $row, $fieldList = '', $nl2br = true, $prefix = 'FIELD_', $htmlSpecialCharsValue = false, $respectXhtml = false)
490  {
491  if ($fieldList) {
492  $fArr = ‪GeneralUtility::trimExplode(',', $fieldList, true);
493  foreach ($fArr as $field) {
494  $markContentArray['###' . $prefix . $field . '###'] = $nl2br ? nl2br($row[$field], $respectXhtml) : $row[$field];
495  }
496  } else {
497  if (is_array($row)) {
498  foreach ($row as $field => $value) {
500  if ($htmlSpecialCharsValue) {
501  $value = htmlspecialchars($value);
502  }
503  $markContentArray['###' . $prefix . $field . '###'] = $nl2br ? nl2br($value, $respectXhtml) : $value;
504  }
505  }
506  }
507  }
508  return $markContentArray;
509  }
510 
516  protected function ‪getCache()
517  {
518  return GeneralUtility::makeInstance(CacheManager::class)->getCache('hash');
519  }
520 
526  protected function ‪getRuntimeCache()
527  {
528  return GeneralUtility::makeInstance(CacheManager::class)->getCache('runtime');
529  }
530 }
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:999
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\substituteMarkerInObject
‪mixed substituteMarkerInObject(&$tree, array $markContentArray)
Definition: MarkerBasedTemplateService.php:464
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger($var)
Definition: MathUtility.php:74
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\getRuntimeCache
‪TYPO3 CMS Core Cache Frontend FrontendInterface getRuntimeCache()
Definition: MarkerBasedTemplateService.php:526
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\substituteMarkerAndSubpartArrayRecursive
‪string substituteMarkerAndSubpartArrayRecursive($content, array $markersAndSubparts, $wrap='', $uppercase=false, $deleteUnused=false)
Definition: MarkerBasedTemplateService.php:264
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\substituteMarkerArray
‪string substituteMarkerArray($content, $markContentArray, $wrap='', $uppercase=false, $deleteUnused=false)
Definition: MarkerBasedTemplateService.php:199
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\substituteMarker
‪string substituteMarker($content, $marker, $markContent)
Definition: MarkerBasedTemplateService.php:174
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\substituteMarkerArrayCached
‪string substituteMarkerArrayCached($content, array $markContentArray=null, array $subpartContentArray=null, array $wrappedSubpartContentArray=null)
Definition: MarkerBasedTemplateService.php:356
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\substituteSubpartArray
‪string substituteSubpartArray($content, array $subpartsContent)
Definition: MarkerBasedTemplateService.php:154
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\fillInMarkerArray
‪array fillInMarkerArray(array $markContentArray, array $row, $fieldList='', $nl2br=true, $prefix='FIELD_', $htmlSpecialCharsValue=false, $respectXhtml=false)
Definition: MarkerBasedTemplateService.php:489
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\substituteSubpart
‪string substituteSubpart($content, $marker, $subpartContent, $recursive=true, $keepMarker=false)
Definition: MarkerBasedTemplateService.php:80
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:36
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\getCache
‪TYPO3 CMS Core Cache Frontend FrontendInterface getCache()
Definition: MarkerBasedTemplateService.php:516
‪TYPO3\CMS\Core\Service
Definition: AbstractService.php:16
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:22
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService\getSubpart
‪string getSubpart($content, $marker)
Definition: MarkerBasedTemplateService.php:37
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService
Definition: MarkerBasedTemplateService.php:27
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50