TYPO3  7.6
AbstractViewHelper.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Fluid\Core\ViewHelper;
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 = array();
37 
47  private static $argumentDefinitionCache = array();
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 
109  protected $objectManager;
110 
116  protected $escapingInterceptorEnabled = true;
117 
122  public function setArguments(array $arguments)
123  {
124  $this->arguments = $arguments;
125  }
126 
131  public function setRenderingContext(\TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface $renderingContext)
132  {
133  $this->renderingContext = $renderingContext;
134  $this->templateVariableContainer = $renderingContext->getTemplateVariableContainer();
135  if ($renderingContext->getControllerContext() !== null) {
136  $this->controllerContext = $renderingContext->getControllerContext();
137  }
138  $this->viewHelperVariableContainer = $renderingContext->getViewHelperVariableContainer();
139  }
140 
146  public function injectReflectionService(\TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService)
147  {
148  $this->reflectionService = $reflectionService;
149  }
150 
159  {
161  }
162 
176  protected function registerArgument($name, $type, $description, $required = false, $defaultValue = null)
177  {
178  if (array_key_exists($name, $this->argumentDefinitions)) {
179  throw new \TYPO3\CMS\Fluid\Core\ViewHelper\Exception('Argument "' . $name . '" has already been defined, thus it should not be defined again.', 1253036401);
180  }
181  $this->argumentDefinitions[$name] = new \TYPO3\CMS\Fluid\Core\ViewHelper\ArgumentDefinition($name, $type, $description, $required, $defaultValue);
182  return $this;
183  }
184 
199  protected function overrideArgument($name, $type, $description, $required = false, $defaultValue = null)
200  {
201  if (!array_key_exists($name, $this->argumentDefinitions)) {
202  throw new \TYPO3\CMS\Fluid\Core\ViewHelper\Exception('Argument "' . $name . '" has not been defined, thus it can\'t be overridden.', 1279212461);
203  }
204  $this->argumentDefinitions[$name] = new \TYPO3\CMS\Fluid\Core\ViewHelper\ArgumentDefinition($name, $type, $description, $required, $defaultValue);
205  return $this;
206  }
207 
216  public function setViewHelperNode(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ViewHelperNode $node)
217  {
218  $this->viewHelperNode = $node;
219  }
220 
228  {
229  $this->renderChildrenClosure = $renderChildrenClosure;
230  }
231 
238  {
239  $this->validateArguments();
240  $this->initialize();
241 
242  return $this->callRenderMethod();
243  }
244 
251  protected function callRenderMethod()
252  {
253  $renderMethodParameters = array();
254  foreach ($this->argumentDefinitions as $argumentName => $argumentDefinition) {
255  if ($argumentDefinition->isMethodParameter()) {
256  $renderMethodParameters[$argumentName] = $this->arguments[$argumentName];
257  }
258  }
259 
260  try {
261  return call_user_func_array(array($this, 'render'), $renderMethodParameters);
262  } catch (Exception $exception) {
263  if (GeneralUtility::getApplicationContext()->isProduction()) {
264  $this->getLogger()->error('A Fluid ViewHelper Exception was captured: ' . $exception->getMessage() . ' (' . $exception->getCode() . ')', array('exception' => $exception));
265  return '';
266  } else {
267  throw $exception;
268  }
269  }
270  }
271 
275  protected function getLogger()
276  {
277  return GeneralUtility::makeInstance(LogManager::class)->getLogger(__CLASS__);
278  }
279 
288  public function initialize()
289  {
290  }
291 
299  public function renderChildren()
300  {
301  if ($this->renderChildrenClosure !== null) {
302  $closure = $this->renderChildrenClosure;
303  return $closure();
304  }
305  return $this->viewHelperNode->evaluateChildNodes($this->renderingContext);
306  }
307 
316  protected function buildRenderChildrenClosure()
317  {
318  $self = $this;
319  return function () use ($self) {
320  return $self->renderChildren();
321  };
322  }
323 
329  public function prepareArguments()
330  {
331  if (!$this->argumentsInitialized) {
332  $thisClassName = get_class($this);
333  if (isset(self::$argumentDefinitionCache[$thisClassName])) {
334  $this->argumentDefinitions = self::$argumentDefinitionCache[$thisClassName];
335  } else {
337  $this->initializeArguments();
338  self::$argumentDefinitionCache[$thisClassName] = $this->argumentDefinitions;
339  }
340  $this->argumentsInitialized = true;
341  }
343  }
344 
351  private function registerRenderMethodArguments()
352  {
353  $methodParameters = $this->reflectionService->getMethodParameters(get_class($this), 'render');
354  if (count($methodParameters) === 0) {
355  return;
356  }
357 
358  if (\TYPO3\CMS\Fluid\Fluid::$debugMode) {
359  $methodTags = $this->reflectionService->getMethodTagsValues(get_class($this), 'render');
360 
361  $paramAnnotations = array();
362  if (isset($methodTags['param'])) {
363  $paramAnnotations = $methodTags['param'];
364  }
365  }
366 
367  $i = 0;
368  foreach ($methodParameters as $parameterName => $parameterInfo) {
369  $dataType = null;
370  if (isset($parameterInfo['type'])) {
371  $dataType = $parameterInfo['type'];
372  } elseif ($parameterInfo['array']) {
373  $dataType = 'array';
374  }
375  if ($dataType === null) {
376  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);
377  }
378 
379  $description = '';
380  if (\TYPO3\CMS\Fluid\Fluid::$debugMode && isset($paramAnnotations[$i])) {
381  $explodedAnnotation = explode(' ', $paramAnnotations[$i]);
382  array_shift($explodedAnnotation);
383  array_shift($explodedAnnotation);
384  $description = implode(' ', $explodedAnnotation);
385  }
386  $defaultValue = null;
387  if (isset($parameterInfo['defaultValue'])) {
388  $defaultValue = $parameterInfo['defaultValue'];
389  }
390  $this->argumentDefinitions[$parameterName] = new \TYPO3\CMS\Fluid\Core\ViewHelper\ArgumentDefinition($parameterName, $dataType, $description, ($parameterInfo['optional'] === false), $defaultValue, true);
391  $i++;
392  }
393  }
394 
401  public function validateArguments()
402  {
404  if (!count($argumentDefinitions)) {
405  return;
406  }
407  foreach ($argumentDefinitions as $argumentName => $registeredArgument) {
408  if ($this->hasArgument($argumentName)) {
409  if ($this->arguments[$argumentName] === $registeredArgument->getDefaultValue()) {
410  continue;
411  }
412 
413  $type = $registeredArgument->getType();
414  if ($type === 'array') {
415  if (!is_array($this->arguments[$argumentName]) && !$this->arguments[$argumentName] instanceof \ArrayAccess && !$this->arguments[$argumentName] instanceof \Traversable) {
416  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);
417  }
418  } elseif ($type === 'boolean') {
419  if (!is_bool($this->arguments[$argumentName])) {
420  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);
421  }
422  } elseif (class_exists($type, false)) {
423  if (!($this->arguments[$argumentName] instanceof $type)) {
424  if (is_object($this->arguments[$argumentName])) {
425  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);
426  } else {
427  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);
428  }
429  }
430  }
431  }
432  }
433  }
434 
442  public function initializeArguments()
443  {
444  }
445 
455  //abstract public function render();
456 
464  protected function hasArgument($argumentName)
465  {
466  return isset($this->arguments[$argumentName]) && $this->arguments[$argumentName] !== null;
467  }
468 
485  public function compile($argumentsVariableName, $renderChildrenClosureVariableName, &$initializationPhpCode, \TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\AbstractNode $syntaxTreeNode, \TYPO3\CMS\Fluid\Core\Compiler\TemplateCompiler $templateCompiler)
486  {
487  return sprintf('%s::renderStatic(%s, %s, $renderingContext)',
488  get_class($this), $argumentsVariableName, $renderChildrenClosureVariableName);
489  }
490 
501  public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, \TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface $renderingContext)
502  {
503  return null;
504  }
505 
513  public function resetState()
514  {
515  }
516 }