Skip to content

Commit 2d2d5db

Browse files
NamelessCodermbrodala
authored andcommitted
[TASK] Refactor and and guard namespace extraction (#451)
Refactors the namespace validation from occurring in the TemplateProcessor, to occur instead when parsing the template. Behavior remains unchanged. Also guards several potentially empty matches of namespaces from being iterated over, causing fatal PHP errors.
1 parent 865890c commit 2d2d5db

File tree

3 files changed

+71
-62
lines changed

3 files changed

+71
-62
lines changed

src/Core/Parser/TemplateParser.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,9 +355,12 @@ protected function openingViewHelperTagHandler(ParsingState $state, $namespaceId
355355
protected function initializeViewHelperAndAddItToStack(ParsingState $state, $namespaceIdentifier, $methodIdentifier, $argumentsObjectTree)
356356
{
357357
$viewHelperResolver = $this->renderingContext->getViewHelperResolver();
358-
if (!$viewHelperResolver->isNamespaceValid($namespaceIdentifier)) {
358+
if ($viewHelperResolver->isNamespaceIgnored($namespaceIdentifier)) {
359359
return null;
360360
}
361+
if (!$viewHelperResolver->isNamespaceValid($namespaceIdentifier)) {
362+
throw new UnknownNamespaceException('Unknown Namespace: ' . $namespaceIdentifier);
363+
}
361364
try {
362365
$currentViewHelperNode = new ViewHelperNode(
363366
$this->renderingContext,
@@ -398,9 +401,12 @@ protected function initializeViewHelperAndAddItToStack(ParsingState $state, $nam
398401
protected function closingViewHelperTagHandler(ParsingState $state, $namespaceIdentifier, $methodIdentifier)
399402
{
400403
$viewHelperResolver = $this->renderingContext->getViewHelperResolver();
401-
if (!$viewHelperResolver->isNamespaceValid($namespaceIdentifier)) {
404+
if ($viewHelperResolver->isNamespaceIgnored($namespaceIdentifier)) {
402405
return false;
403406
}
407+
if (!$viewHelperResolver->isNamespaceValid($namespaceIdentifier)) {
408+
throw new UnknownNamespaceException('Unknown Namespace: ' . $namespaceIdentifier);
409+
}
404410
$lastStackElement = $state->popNodeFromStack();
405411
if (!($lastStackElement instanceof ViewHelperNode)) {
406412
throw new Exception('You closed a templating tag which you never opened!', 1224485838);

src/Core/Parser/TemplateProcessor/NamespaceDetectionTemplateProcessor.php

Lines changed: 20 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ public function preProcessSource($templateSource)
5555
{
5656
$templateSource = $this->replaceCdataSectionsByEmptyLines($templateSource);
5757
$templateSource = $this->registerNamespacesFromTemplateSource($templateSource);
58-
$this->throwExceptionsForUnhandledNamespaces($templateSource);
5958
return $templateSource;
6059
}
6160

@@ -125,70 +124,35 @@ public function registerNamespacesFromTemplateSource($templateSource)
125124
substr($templateSource, strrpos($templateSource, $closingTag) + strlen($closingTag));
126125
}
127126
} else {
128-
if (!empty($namespaces)) {
129-
$namespaceAttributesToRemove = [];
130-
foreach ($namespaces as $namespace) {
131-
if (!$viewHelperResolver->isNamespaceIgnored($namespace[1])) {
132-
$namespaceAttributesToRemove[] = preg_quote($namespace[1], '/') . '="' . preg_quote($namespace[2], '/') . '"';
133-
}
134-
}
135-
if (count($namespaceAttributesToRemove)) {
136-
$matchWithRemovedNamespaceAttributes = preg_replace('/(?:\\s*+xmlns:(?:' . implode('|', $namespaceAttributesToRemove) . ')\\s*+)++/', ' ', $matches[0]);
137-
$templateSource = str_replace($matches[0], $matchWithRemovedNamespaceAttributes, $templateSource);
127+
$namespaceAttributesToRemove = [];
128+
foreach ($namespaces as $namespace) {
129+
if (!$viewHelperResolver->isNamespaceIgnored($namespace[1])) {
130+
$namespaceAttributesToRemove[] = preg_quote($namespace[1], '/') . '="' . preg_quote($namespace[2], '/') . '"';
138131
}
139132
}
133+
if (count($namespaceAttributesToRemove)) {
134+
$matchWithRemovedNamespaceAttributes = preg_replace('/(?:\\s*+xmlns:(?:' . implode('|', $namespaceAttributesToRemove) . ')\\s*+)++/', ' ', $matches[0]);
135+
$templateSource = str_replace($matches[0], $matchWithRemovedNamespaceAttributes, $templateSource);
136+
}
140137
}
141138
}
142139

143140
preg_match_all(static::NAMESPACE_DECLARATION, $templateSource, $namespaces);
144-
foreach ($namespaces['identifier'] as $key => $identifier) {
145-
$namespace = $namespaces['phpNamespace'][$key];
146-
if (strlen($namespace) === 0) {
147-
$namespace = null;
148-
}
149-
$viewHelperResolver->addNamespace($identifier, $namespace);
150-
}
151-
foreach ($namespaces[0] as $removal) {
152-
$templateSource = str_replace($removal, '', $templateSource);
153-
}
154-
155-
return $templateSource;
156-
}
157-
158-
/**
159-
* Throw an UnknownNamespaceException for any unknown and not ignored
160-
* namespace inside the template string
161-
*
162-
* @param string $templateSource
163-
* @return void
164-
*/
165-
public function throwExceptionsForUnhandledNamespaces($templateSource)
166-
{
167-
$viewHelperResolver = $this->renderingContext->getViewHelperResolver();
168-
$splitTemplate = preg_split(Patterns::$SPLIT_PATTERN_TEMPLATE_DYNAMICTAGS, $templateSource, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
169-
foreach ($splitTemplate as $templateElement) {
170-
if (preg_match(Patterns::$SCAN_PATTERN_TEMPLATE_VIEWHELPERTAG, $templateElement, $matchedVariables) > 0) {
171-
if (!$viewHelperResolver->isNamespaceValidOrIgnored($matchedVariables['NamespaceIdentifier'])) {
172-
throw new UnknownNamespaceException('Unknown Namespace: ' . htmlspecialchars($matchedVariables[0]));
141+
if (!empty($namespaces['identifier'])) {
142+
// There are no namespace declarations using curly-brace syntax.
143+
foreach ($namespaces['identifier'] as $key => $identifier) {
144+
$namespace = $namespaces['phpNamespace'][$key];
145+
if (strlen($namespace) === 0) {
146+
$namespace = null;
173147
}
174-
continue;
175-
} elseif (preg_match(Patterns::$SCAN_PATTERN_TEMPLATE_CLOSINGVIEWHELPERTAG, $templateElement, $matchedVariables) > 0) {
176-
continue;
148+
$viewHelperResolver->addNamespace($identifier, $namespace);
177149
}
178-
179-
$sections = preg_split(Patterns::$SPLIT_PATTERN_SHORTHANDSYNTAX, $templateElement, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
180-
foreach ($sections as $section) {
181-
if (preg_match(Patterns::$SCAN_PATTERN_SHORTHANDSYNTAX_OBJECTACCESSORS, $section, $matchedVariables) > 0) {
182-
preg_match_all(Patterns::$SPLIT_PATTERN_SHORTHANDSYNTAX_VIEWHELPER, $section, $shorthandViewHelpers, PREG_SET_ORDER);
183-
if (is_array($shorthandViewHelpers) === true) {
184-
foreach ($shorthandViewHelpers as $shorthandViewHelper) {
185-
if (!$viewHelperResolver->isNamespaceValidOrIgnored($shorthandViewHelper['NamespaceIdentifier'])) {
186-
throw new UnknownNamespaceException('Unknown Namespace: ' . $shorthandViewHelper['NamespaceIdentifier']);
187-
}
188-
}
189-
}
190-
}
150+
foreach ($namespaces[0] as $removal) {
151+
$templateSource = str_replace($removal, '', $templateSource);
191152
}
153+
192154
}
155+
156+
return $templateSource;
193157
}
194158
}

tests/Unit/Core/Parser/TemplateParserTest.php

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode;
2121
use TYPO3Fluid\Fluid\Core\Parser\TemplateParser;
2222
use TYPO3Fluid\Fluid\Core\Parser\TemplateProcessorInterface;
23+
use TYPO3Fluid\Fluid\Core\Parser\UnknownNamespaceException;
2324
use TYPO3Fluid\Fluid\Core\Variables\StandardVariableProvider;
2425
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
2526
use TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperResolver;
@@ -39,9 +40,28 @@ class TemplateParserTest extends UnitTestCase
3940
/**
4041
* @test
4142
*/
42-
public function testInitializeViewHelperAndAddItToStackReturnsFalseIfNamespaceNotValid()
43+
public function testInitializeViewHelperAndAddItToStackReturnsFalseIfNamespaceIgnored()
4344
{
44-
$resolver = $this->getMock(ViewHelperResolver::class, ['isNamespaceValid']);
45+
$resolver = $this->getMock(ViewHelperResolver::class, ['isNamespaceIgnored']);
46+
$resolver->expects($this->once())->method('isNamespaceIgnored')->willReturn(true);
47+
$context = new RenderingContextFixture();
48+
$context->setViewHelperResolver($resolver);
49+
$templateParser = new TemplateParser();
50+
$templateParser->setRenderingContext($context);
51+
$method = new \ReflectionMethod($templateParser, 'initializeViewHelperAndAddItToStack');
52+
$method->setAccessible(true);
53+
$result = $method->invokeArgs($templateParser, [new ParsingState(), 'f', 'render', []]);
54+
$this->assertNull($result);
55+
}
56+
57+
/**
58+
* @test
59+
*/
60+
public function testInitializeViewHelperAndAddItToStackThrowsExceptionIfNamespaceInvalid()
61+
{
62+
$this->setExpectedException(UnknownNamespaceException::class);
63+
$resolver = $this->getMock(ViewHelperResolver::class, ['isNamespaceIgnored', 'isNamespaceValid']);
64+
$resolver->expects($this->once())->method('isNamespaceIgnored')->willReturn(false);
4565
$resolver->expects($this->once())->method('isNamespaceValid')->willReturn(false);
4666
$context = new RenderingContextFixture();
4767
$context->setViewHelperResolver($resolver);
@@ -56,9 +76,28 @@ public function testInitializeViewHelperAndAddItToStackReturnsFalseIfNamespaceNo
5676
/**
5777
* @test
5878
*/
59-
public function testClosingViewHelperTagHandlerReturnsFalseIfNamespaceNotValid()
79+
public function testClosingViewHelperTagHandlerReturnsFalseIfNamespaceIgnored()
80+
{
81+
$resolver = $this->getMock(ViewHelperResolver::class, ['isNamespaceIgnored']);
82+
$resolver->expects($this->once())->method('isNamespaceIgnored')->willReturn(true);
83+
$context = new RenderingContextFixture();
84+
$context->setViewHelperResolver($resolver);
85+
$templateParser = new TemplateParser();
86+
$templateParser->setRenderingContext($context);
87+
$method = new \ReflectionMethod($templateParser, 'closingViewHelperTagHandler');
88+
$method->setAccessible(true);
89+
$result = $method->invokeArgs($templateParser, [new ParsingState(), 'f', 'render']);
90+
$this->assertFalse($result);
91+
}
92+
93+
/**
94+
* @test
95+
*/
96+
public function testClosingViewHelperTagHandlerThrowsExceptionIfNamespaceInvalid()
6097
{
61-
$resolver = $this->getMock(ViewHelperResolver::class, ['isNamespaceValid']);
98+
$this->setExpectedException(UnknownNamespaceException::class);
99+
$resolver = $this->getMock(ViewHelperResolver::class, ['isNamespaceValid', 'isNamespaceIgnored']);
100+
$resolver->expects($this->once())->method('isNamespaceIgnored')->willReturn(false);
62101
$resolver->expects($this->once())->method('isNamespaceValid')->willReturn(false);
63102
$context = new RenderingContextFixture();
64103
$context->setViewHelperResolver($resolver);

0 commit comments

Comments
 (0)