/** * Pre-process the template source before it is returned to the TemplateParser or passed to * the next TemplateProcessorInterface instance. * * Detects all tags that carry an `xmlns:` definition using a Fluid-compatible prefix and a * conventional namespace URL (http://typo3.org/ns/). Extracts the detected namespaces and * removes the detected tag. * * @param string $templateSource * @return string */ public function preProcessSource($templateSource) { $matches = array(); $namespacePattern = 'xmlns:([a-z0-9]+)="(http\\:\\/\\/typo3\\.org\\/ns\\/[^"]+)"'; $matched = preg_match('/<([a-z0-9]+)(?:[^>]*?)\\s+' . $namespacePattern . '[^>]*>/', $templateSource, $matches); if ($matched) { $namespaces = array(); preg_match_all('/' . $namespacePattern . '/', $matches[0], $namespaces, PREG_SET_ORDER); foreach ($namespaces as $set) { $namespaceUrl = $set[2]; $namespaceUri = substr($namespaceUrl, 20); $namespacePhp = str_replace('/', '\\', $namespaceUri); $this->renderingContext->getViewHelperResolver()->addNamespace($set[1], $namespacePhp); } if (strpos($matches[0], 'data-namespace-typo3-fluid="true"')) { $templateSource = str_replace($matches[0], '', $templateSource); $closingTagName = $matches[1]; $closingTag = '</' . $closingTagName . '>'; if (strpos($templateSource, $closingTag)) { $templateSource = substr($templateSource, 0, strrpos($templateSource, $closingTag)) . substr($templateSource, strrpos($templateSource, $closingTag) + strlen($closingTag)); } } else { if (!empty($namespaces)) { $namespaceAttributesToRemove = []; foreach ($namespaces as $namespace) { $namespaceAttributesToRemove[] = preg_quote($namespace[1], '/') . '="' . preg_quote($namespace[2], '/') . '"'; } $matchWithRemovedNamespaceAttributes = preg_replace('/(?:\\s*+xmlns:(?:' . implode('|', $namespaceAttributesToRemove) . ')\\s*+)++/', ' ', $matches[0]); $templateSource = str_replace($matches[0], $matchWithRemovedNamespaceAttributes, $templateSource); } } } return $templateSource; }
/** * Invoke the ViewHelper described by the ViewHelperNode, the properties * of which will already have been filled by the ViewHelperResolver. * * @param string|ViewHelperInterface $viewHelperClassName * @param array $arguments * @param RenderingContextInterface $renderingContext * @param \Closure $renderChildrenClosure * @return mixed */ public function invoke($viewHelperClassNameOrInstance, array $arguments, RenderingContextInterface $renderingContext, \Closure $renderChildrenClosure = NULL) { if ($viewHelperClassNameOrInstance instanceof ViewHelperInterface) { $viewHelper = $viewHelperClassNameOrInstance; } else { $viewHelper = $this->viewHelperResolver->createViewHelperInstanceFromClassName($viewHelperClassNameOrInstance); } $expectedViewHelperArguments = $renderingContext->getViewHelperResolver()->getArgumentDefinitionsForViewHelper($viewHelper); // Rendering process $evaluatedArguments = array(); foreach ($expectedViewHelperArguments as $argumentName => $argumentDefinition) { if (isset($arguments[$argumentName])) { /** @var NodeInterface|mixed $argumentValue */ $argumentValue = $arguments[$argumentName]; $evaluatedArguments[$argumentName] = $argumentValue instanceof NodeInterface ? $argumentValue->evaluate($renderingContext) : $argumentValue; } else { $evaluatedArguments[$argumentName] = $argumentDefinition->getDefaultValue(); } } $this->abortIfUnregisteredArgumentsExist($expectedViewHelperArguments, $evaluatedArguments); $this->abortIfRequiredArgumentsAreMissing($expectedViewHelperArguments, $evaluatedArguments); $viewHelper->setArguments($evaluatedArguments); $viewHelper->setRenderingContext($renderingContext); if ($renderChildrenClosure) { $viewHelper->setRenderChildrenClosure($renderChildrenClosure); } return $viewHelper->initializeArgumentsAndRender(); }
/** * Throw an UnknownNamespaceException for any unknown and not ignored * namespace inside the template string * * @param string $templateSource * @return void */ public function throwExceptionsForUnhandledNamespaces($templateSource) { $viewHelperResolver = $this->renderingContext->getViewHelperResolver(); $splitTemplate = preg_split(Patterns::$SPLIT_PATTERN_TEMPLATE_DYNAMICTAGS, $templateSource, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); foreach ($splitTemplate as $templateElement) { if (preg_match(Patterns::$SCAN_PATTERN_TEMPLATE_VIEWHELPERTAG, $templateElement, $matchedVariables) > 0) { if (!$viewHelperResolver->isNamespaceValidOrIgnored($matchedVariables['NamespaceIdentifier'])) { throw new UnknownNamespaceException('Unkown Namespace: ' . htmlspecialchars($matchedVariables[0])); } continue; } elseif (preg_match(Patterns::$SCAN_PATTERN_TEMPLATE_CLOSINGVIEWHELPERTAG, $templateElement, $matchedVariables) > 0) { continue; } $sections = preg_split(Patterns::$SPLIT_PATTERN_SHORTHANDSYNTAX, $templateElement, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); foreach ($sections as $section) { if (preg_match(Patterns::$SCAN_PATTERN_SHORTHANDSYNTAX_OBJECTACCESSORS, $section, $matchedVariables) > 0) { preg_match_all(Patterns::$SPLIT_PATTERN_SHORTHANDSYNTAX_VIEWHELPER, $section, $shorthandViewHelpers, PREG_SET_ORDER); if (is_array($shorthandViewHelpers) === true) { foreach ($shorthandViewHelpers as $shorthandViewHelper) { if (!$viewHelperResolver->isNamespaceValidOrIgnored($shorthandViewHelper['NamespaceIdentifier'])) { throw new UnknownNamespaceException('Unkown Namespace: ' . $shorthandViewHelper['NamespaceIdentifier']); } } } } } } }
/** * Invoke the ViewHelper described by the ViewHelperNode, the properties * of which will already have been filled by the ViewHelperResolver. * * @param string|ViewHelperInterface $viewHelperClassNameOrInstance * @param array $arguments * @param RenderingContextInterface $renderingContext * @param null|\Closure $renderChildrenClosure * @return string */ public function invoke($viewHelperClassNameOrInstance, array $arguments, RenderingContextInterface $renderingContext, \Closure $renderChildrenClosure = null) { $viewHelperResolver = $renderingContext->getViewHelperResolver(); if ($viewHelperClassNameOrInstance instanceof ViewHelperInterface) { $viewHelper = $viewHelperClassNameOrInstance; } else { $viewHelper = $viewHelperResolver->createViewHelperInstanceFromClassName($viewHelperClassNameOrInstance); } $expectedViewHelperArguments = $viewHelperResolver->getArgumentDefinitionsForViewHelper($viewHelper); // Rendering process $evaluatedArguments = []; $undeclaredArguments = []; foreach ($expectedViewHelperArguments as $argumentName => $argumentDefinition) { if (isset($arguments[$argumentName])) { /** @var NodeInterface|mixed $argumentValue */ $argumentValue = $arguments[$argumentName]; $evaluatedArguments[$argumentName] = $argumentValue instanceof NodeInterface ? $argumentValue->evaluate($renderingContext) : $argumentValue; } else { $evaluatedArguments[$argumentName] = $argumentDefinition->getDefaultValue(); } } foreach ($arguments as $argumentName => $argumentValue) { if (!array_key_exists($argumentName, $evaluatedArguments)) { $undeclaredArguments[$argumentName] = $argumentValue instanceof NodeInterface ? $argumentValue->evaluate($renderingContext) : $argumentValue; } } if ($renderChildrenClosure) { $viewHelper->setRenderChildrenClosure($renderChildrenClosure); } $viewHelper->setRenderingContext($renderingContext); $viewHelper->setArguments($evaluatedArguments); $viewHelper->handleAdditionalArguments($undeclaredArguments); return $viewHelper->initializeArgumentsAndRender(); }
/** * Constructor. * * @param RenderingContextInterface $renderingContext a RenderingContext, provided by invoker * @param string $namespace the namespace identifier of the ViewHelper. * @param string $identifier the name of the ViewHelper to render, inside the namespace provided. * @param NodeInterface[] $arguments Arguments of view helper - each value is a RootNode. * @param ParsingState $state */ public function __construct(RenderingContextInterface $renderingContext, $namespace, $identifier, array $arguments, ParsingState $state) { $resolver = $renderingContext->getViewHelperResolver(); $this->arguments = $arguments; $this->viewHelperClassName = $resolver->resolveViewHelperClassName($namespace, $identifier); $this->uninitializedViewHelper = $resolver->createViewHelperInstanceFromClassName($this->viewHelperClassName); $this->uninitializedViewHelper->setRenderingContext($renderingContext); $this->uninitializedViewHelper->setViewHelperNode($this); $this->argumentDefinitions = $resolver->getArgumentDefinitionsForViewHelper($this->uninitializedViewHelper); $this->rewriteBooleanNodesInArgumentsObjectTree($this->argumentDefinitions, $this->arguments); $this->validateArguments($this->argumentDefinitions, $this->arguments); }
/** * Constructor. * * @param RenderingContextInterface $renderingContext a RenderingContext, provided by invoker * @param string $namespace the namespace identifier of the ViewHelper. * @param string $identifier the name of the ViewHelper to render, inside the namespace provided. * @param NodeInterface[] $arguments Arguments of view helper - each value is a RootNode. * @param ParsingState $state */ public function __construct(RenderingContextInterface $renderingContext, $namespace, $identifier, array $arguments, ParsingState $state) { $resolver = $renderingContext->getViewHelperResolver(); $this->arguments = $arguments; $this->viewHelperClassName = $resolver->resolveViewHelperClassName($namespace, $identifier); $this->uninitializedViewHelper = $resolver->createViewHelperInstanceFromClassName($this->viewHelperClassName); $this->uninitializedViewHelper->setViewHelperNode($this); // Note: RenderingContext required here though replaced later. See https://github.com/TYPO3Fluid/Fluid/pull/93 $this->uninitializedViewHelper->setRenderingContext($renderingContext); $this->argumentDefinitions = $resolver->getArgumentDefinitionsForViewHelper($this->uninitializedViewHelper); $this->rewriteBooleanNodesInArgumentsObjectTree($this->argumentDefinitions, $this->arguments); $this->validateArguments($this->argumentDefinitions, $this->arguments); }
/** * Handles a closing view helper tag * * @param ParsingState $state The current parsing state * @param string $namespaceIdentifier Namespace identifier for the closing tag. * @param string $methodIdentifier Method identifier. * @return boolean whether the viewHelper was found and added to the stack or not * @throws Exception */ protected function closingViewHelperTagHandler(ParsingState $state, $namespaceIdentifier, $methodIdentifier) { $viewHelperResolver = $this->renderingContext->getViewHelperResolver(); if (!$viewHelperResolver->isNamespaceValid($namespaceIdentifier)) { return FALSE; } $lastStackElement = $state->popNodeFromStack(); if (!$lastStackElement instanceof ViewHelperNode) { throw new Exception('You closed a templating tag which you never opened!', 1224485838); } $actualViewHelperClassName = $viewHelperResolver->resolveViewHelperClassName($namespaceIdentifier, $methodIdentifier); $expectedViewHelperClassName = $lastStackElement->getViewHelperClassName(); if ($actualViewHelperClassName !== $expectedViewHelperClassName) { throw new Exception('Templating tags not properly nested. Expected: ' . $expectedViewHelperClassName . '; Actual: ' . $actualViewHelperClassName, 1224485398); } $this->callInterceptor($lastStackElement, InterceptorInterface::INTERCEPT_CLOSING_VIEWHELPER, $state); $state->getNodeFromStack()->addChildNode($lastStackElement); return TRUE; }
/** * @param string $identifier * @param ParsingState $parsingState * @return void */ public function store($identifier, ParsingState $parsingState) { if ($this->isDisabled()) { if ($this->renderingContext->isCacheEnabled()) { // Compiler is disabled but cache is enabled. Flush cache to make sure. $this->renderingContext->getCache()->flush($identifier); } $parsingState->setCompilable(FALSE); return; } $identifier = $this->sanitizeIdentifier($identifier); $this->nodeConverter->setVariableCounter(0); $generatedRenderFunctions = $this->generateSectionCodeFromParsingState($parsingState); $generatedRenderFunctions .= $this->generateCodeForSection($this->nodeConverter->convertListOfSubNodes($parsingState->getRootNode()), 'render', 'Main Render function'); $classDefinition = 'class ' . $identifier . ' extends \\TYPO3Fluid\\Fluid\\Core\\Compiler\\AbstractCompiledTemplate'; $templateCode = <<<EOD <?php %s { public function getLayoutName(\\TYPO3Fluid\\Fluid\\Core\\Rendering\\RenderingContextInterface \$renderingContext) { \$layout = %s; if (!\$layout) { \$layout = '%s'; } return \$layout; } public function hasLayout() { return %s; } public function addCompiledNamespaces(\\TYPO3Fluid\\Fluid\\Core\\Rendering\\RenderingContextInterface \$renderingContext) { \$renderingContext->getViewHelperResolver()->addNamespaces(%s); } %s } EOD; $templateCode = sprintf($templateCode, $classDefinition, '$renderingContext->getVariableProvider()->get(\'layoutName\')', $parsingState->getVariableContainer()->get('layoutName'), $parsingState->hasLayout() ? 'TRUE' : 'FALSE', var_export($this->renderingContext->getViewHelperResolver()->getNamespaces(), TRUE), $generatedRenderFunctions); $this->renderingContext->getCache()->set($identifier, $templateCode); }
/** * @param RenderingContextInterface $renderingContext * @param string $expression * @param array $matches * @return mixed */ public static function evaluateExpression(RenderingContextInterface $renderingContext, $expression, array $matches) { $renderingContext->getViewHelperResolver()->addNamespace($matches[1], $matches[2]); }
/** * Public such that it is callable from within closures * * @param integer $uniqueCounter * @param RenderingContextInterface $renderingContext * @param string $viewHelperName * @return AbstractViewHelper */ public function getViewHelper($uniqueCounter, RenderingContextInterface $renderingContext, $viewHelperName) { return $renderingContext->getViewHelperResolver()->createViewHelperInstanceFromClassName($viewHelperName); }
/** * Gets the ViewHelperResolver instance from RenderingContext * * @return ViewHelperResolver */ public function getViewHelperResolver() { return $this->baseRenderingContext->getViewHelperResolver(); }