|
@@ -1,43 +1,70 @@
|
|
|
<?php
|
|
<?php
|
|
|
|
|
+declare(strict_types=1);
|
|
|
|
|
|
|
|
namespace Opentalent\OtTemplating\ViewHelpers;
|
|
namespace Opentalent\OtTemplating\ViewHelpers;
|
|
|
|
|
|
|
|
|
|
+use Psr\Http\Message\ServerRequestInterface;
|
|
|
|
|
+use TYPO3\CMS\Core\Context\Context;
|
|
|
|
|
+use TYPO3\CMS\Core\Routing\PageArguments;
|
|
|
|
|
+use TYPO3\CMS\Core\Site\Entity\SiteInterface;
|
|
|
|
|
+use TYPO3\CMS\Core\Site\SiteFinder;
|
|
|
|
|
+use TYPO3\CMS\Core\TimeTracker\TimeTracker;
|
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
|
|
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
|
|
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
|
|
|
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
|
|
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
|
|
|
|
|
+use TYPO3\CMS\Fluid\Core\Rendering\RenderingContext;
|
|
|
|
|
+use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
|
|
|
|
|
+use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
|
|
|
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
|
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
|
|
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
|
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
|
|
|
|
+use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
|
|
use TYPO3Fluid\Fluid\Core\ViewHelper\Exception;
|
|
use TYPO3Fluid\Fluid\Core\ViewHelper\Exception;
|
|
|
|
|
+use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithContentArgumentAndRenderStatic;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * This view helper is a wrapper for the Fluid/CObjectViewhelper class
|
|
|
|
|
- * that allow to override the TS setup of the object by given variables
|
|
|
|
|
|
|
+ * This view helper is a modified version of the TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper class
|
|
|
|
|
+ * that allow to override the TS setup of the object by given variables
|
|
|
*
|
|
*
|
|
|
- * It accepts the same arguments as \TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper,
|
|
|
|
|
- * and an additional argument 'settings'
|
|
|
|
|
|
|
+ * It accepts the same arguments as \TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper,
|
|
|
|
|
+ * and an additional argument 'settings'
|
|
|
*
|
|
*
|
|
|
- * @see https://docs.typo3.org/p/georgringer/news/master/en-us/Introduction/Index.html
|
|
|
|
|
|
|
+ * @see https://docs.typo3.org/p/georgringer/news/master/en-us/Introduction/Index.html
|
|
|
*
|
|
*
|
|
|
- * example:
|
|
|
|
|
|
|
+ * example:
|
|
|
*
|
|
*
|
|
|
- * {namespace ot=Opentalent\OtTemplating\ViewHelpers}
|
|
|
|
|
- *
|
|
|
|
|
- * <ot:cObject typoscriptObjectPath="lib.tx_ottemplating.widgets.news_list"
|
|
|
|
|
- * settings="{'settings.defaultPageUid': 1}" />
|
|
|
|
|
|
|
+ * {namespace ot=Opentalent\OtTemplating\ViewHelpers}
|
|
|
*
|
|
*
|
|
|
|
|
+ * <ot:cObject typoscriptObjectPath="lib.tx_ottemplating.widgets.news_list"
|
|
|
|
|
+ * settings="{'settings.defaultPageUid': 1}" />
|
|
|
*
|
|
*
|
|
|
* @package Opentalent\OtTemplating\ViewHelpers
|
|
* @package Opentalent\OtTemplating\ViewHelpers
|
|
|
*/
|
|
*/
|
|
|
-class CObjectViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper {
|
|
|
|
|
|
|
+final class CObjectViewHelper extends AbstractViewHelper
|
|
|
|
|
+{
|
|
|
|
|
+ use CompileWithContentArgumentAndRenderStatic;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * Initialize arguments.
|
|
|
|
|
|
|
+ * Disable escaping of child nodes' output
|
|
|
*
|
|
*
|
|
|
- * @throws Exception
|
|
|
|
|
|
|
+ * @var bool
|
|
|
|
|
+ */
|
|
|
|
|
+ protected $escapeChildren = false;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Disable escaping of this node's output
|
|
|
|
|
+ *
|
|
|
|
|
+ * @var bool
|
|
|
*/
|
|
*/
|
|
|
- public function initializeArguments()
|
|
|
|
|
|
|
+ protected $escapeOutput = false;
|
|
|
|
|
+
|
|
|
|
|
+ public function initializeArguments(): void
|
|
|
{
|
|
{
|
|
|
- parent::initializeArguments();
|
|
|
|
|
|
|
+ $this->registerArgument('data', 'mixed', 'the data to be used for rendering the cObject. Can be an object, array or string. If this argument is not set, child nodes will be used');
|
|
|
|
|
+ $this->registerArgument('typoscriptObjectPath', 'string', 'the TypoScript setup path of the TypoScript object to render', true);
|
|
|
|
|
+ $this->registerArgument('currentValueKey', 'string', 'currentValueKey');
|
|
|
|
|
+ $this->registerArgument('table', 'string', 'the table name associated with "data" argument. Typically tt_content or one of your custom tables. This argument should be set if rendering a FILES cObject where file references are used, or if the data argument is a database record.', false, '');
|
|
|
|
|
+
|
|
|
|
|
+ // <-- Additional paramter
|
|
|
$this->registerArgument(
|
|
$this->registerArgument(
|
|
|
'settings',
|
|
'settings',
|
|
|
'array',
|
|
'array',
|
|
@@ -48,26 +75,23 @@ class CObjectViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * <!> This is a copy/paste of the parent method, slighly modified
|
|
|
|
|
- * to override the $setup variable with the 'settings' argument
|
|
|
|
|
- *
|
|
|
|
|
* Renders the TypoScript object in the given TypoScript setup path.
|
|
* Renders the TypoScript object in the given TypoScript setup path.
|
|
|
*
|
|
*
|
|
|
- * @param array $arguments
|
|
|
|
|
- * @param \Closure $renderChildrenClosure
|
|
|
|
|
- * @param RenderingContextInterface $renderingContext
|
|
|
|
|
- * @return mixed
|
|
|
|
|
* @throws Exception
|
|
* @throws Exception
|
|
|
*/
|
|
*/
|
|
|
- public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
|
|
|
|
|
|
|
+ public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext): string
|
|
|
{
|
|
{
|
|
|
$data = $renderChildrenClosure();
|
|
$data = $renderChildrenClosure();
|
|
|
- $typoscriptObjectPath = $arguments['typoscriptObjectPath'];
|
|
|
|
|
|
|
+ $typoscriptObjectPath = (string)$arguments['typoscriptObjectPath'];
|
|
|
$currentValueKey = $arguments['currentValueKey'];
|
|
$currentValueKey = $arguments['currentValueKey'];
|
|
|
$table = $arguments['table'];
|
|
$table = $arguments['table'];
|
|
|
- $contentObjectRenderer = static::getContentObjectRenderer($renderingContext->getRequest());
|
|
|
|
|
|
|
+ /** @var RenderingContext $renderingContext */
|
|
|
|
|
+ $request = $renderingContext->getRequest();
|
|
|
|
|
+ $contentObjectRenderer = self::getContentObjectRenderer($request);
|
|
|
|
|
+ $contentObjectRenderer->setRequest($request);
|
|
|
|
|
+ $tsfeBackup = null;
|
|
|
if (!isset($GLOBALS['TSFE']) || !($GLOBALS['TSFE'] instanceof TypoScriptFrontendController)) {
|
|
if (!isset($GLOBALS['TSFE']) || !($GLOBALS['TSFE'] instanceof TypoScriptFrontendController)) {
|
|
|
- static::simulateFrontendEnvironment();
|
|
|
|
|
|
|
+ $tsfeBackup = self::simulateFrontendEnvironment();
|
|
|
}
|
|
}
|
|
|
$currentValue = null;
|
|
$currentValue = null;
|
|
|
if (is_object($data)) {
|
|
if (is_object($data)) {
|
|
@@ -83,8 +107,8 @@ class CObjectViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper {
|
|
|
$contentObjectRenderer->setCurrentVal($data[$currentValueKey]);
|
|
$contentObjectRenderer->setCurrentVal($data[$currentValueKey]);
|
|
|
}
|
|
}
|
|
|
$pathSegments = GeneralUtility::trimExplode('.', $typoscriptObjectPath);
|
|
$pathSegments = GeneralUtility::trimExplode('.', $typoscriptObjectPath);
|
|
|
- $lastSegment = array_pop($pathSegments);
|
|
|
|
|
- $setup = static::getConfigurationManager()->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT);
|
|
|
|
|
|
|
+ $lastSegment = (string)array_pop($pathSegments);
|
|
|
|
|
+ $setup = self::getConfigurationManager()->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT);
|
|
|
foreach ($pathSegments as $segment) {
|
|
foreach ($pathSegments as $segment) {
|
|
|
if (!array_key_exists($segment . '.', $setup)) {
|
|
if (!array_key_exists($segment . '.', $setup)) {
|
|
|
throw new Exception(
|
|
throw new Exception(
|
|
@@ -107,12 +131,93 @@ class CObjectViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper {
|
|
|
|
|
|
|
|
$content = self::renderContentObject($contentObjectRenderer, $setup, $typoscriptObjectPath, $lastSegment);
|
|
$content = self::renderContentObject($contentObjectRenderer, $setup, $typoscriptObjectPath, $lastSegment);
|
|
|
if (!isset($GLOBALS['TSFE']) || !($GLOBALS['TSFE'] instanceof TypoScriptFrontendController)) {
|
|
if (!isset($GLOBALS['TSFE']) || !($GLOBALS['TSFE'] instanceof TypoScriptFrontendController)) {
|
|
|
- static::resetFrontendEnvironment();
|
|
|
|
|
|
|
+ self::resetFrontendEnvironment($tsfeBackup);
|
|
|
|
|
+ }
|
|
|
|
|
+ return $content;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Renders single content object and increases time tracker stack pointer
|
|
|
|
|
+ */
|
|
|
|
|
+ protected static function renderContentObject(ContentObjectRenderer $contentObjectRenderer, array $setup, string $typoscriptObjectPath, string $lastSegment): string
|
|
|
|
|
+ {
|
|
|
|
|
+ $timeTracker = GeneralUtility::makeInstance(TimeTracker::class);
|
|
|
|
|
+ if ($timeTracker->LR) {
|
|
|
|
|
+ $timeTracker->push('/f:cObject/', '<' . $typoscriptObjectPath);
|
|
|
|
|
+ }
|
|
|
|
|
+ $timeTracker->incStackPointer();
|
|
|
|
|
+ $content = $contentObjectRenderer->cObjGetSingle($setup[$lastSegment], $setup[$lastSegment . '.'] ?? [], $typoscriptObjectPath);
|
|
|
|
|
+ $timeTracker->decStackPointer();
|
|
|
|
|
+ if ($timeTracker->LR) {
|
|
|
|
|
+ $timeTracker->pull($content);
|
|
|
}
|
|
}
|
|
|
return $content;
|
|
return $content;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ protected static function getConfigurationManager(): ConfigurationManagerInterface
|
|
|
|
|
+ {
|
|
|
|
|
+ // @todo: this should be replaced by DI once Fluid can handle DI properly
|
|
|
|
|
+ return GeneralUtility::getContainer()->get(ConfigurationManagerInterface::class);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ protected static function getContentObjectRenderer(ServerRequestInterface $request): ContentObjectRenderer
|
|
|
|
|
+ {
|
|
|
|
|
+ if (($GLOBALS['TSFE'] ?? null) instanceof TypoScriptFrontendController) {
|
|
|
|
|
+ $tsfe = $GLOBALS['TSFE'];
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $site = $request->getAttribute('site');
|
|
|
|
|
+ if (!($site instanceof SiteInterface)) {
|
|
|
|
|
+ $sites = GeneralUtility::makeInstance(SiteFinder::class)->getAllSites();
|
|
|
|
|
+ $site = reset($sites);
|
|
|
|
|
+ }
|
|
|
|
|
+ $language = $request->getAttribute('language') ?? $site->getDefaultLanguage();
|
|
|
|
|
+ $pageArguments = $request->getAttribute('routing') ?? new PageArguments(0, '0', []);
|
|
|
|
|
+ $tsfe = GeneralUtility::makeInstance(
|
|
|
|
|
+ TypoScriptFrontendController::class,
|
|
|
|
|
+ GeneralUtility::makeInstance(Context::class),
|
|
|
|
|
+ $site,
|
|
|
|
|
+ $language,
|
|
|
|
|
+ $pageArguments,
|
|
|
|
|
+ GeneralUtility::makeInstance(FrontendUserAuthentication::class)
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ $contentObjectRenderer = GeneralUtility::makeInstance(ContentObjectRenderer::class, $tsfe);
|
|
|
|
|
+ $parent = $request->getAttribute('currentContentObject');
|
|
|
|
|
+ if ($parent instanceof ContentObjectRenderer) {
|
|
|
|
|
+ $contentObjectRenderer->setParent($parent->data, $parent->currentRecord);
|
|
|
|
|
+ }
|
|
|
|
|
+ return $contentObjectRenderer;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->cObjGetSingle() relies on $GLOBALS['TSFE']
|
|
|
|
|
+ */
|
|
|
|
|
+ protected static function simulateFrontendEnvironment(): ?TypoScriptFrontendController
|
|
|
|
|
+ {
|
|
|
|
|
+ $tsfeBackup = $GLOBALS['TSFE'] ?? null;
|
|
|
|
|
+ $GLOBALS['TSFE'] = new \stdClass();
|
|
|
|
|
+ $GLOBALS['TSFE']->cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
|
|
|
|
|
+ return $tsfeBackup;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Resets $GLOBALS['TSFE'] if it was previously changed by simulateFrontendEnvironment()
|
|
|
|
|
+ */
|
|
|
|
|
+ protected static function resetFrontendEnvironment(?TypoScriptFrontendController $tsfeBackup): void
|
|
|
|
|
+ {
|
|
|
|
|
+ $GLOBALS['TSFE'] = $tsfeBackup;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Explicitly set argument name to be used as content.
|
|
|
|
|
+ */
|
|
|
|
|
+ public function resolveContentArgumentName(): string
|
|
|
|
|
+ {
|
|
|
|
|
+ return 'data';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
|
|
+ * -- Additional method --
|
|
|
* Recursively replace any {$var} value in the given configuration
|
|
* Recursively replace any {$var} value in the given configuration
|
|
|
* if 'var' is a key in the 'overrideSetup' array
|
|
* if 'var' is a key in the 'overrideSetup' array
|
|
|
*
|
|
*
|
|
@@ -143,6 +248,7 @@ class CObjectViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
|
|
+ * -- Additional method --
|
|
|
* Similar to array_merge_recursive, except that the end nodes of the
|
|
* Similar to array_merge_recursive, except that the end nodes of the
|
|
|
* base array is replaced and not merged.
|
|
* base array is replaced and not merged.
|
|
|
*
|
|
*
|