Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Support Vendor.Package as namespace name #329

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 40 additions & 17 deletions src/Core/ViewHelper/ViewHelperResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ public function setNamespaces(array $namespaces)
*/
public function isNamespaceValid($namespaceIdentifier)
{
if (strpos($namespaceIdentifier, '.')) {
return true;
}

if (!array_key_exists($namespaceIdentifier, $this->namespaces)) {
return false;
}
Expand Down Expand Up @@ -245,18 +249,8 @@ public function isNamespaceIgnored($namespaceIdentifier)
public function resolveViewHelperClassName($namespaceIdentifier, $methodIdentifier)
{
if (!isset($this->resolvedViewHelperClassNames[$namespaceIdentifier][$methodIdentifier])) {
$resolvedViewHelperClassName = $this->resolveViewHelperName($namespaceIdentifier, $methodIdentifier);
$actualViewHelperClassName = implode('\\', array_map('ucfirst', explode('.', $resolvedViewHelperClassName)));
if (false === class_exists($actualViewHelperClassName) || $actualViewHelperClassName === false) {
throw new ParserException(sprintf(
'The ViewHelper "<%s:%s>" could not be resolved.' . chr(10) .
'Based on your spelling, the system would load the class "%s", however this class does not exist.',
$namespaceIdentifier,
$methodIdentifier,
$resolvedViewHelperClassName
), 1407060572);
}
$this->resolvedViewHelperClassNames[$namespaceIdentifier][$methodIdentifier] = $actualViewHelperClassName;
$this->resolvedViewHelperClassNames[$namespaceIdentifier][$methodIdentifier] =
$this->resolveViewHelperName($namespaceIdentifier, $methodIdentifier);
}
return $this->resolvedViewHelperClassNames[$namespaceIdentifier][$methodIdentifier];
}
Expand Down Expand Up @@ -320,13 +314,42 @@ protected function resolveViewHelperName($namespaceIdentifier, $methodIdentifier
} else {
$className = ucfirst($explodedViewHelperName[0]);
}
$className .= 'ViewHelper';
$classNames = [
$className . 'ViewHelper',
$className,
];

if (array_key_exists($namespaceIdentifier, $this->namespaces)) {
$namespaces = (array) $this->namespaces[$namespaceIdentifier];
} else {
$namespacePrefix = $this->namespaces[$namespaceIdentifier] = str_replace('.', '\\', $namespaceIdentifier);
$namespaces = [
$namespacePrefix . '\\ViewHelpers',
$namespacePrefix,
];
}

$namespaces = (array) $this->namespaces[$namespaceIdentifier];
$checked = [];
foreach (array_reverse($namespaces) as $namespace) {
$namespace = rtrim($namespace, '\\');
foreach ($classNames as $className) {
$name = $namespace . '\\' . $className;
if (class_exists($name) && is_a($name, ViewHelperInterface::class, true)) {
return $name;
}
$checked[] = $name;
}
}

do {
$name = rtrim(array_pop($namespaces), '\\') . '\\' . $className;
} while (!class_exists($name) && count($namespaces));
throw new ParserException(
sprintf(
'The ViewHelper "<%s:%s>" could not be resolved. Fluid checked for "%s" but none of those classes exist.',
$namespaceIdentifier,
$methodIdentifier,
implode(', ', $checked)
),
1407060572
);

return $name;
}
Expand Down
2 changes: 1 addition & 1 deletion tests/Functional/ExamplesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ public function getExampleScriptTestValues()
'Section rendering error: Section "DoesNotExist" does not exist. Section rendering is mandatory; "optional" is false.',
'ViewHelper error: Undeclared arguments passed to ViewHelper TYPO3Fluid\Fluid\ViewHelpers\IfViewHelper: notregistered. Valid arguments are: then, else, condition - Offending code: <f:if notregistered="1" />',
'Parser error: The ViewHelper "<f:invalid>" could not be resolved.',
'Based on your spelling, the system would load the class "TYPO3Fluid\Fluid\ViewHelpers\InvalidViewHelper", however this class does not exist. Offending code: <f:invalid />',
'Fluid checked for "TYPO3Fluid\Fluid\ViewHelpers\InvalidViewHelper, TYPO3Fluid\Fluid\ViewHelpers\Invalid" but none of those classes exist. Offending code: <f:invalid />',
'Invalid expression: Invalid target conversion type "invalidtype" specified in casting expression "{foobar as invalidtype}".',
]
]
Expand Down
21 changes: 21 additions & 0 deletions tests/Unit/Core/ViewHelper/ViewHelperResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,16 @@ public function testResolveViewHelperClassNameSupportsMultipleNamespaces()
$this->assertEquals('TYPO3Fluid\\Fluid\\ViewHelpers\\RenderViewHelper', $result);
}

/**
* @test
*/
public function testResolveViewHelperClassNameSupportsDirectDottedNamespace()
{
$resolver = $this->getAccessibleMock(ViewHelperResolver::class, ['dummy']);
$result = $resolver->_call('resolveViewHelperName', 'TYPO3Fluid.Fluid', 'render');
$this->assertEquals('TYPO3Fluid\\Fluid\\ViewHelpers\\RenderViewHelper', $result);
}

/**
* @test
*/
Expand All @@ -103,6 +113,16 @@ public function testResolveViewHelperClassNameTrimsBackslashSuffixFromNamespace(
$this->assertEquals('TYPO3Fluid\\Fluid\\ViewHelpers\\RenderViewHelper', $result);
}

/**
* @test
*/
public function testResolveViewHelperClassNameSupportsVendorAndPackageNameAsNamespace()
{
$resolver = $this->getAccessibleMock(ViewHelperResolver::class, ['dummy']);
$result = $resolver->_call('resolveViewHelperName', 'TYPO3Fluid.Fluid', 'render');
$this->assertEquals('TYPO3Fluid\\Fluid\\ViewHelpers\\RenderViewHelper', $result);
}

/**
* @test
*/
Expand Down Expand Up @@ -255,6 +275,7 @@ public function getIsNamespaceValidTestValues()
[['foo' => ['test']], 'foo', true],
[['foo' => ['test']], 'foobar', false],
[['foo*' => null], 'foo', false],
[[], 'Vendor.Namespace', true],
];
}

Expand Down