1
|
|
|
<?php |
2
|
|
|
namespace TYPO3Fluid\Fluid\Core\Parser\Interceptor; |
3
|
|
|
|
4
|
|
|
/* |
5
|
|
|
* This file belongs to the package "TYPO3 Fluid". |
6
|
|
|
* See LICENSE.txt that was shipped with this package. |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
use TYPO3Fluid\Fluid\Core\Parser\InterceptorInterface; |
10
|
|
|
use TYPO3Fluid\Fluid\Core\Parser\ParsingState; |
11
|
|
|
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\EscapingNode; |
12
|
|
|
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\Expression\ExpressionNodeInterface; |
13
|
|
|
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\NodeInterface; |
14
|
|
|
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ObjectAccessorNode; |
15
|
|
|
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* An interceptor adding the "Htmlspecialchars" viewhelper to the suitable places. |
19
|
|
|
*/ |
20
|
|
|
class Escape implements InterceptorInterface |
21
|
|
|
{ |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* Is the interceptor enabled right now for child nodes? |
25
|
|
|
* |
26
|
|
|
* @var boolean |
27
|
|
|
*/ |
28
|
|
|
protected $childrenEscapingEnabled = true; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* A stack of ViewHelperNodes which currently disable the interceptor. |
32
|
|
|
* Needed to enable the interceptor again. |
33
|
|
|
* |
34
|
|
|
* @var NodeInterface[] |
35
|
|
|
*/ |
36
|
|
|
protected $viewHelperNodesWhichDisableTheInterceptor = []; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Adds a ViewHelper node using the Format\HtmlspecialcharsViewHelper to the given node. |
40
|
|
|
* If "escapingInterceptorEnabled" in the ViewHelper is FALSE, will disable itself inside the ViewHelpers body. |
41
|
|
|
* |
42
|
|
|
* @param NodeInterface $node |
43
|
|
|
* @param integer $interceptorPosition One of the INTERCEPT_* constants for the current interception point |
44
|
|
|
* @param ParsingState $parsingState the current parsing state. Not needed in this interceptor. |
45
|
|
|
* @return NodeInterface |
46
|
|
|
*/ |
47
|
|
|
public function process(NodeInterface $node, $interceptorPosition, ParsingState $parsingState) |
48
|
|
|
{ |
49
|
|
|
$viewHelper = $node instanceof ViewHelperNode ? $node->getUninitializedViewHelper() : $node; |
50
|
|
|
if ($interceptorPosition === InterceptorInterface::INTERCEPT_OPENING_VIEWHELPER) { |
51
|
|
|
/** @var ViewHelperNode $node */ |
52
|
|
|
if (!$viewHelper->isChildrenEscapingEnabled()) { |
|
|
|
|
53
|
|
|
$this->childrenEscapingEnabled = false; |
54
|
|
|
$this->viewHelperNodesWhichDisableTheInterceptor[] = $node; |
55
|
|
|
} |
56
|
|
|
} elseif ($interceptorPosition === InterceptorInterface::INTERCEPT_CLOSING_VIEWHELPER) { |
57
|
|
|
if (end($this->viewHelperNodesWhichDisableTheInterceptor) === $node) { |
58
|
|
|
array_pop($this->viewHelperNodesWhichDisableTheInterceptor); |
59
|
|
|
if (count($this->viewHelperNodesWhichDisableTheInterceptor) === 0) { |
60
|
|
|
$this->childrenEscapingEnabled = true; |
61
|
|
|
} |
62
|
|
|
} |
63
|
|
|
/** @var ViewHelperNode $node */ |
64
|
|
|
if ($this->childrenEscapingEnabled && $viewHelper->isOutputEscapingEnabled()) { |
|
|
|
|
65
|
|
|
$node = new EscapingNode($node); |
66
|
|
|
} |
67
|
|
|
} elseif ($this->childrenEscapingEnabled && ($node instanceof ObjectAccessorNode || $node instanceof ExpressionNodeInterface)) { |
68
|
|
|
$node = new EscapingNode($node); |
69
|
|
|
} |
70
|
|
|
return $node; |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* This interceptor wants to hook into object accessor creation, and opening / closing ViewHelpers. |
75
|
|
|
* |
76
|
|
|
* @return array Array of INTERCEPT_* constants |
77
|
|
|
*/ |
78
|
|
|
public function getInterceptionPoints() |
79
|
|
|
{ |
80
|
|
|
return [ |
81
|
|
|
InterceptorInterface::INTERCEPT_OPENING_VIEWHELPER, |
82
|
|
|
InterceptorInterface::INTERCEPT_CLOSING_VIEWHELPER, |
83
|
|
|
InterceptorInterface::INTERCEPT_OBJECTACCESSOR, |
84
|
|
|
InterceptorInterface::INTERCEPT_EXPRESSION, |
85
|
|
|
]; |
86
|
|
|
} |
87
|
|
|
} |
88
|
|
|
|
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the interface: