CObjectViewHelper.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. <?php
  2. namespace Opentalent\OtTemplating\ViewHelpers;
  3. use TYPO3\CMS\Core\Utility\GeneralUtility;
  4. use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
  5. use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
  6. use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
  7. use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
  8. use TYPO3Fluid\Fluid\Core\ViewHelper\Exception;
  9. /**
  10. * This view helper is a wrapper for the Fluid/CObjectViewhelper class
  11. * that allow to override the TS setup of the object by given variables
  12. *
  13. * It accepts the same arguments as \TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper,
  14. * and an additional argument 'settings'
  15. *
  16. * @see https://docs.typo3.org/p/georgringer/news/master/en-us/Introduction/Index.html
  17. *
  18. * example:
  19. *
  20. * {namespace ot=Opentalent\OtTemplating\ViewHelpers}
  21. *
  22. * <ot:cObject typoscriptObjectPath="lib.tx_ottemplating.widgets.news_list"
  23. * settings="{'settings.defaultPageUid': 1}" />
  24. *
  25. *
  26. * @package Opentalent\OtTemplating\ViewHelpers
  27. */
  28. class CObjectViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper {
  29. /**
  30. * Initialize arguments.
  31. *
  32. * @throws Exception
  33. */
  34. public function initializeArguments()
  35. {
  36. parent::initializeArguments();
  37. $this->registerArgument(
  38. 'settings',
  39. 'array',
  40. 'For each key in this array, the setup entry will be replaced by the corresponding value',
  41. false,
  42. []
  43. );
  44. }
  45. /**
  46. * <!> This is a copy/paste of the parent method, slighly modified
  47. * to override the $setup variable with the 'settings' argument
  48. *
  49. * Renders the TypoScript object in the given TypoScript setup path.
  50. *
  51. * @param array $arguments
  52. * @param \Closure $renderChildrenClosure
  53. * @param RenderingContextInterface $renderingContext
  54. * @return mixed
  55. * @throws Exception
  56. */
  57. public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
  58. {
  59. $data = $renderChildrenClosure();
  60. $typoscriptObjectPath = $arguments['typoscriptObjectPath'];
  61. $currentValueKey = $arguments['currentValueKey'];
  62. $table = $arguments['table'];
  63. $contentObjectRenderer = static::getContentObjectRenderer($renderingContext->getRequest());
  64. if (!isset($GLOBALS['TSFE']) || !($GLOBALS['TSFE'] instanceof TypoScriptFrontendController)) {
  65. static::simulateFrontendEnvironment();
  66. }
  67. $currentValue = null;
  68. if (is_object($data)) {
  69. $data = ObjectAccess::getGettableProperties($data);
  70. } elseif (is_string($data) || is_numeric($data)) {
  71. $currentValue = (string)$data;
  72. $data = [$data];
  73. }
  74. $contentObjectRenderer->start($data, $table);
  75. if ($currentValue !== null) {
  76. $contentObjectRenderer->setCurrentVal($currentValue);
  77. } elseif ($currentValueKey !== null && isset($data[$currentValueKey])) {
  78. $contentObjectRenderer->setCurrentVal($data[$currentValueKey]);
  79. }
  80. $pathSegments = GeneralUtility::trimExplode('.', $typoscriptObjectPath);
  81. $lastSegment = array_pop($pathSegments);
  82. $setup = static::getConfigurationManager()->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT);
  83. foreach ($pathSegments as $segment) {
  84. if (!array_key_exists($segment . '.', $setup)) {
  85. throw new Exception(
  86. 'TypoScript object path "' . $typoscriptObjectPath . '" does not exist',
  87. 1253191023
  88. );
  89. }
  90. $setup = $setup[$segment . '.'];
  91. }
  92. if (!isset($setup[$lastSegment])) {
  93. throw new Exception(
  94. 'No Content Object definition found at TypoScript object path "' . $typoscriptObjectPath . '"',
  95. 1540246570
  96. );
  97. }
  98. // <---- Added by Opentalent to override the TS setup
  99. $setup = self::evalConfiguration($setup, $lastSegment, $arguments['settings']);
  100. // ----->
  101. $content = self::renderContentObject($contentObjectRenderer, $setup, $typoscriptObjectPath, $lastSegment);
  102. if (!isset($GLOBALS['TSFE']) || !($GLOBALS['TSFE'] instanceof TypoScriptFrontendController)) {
  103. static::resetFrontendEnvironment();
  104. }
  105. return $content;
  106. }
  107. /**
  108. * Recursively replace any {$var} value in the given configuration
  109. * if 'var' is a key in the 'overrideSetup' array
  110. *
  111. * @param array $setup
  112. * @param string $entry_name
  113. * @param array $override_settings
  114. * @return array
  115. */
  116. private static function evalConfiguration(array $setup, string $entry_name, array $override_settings) {
  117. $entry_setup = $setup[$entry_name . '.'];
  118. foreach ($override_settings as $key => $val) {
  119. $override = [];
  120. $path = explode('.', $key);
  121. foreach (array_reverse($path) as $i => $segment) {
  122. if ($i == 0) {
  123. $override[$segment] = $val;
  124. } else {
  125. $override = [$segment . '.' => $override];
  126. }
  127. }
  128. $entry_setup = self::merge($entry_setup, $override);
  129. }
  130. $setup[$entry_name . '.'] = $entry_setup;
  131. return $setup;
  132. }
  133. /**
  134. * Similar to array_merge_recursive, except that the end nodes of the
  135. * base array is replaced and not merged.
  136. *
  137. * @param $base_array
  138. * @param $override
  139. * @return mixed
  140. */
  141. private static function merge($base_array, $override) {
  142. foreach ($base_array as $key => $val) {
  143. if (!isset($override[$key])) {
  144. continue;
  145. }
  146. if (is_array($val)) {
  147. $base_array[$key] = self::merge($val, $override[$key]);
  148. } else {
  149. $base_array[$key] = $override[$key];
  150. }
  151. }
  152. return $base_array;
  153. }
  154. }