TYPO3 CMS  TYPO3_7-6
AbstractViewHelper.php
Go to the documentation of this file.
1 <?php
3 
4 /* *
5  * This script is backported from the TYPO3 Flow package "TYPO3.Fluid". *
6  * *
7  * It is free software; you can redistribute it and/or modify it under *
8  * the terms of the GNU Lesser General Public License, either version 3 *
9  * of the License, or (at your option) any later version. *
10  * *
11  * The TYPO3 project - inspiring people to share! *
12  * */
16 
22 abstract class AbstractViewHelper
23 {
29  private $argumentsInitialized = false;
30 
36  private $argumentDefinitions = [];
37 
47  private static $argumentDefinitionCache = [];
48 
54  private $viewHelperNode;
55 
62  protected $arguments;
63 
71 
78  protected $controllerContext;
79 
83  protected $renderingContext;
84 
88  protected $renderChildrenClosure = null;
89 
97 
104 
108  protected $objectManager;
109 
115  protected $escapingInterceptorEnabled = true;
116 
121  public function setArguments(array $arguments)
122  {
123  $this->arguments = $arguments;
124  }
125 
130  public function setRenderingContext(\TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface $renderingContext)
131  {
132  $this->renderingContext = $renderingContext;
133  $this->templateVariableContainer = $renderingContext->getTemplateVariableContainer();
134  if ($renderingContext->getControllerContext() !== null) {
135  $this->controllerContext = $renderingContext->getControllerContext();
136  }
137  $this->viewHelperVariableContainer = $renderingContext->getViewHelperVariableContainer();
138  }
139 
143  public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
144  {
145  $this->objectManager = $objectManager;
146  }
147 
153  public function injectReflectionService(\TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService)
154  {
155  $this->reflectionService = $reflectionService;
156  }
157 
166  {
168  }
169 
183  protected function registerArgument($name, $type, $description, $required = false, $defaultValue = null)
184  {
185  if (array_key_exists($name, $this->argumentDefinitions)) {
186  throw new \TYPO3\CMS\Fluid\Core\ViewHelper\Exception('Argument "' . $name . '" has already been defined, thus it should not be defined again.', 1253036401);
187  }
188  $this->argumentDefinitions[$name] = new \TYPO3\CMS\Fluid\Core\ViewHelper\ArgumentDefinition($name, $type, $description, $required, $defaultValue);
189  return $this;
190  }
191 
206  protected function overrideArgument($name, $type, $description, $required = false, $defaultValue = null)
207  {
208  if (!array_key_exists($name, $this->argumentDefinitions)) {
209  throw new \TYPO3\CMS\Fluid\Core\ViewHelper\Exception('Argument "' . $name . '" has not been defined, thus it can\'t be overridden.', 1279212461);
210  }
211  $this->argumentDefinitions[$name] = new \TYPO3\CMS\Fluid\Core\ViewHelper\ArgumentDefinition($name, $type, $description, $required, $defaultValue);
212  return $this;
213  }
214 
223  public function setViewHelperNode(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ViewHelperNode $node)
224  {
225  $this->viewHelperNode = $node;
226  }
227 
235  {
236  $this->renderChildrenClosure = $renderChildrenClosure;
237  }
238 
245  {
246  $this->validateArguments();
247  $this->initialize();
248 
249  return $this->callRenderMethod();
250  }
251 
258  protected function callRenderMethod()
259  {
260  $renderMethodParameters = [];
261  foreach ($this->argumentDefinitions as $argumentName => $argumentDefinition) {
262  if ($argumentDefinition->isMethodParameter()) {
263  $renderMethodParameters[$argumentName] = $this->arguments[$argumentName];
264  }
265  }
266 
267  try {
268  return call_user_func_array([$this, 'render'], $renderMethodParameters);
269  } catch (Exception $exception) {
270  if (GeneralUtility::getApplicationContext()->isProduction()) {
271  $this->getLogger()->error('A Fluid ViewHelper Exception was captured: ' . $exception->getMessage() . ' (' . $exception->getCode() . ')', ['exception' => $exception]);
272  return '';
273  } else {
274  throw $exception;
275  }
276  }
277  }
278 
282  protected function getLogger()
283  {
284  return GeneralUtility::makeInstance(LogManager::class)->getLogger(__CLASS__);
285  }
286 
295  public function initialize()
296  {
297  }
298 
306  public function renderChildren()
307  {
308  if ($this->renderChildrenClosure !== null) {
309  $closure = $this->renderChildrenClosure;
310  return $closure();
311  }
312  return $this->viewHelperNode->evaluateChildNodes($this->renderingContext);
313  }
314 
323  protected function buildRenderChildrenClosure()
324  {
325  $self = $this;
326  return function () use ($self) {
327  return $self->renderChildren();
328  };
329  }
330 
336  public function prepareArguments()
337  {
338  if (!$this->argumentsInitialized) {
339  $thisClassName = get_class($this);
340  if (isset(self::$argumentDefinitionCache[$thisClassName])) {
341  $this->argumentDefinitions = self::$argumentDefinitionCache[$thisClassName];
342  } else {
344  $this->initializeArguments();
345  self::$argumentDefinitionCache[$thisClassName] = $this->argumentDefinitions;
346  }
347  $this->argumentsInitialized = true;
348  }
350  }
351 
358  private function registerRenderMethodArguments()
359  {
360  $methodParameters = $this->reflectionService->getMethodParameters(get_class($this), 'render');
361  if (count($methodParameters) === 0) {
362  return;
363  }
364 
365  if (\TYPO3\CMS\Fluid\Fluid::$debugMode) {
366  $methodTags = $this->reflectionService->getMethodTagsValues(get_class($this), 'render');
367 
368  $paramAnnotations = [];
369  if (isset($methodTags['param'])) {
370  $paramAnnotations = $methodTags['param'];
371  }
372  }
373 
374  $i = 0;
375  foreach ($methodParameters as $parameterName => $parameterInfo) {
376  $dataType = null;
377  if (isset($parameterInfo['type'])) {
378  $dataType = $parameterInfo['type'];
379  } elseif ($parameterInfo['array']) {
380  $dataType = 'array';
381  }
382  if ($dataType === null) {
383  throw new \TYPO3\CMS\Fluid\Core\Parser\Exception('could not determine type of argument "' . $parameterName . '" of the render-method in ViewHelper "' . get_class($this) . '". Either the methods docComment is invalid or some PHP optimizer strips off comments.', 1242292003);
384  }
385 
386  $description = '';
387  if (\TYPO3\CMS\Fluid\Fluid::$debugMode && isset($paramAnnotations[$i])) {
388  $explodedAnnotation = explode(' ', $paramAnnotations[$i]);
389  array_shift($explodedAnnotation);
390  array_shift($explodedAnnotation);
391  $description = implode(' ', $explodedAnnotation);
392  }
393  $defaultValue = null;
394  if (isset($parameterInfo['defaultValue'])) {
395  $defaultValue = $parameterInfo['defaultValue'];
396  }
397  $this->argumentDefinitions[$parameterName] = new \TYPO3\CMS\Fluid\Core\ViewHelper\ArgumentDefinition($parameterName, $dataType, $description, ($parameterInfo['optional'] === false), $defaultValue, true);
398  $i++;
399  }
400  }
401 
408  public function validateArguments()
409  {
411  if (!count($argumentDefinitions)) {
412  return;
413  }
414  foreach ($argumentDefinitions as $argumentName => $registeredArgument) {
415  if ($this->hasArgument($argumentName)) {
416  if ($this->arguments[$argumentName] === $registeredArgument->getDefaultValue()) {
417  continue;
418  }
419 
420  $type = $registeredArgument->getType();
421  if ($type === 'array') {
422  if (!is_array($this->arguments[$argumentName]) && !$this->arguments[$argumentName] instanceof \ArrayAccess && !$this->arguments[$argumentName] instanceof \Traversable) {
423  throw new \InvalidArgumentException('The argument "' . $argumentName . '" was registered with type "array", but is of type "' . gettype($this->arguments[$argumentName]) . '" in view helper "' . get_class($this) . '"', 1237900529);
424  }
425  } elseif ($type === 'boolean') {
426  if (!is_bool($this->arguments[$argumentName])) {
427  throw new \InvalidArgumentException('The argument "' . $argumentName . '" was registered with type "boolean", but is of type "' . gettype($this->arguments[$argumentName]) . '" in view helper "' . get_class($this) . '".', 1240227732);
428  }
429  } elseif (class_exists($type, false)) {
430  if (!($this->arguments[$argumentName] instanceof $type)) {
431  if (is_object($this->arguments[$argumentName])) {
432  throw new \InvalidArgumentException('The argument "' . $argumentName . '" was registered with type "' . $type . '", but is of type "' . get_class($this->arguments[$argumentName]) . '" in view helper "' . get_class($this) . '".', 1256475114);
433  } else {
434  throw new \InvalidArgumentException('The argument "' . $argumentName . '" was registered with type "' . $type . '", but is of type "' . gettype($this->arguments[$argumentName]) . '" in view helper "' . get_class($this) . '".', 1256475113);
435  }
436  }
437  }
438  }
439  }
440  }
441 
449  public function initializeArguments()
450  {
451  }
452 
462  //abstract public function render();
463 
471  protected function hasArgument($argumentName)
472  {
473  return isset($this->arguments[$argumentName]) && $this->arguments[$argumentName] !== null;
474  }
475 
492  public function compile($argumentsVariableName, $renderChildrenClosureVariableName, &$initializationPhpCode, \TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\AbstractNode $syntaxTreeNode, \TYPO3\CMS\Fluid\Core\Compiler\TemplateCompiler $templateCompiler)
493  {
494  return sprintf('%s::renderStatic(%s, %s, $renderingContext)',
495  get_class($this), $argumentsVariableName, $renderChildrenClosureVariableName);
496  }
497 
508  public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, \TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface $renderingContext)
509  {
510  return null;
511  }
512 
520  public function resetState()
521  {
522  }
523 }
registerArgument($name, $type, $description, $required=false, $defaultValue=null)
injectReflectionService(\TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService)
overrideArgument($name, $type, $description, $required=false, $defaultValue=null)
setViewHelperNode(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ViewHelperNode $node)
setRenderingContext(\TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface $renderingContext)
injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
setRenderChildrenClosure(\Closure $renderChildrenClosure)
compile($argumentsVariableName, $renderChildrenClosureVariableName, &$initializationPhpCode, \TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\AbstractNode $syntaxTreeNode, \TYPO3\CMS\Fluid\Core\Compiler\TemplateCompiler $templateCompiler)
static renderStatic(array $arguments, \Closure $renderChildrenClosure, \TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface $renderingContext)