diff --git a/Neos.FluidAdaptor/Classes/Core/Cache/CacheAdaptor.php b/Neos.FluidAdaptor/Classes/Core/Cache/CacheAdaptor.php index 43bb16e5a4..aaa4dad17f 100644 --- a/Neos.FluidAdaptor/Classes/Core/Cache/CacheAdaptor.php +++ b/Neos.FluidAdaptor/Classes/Core/Cache/CacheAdaptor.php @@ -27,14 +27,7 @@ class CacheAdaptor implements FluidCacheInterface */ protected $flowCache; - /** - * Gets an entry from the cache or NULL if the - * entry does not exist. - * - * @param string $name - * @return string - */ - public function get($name) + public function get(string $name): mixed { if ($this->flowCache->has($name)) { $this->flowCache->requireOnce($name); @@ -43,45 +36,21 @@ public function get($name) return $this->flowCache->getWrapped($name); } - /** - * Set or updates an entry identified by $name - * into the cache. - * - * @param string $name - * @param string $value - */ - public function set($name, $value) + public function set(string $name, mixed $value): void { - // we need to strip the first line with the php header as the flow cache adds that again. $this->flowCache->set($name, substr($value, strpos($value, "\n") + 1)); } - /** - * Flushes the cache either by entry or flushes - * the entire cache if no entry is provided. - * - * @param string|null $name - * @return bool|null - */ - public function flush($name = null) + public function flush(?string $name = null): void { - if ($name !== null) { - return $this->flowCache->remove($name); - } else { + if ($name === null) { $this->flowCache->flush(); - return null; + return; } + $this->flowCache->remove($name); } - /** - * Get an instance of FluidCacheWarmerInterface which - * can warm up template files that would normally be - * cached on-the-fly to this FluidCacheInterface - * implementaion. - * - * @return FluidCacheWarmerInterface - */ - public function getCacheWarmer() + public function getCacheWarmer(): FluidCacheWarmerInterface { return new StandardCacheWarmer(); } diff --git a/Neos.FluidAdaptor/Classes/Core/Parser/Interceptor/ResourceInterceptor.php b/Neos.FluidAdaptor/Classes/Core/Parser/Interceptor/ResourceInterceptor.php index 286870a6ac..65c9a7978e 100644 --- a/Neos.FluidAdaptor/Classes/Core/Parser/Interceptor/ResourceInterceptor.php +++ b/Neos.FluidAdaptor/Classes/Core/Parser/Interceptor/ResourceInterceptor.php @@ -11,6 +11,8 @@ * source code. */ +use Neos\Flow\Annotations as Flow; +use Neos\Flow\Mvc\Routing\Router; use Neos\Flow\Package\FlowPackageKey; use Neos\FluidAdaptor\Core\Parser\SyntaxTree\ResourceUriNode; use TYPO3Fluid\Fluid\Core\Parser\InterceptorInterface; @@ -40,7 +42,7 @@ class ResourceInterceptor implements InterceptorInterface * * @var string */ - const PATTERN_SPLIT_AT_RESOURCE_URIS = '! + private const PATTERN_SPLIT_AT_RESOURCE_URIS = '! ( (?:[^"\'(\s]+/ # URL part: A string with no quotes, no opening parentheses and no whitespace )* # a URL consists of multiple URL parts @@ -55,7 +57,7 @@ class ResourceInterceptor implements InterceptorInterface * @var string * @see \Neos\Flow\Package\FlowPackageKey::PATTERN */ - const PATTERN_MATCH_RESOURCE_URI = '!(?:../)*(?:(?P[A-Za-z0-9]+\.(?:[A-Za-z0-9][\.a-z0-9]*)+)/Resources/)?Public/(?P[^"]+)!'; + private const PATTERN_MATCH_RESOURCE_URI = '!(?:../)*(?:(?P[A-Za-z0-9]+\.(?:[A-Za-z0-9][\.a-z0-9]*)+)/Resources/)?Public/(?P[^"]+)!'; /** * The default package key to use when rendering resource links without a @@ -63,7 +65,13 @@ class ResourceInterceptor implements InterceptorInterface * * @var string */ - protected $defaultPackageKey; + protected string $defaultPackageKey = ''; + + /** + * @Flow\Inject + * @var Router + */ + protected Router $router; /** * Set the default package key to use for resource URIs. @@ -72,7 +80,7 @@ class ResourceInterceptor implements InterceptorInterface * @return void * @throws \InvalidArgumentException */ - public function setDefaultPackageKey($defaultPackageKey) + public function setDefaultPackageKey(string $defaultPackageKey): void { if (!FlowPackageKey::isPackageKeyValid($defaultPackageKey)) { throw new \InvalidArgumentException('The given argument was not a valid package key.', 1277287099); @@ -89,12 +97,9 @@ public function setDefaultPackageKey($defaultPackageKey) * @param ParsingState $parsingState the current parsing state. Not needed in this interceptor. * @return NodeInterface the modified node */ - public function process(NodeInterface $node, $interceptorPosition, ParsingState $parsingState) + public function process(NodeInterface $node, $interceptorPosition, ParsingState $parsingState): NodeInterface { - if (!$node instanceof TextNode) { - return $node; - } - if (strpos($node->getText(), 'Public/') === false) { + if (!$node instanceof TextNode || !str_contains($node->getText(), 'Public/')) { return $node; } $textParts = preg_split(self::PATTERN_SPLIT_AT_RESOURCE_URIS, $node->getText(), -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); @@ -106,14 +111,13 @@ public function process(NodeInterface $node, $interceptorPosition, ParsingState 'path' => new TextNode($matches['Path']) ]; - if ($this->defaultPackageKey !== null) { - $arguments['package'] = new TextNode($this->defaultPackageKey); - } + $packageKey = $this->defaultPackageKey; + if (isset($matches['Package']) && FlowPackageKey::isPackageKeyValid($matches['Package'])) { - $arguments['package'] = new TextNode($matches['Package']); + $packageKey = $matches['Package']; } - $resourceUriNode = new ResourceUriNode($arguments); + $resourceUriNode = new ResourceUriNode($matches['Path'], $packageKey); $node->addChildNode($resourceUriNode); } else { $textNode = new TextNode($part); diff --git a/Neos.FluidAdaptor/Classes/Core/Parser/SyntaxTree/ResourceUriNode.php b/Neos.FluidAdaptor/Classes/Core/Parser/SyntaxTree/ResourceUriNode.php index db44103330..f05a853f1a 100644 --- a/Neos.FluidAdaptor/Classes/Core/Parser/SyntaxTree/ResourceUriNode.php +++ b/Neos.FluidAdaptor/Classes/Core/Parser/SyntaxTree/ResourceUriNode.php @@ -11,53 +11,73 @@ * source code. */ +use Neos\Flow\I18n\Service; +use Neos\Flow\ResourceManagement\Exception; +use Neos\Flow\ResourceManagement\ResourceManager; use Neos\FluidAdaptor\Core\Parser\Interceptor\ResourceInterceptor; -use Neos\FluidAdaptor\Core\ViewHelper\ViewHelperResolver; -use Neos\FluidAdaptor\ViewHelpers\Uri\ResourceViewHelper; -use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode; -use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\NodeInterface; +use Neos\FluidAdaptor\Core\Rendering\RenderingContext; +use Neos\FluidAdaptor\Core\ViewHelper\Exception\InvalidVariableException; +use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\AbstractNode; +use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface; /** * A special ViewHelperNode that works via injections and is created by the ResourceInterceptor * * @see ResourceInterceptor */ -class ResourceUriNode extends ViewHelperNode +class ResourceUriNode extends AbstractNode { /** - * @var array + * @var ResourceManager|null */ - protected $arguments = []; + protected ?ResourceManager $resourceManager; - /** - * @var ViewHelperResolver - */ - protected $viewHelperResolver; + protected ?Service $i18nService; - /** - * @var string - */ - protected $viewHelperClassName = ResourceViewHelper::class; + public function injectResourceManager(ResourceManager $resourceManager): void + { + $this->resourceManager = $resourceManager; + } - /** - * @param ViewHelperResolver $viewHelperResolver - */ - public function injectViewHelperResolver(ViewHelperResolver $viewHelperResolver) + public function injectService(Service $i18nService): void { - $this->viewHelperResolver = $viewHelperResolver; - $this->uninitializedViewHelper = $this->viewHelperResolver->createViewHelperInstanceFromClassName($this->viewHelperClassName); - /** @phpstan-ignore-next-line we use internal api */ - $this->uninitializedViewHelper->setViewHelperNode($this); - $this->argumentDefinitions = $this->viewHelperResolver->getArgumentDefinitionsForViewHelper($this->uninitializedViewHelper); + $this->i18nService = $i18nService; + } + + public function __construct( + public readonly string $path, + public readonly string $package + ) { } /** - * Constructor. - * - * @param NodeInterface[] $arguments Arguments of view helper - each value is a RootNode. + * @param RenderingContextInterface $renderingContext + * @return string + * @throws InvalidVariableException */ - public function __construct(array $arguments) + public function evaluate(RenderingContextInterface $renderingContext): string { - $this->arguments = $arguments; + $package = $this->package; + $path = $this->path; + if ($package === '') { + /** @var RenderingContext $renderingContext */ + $package = $renderingContext->getControllerContext()?->getRequest()?->getControllerPackageKey(); + } + if (str_starts_with($path, 'resource://')) { + try { + [$package, $path] = $this->resourceManager->getPackageAndPathByPublicPath($path); + } catch (Exception $e) { + throw new InvalidVariableException(sprintf('The specified path "%s" does not point to a public resource.', $path), 1386458851, $e); + } + } + + $resourcePath = 'resource://' . $package . '/Public/' . $this->path; + $localizedResourcePathData = $this->i18nService->getLocalizedFilename($resourcePath); + $matches = []; + if (preg_match('#resource://([^/]+)/Public/(.*)#', current($localizedResourcePathData), $matches) === 1) { + [$_, $package, $path] = $matches; + } + + return $this->resourceManager->getPublicPackageResourceUri($package, $path); } } diff --git a/Neos.FluidAdaptor/Classes/Core/Parser/TemplateParser.php b/Neos.FluidAdaptor/Classes/Core/Parser/TemplateParser.php index 1ad1054885..742bf9f1ba 100644 --- a/Neos.FluidAdaptor/Classes/Core/Parser/TemplateParser.php +++ b/Neos.FluidAdaptor/Classes/Core/Parser/TemplateParser.php @@ -9,7 +9,7 @@ class TemplateParser extends \TYPO3Fluid\Fluid\Core\Parser\TemplateParser /** * @return boolean */ - public function isEscapingEnabled() + public function isEscapingEnabled(): bool { return $this->escapingEnabled; } @@ -17,7 +17,7 @@ public function isEscapingEnabled() /** * @param boolean $escapingEnabled */ - public function setEscapingEnabled($escapingEnabled) + public function setEscapingEnabled($escapingEnabled): void { $this->escapingEnabled = $escapingEnabled; } diff --git a/Neos.FluidAdaptor/Classes/Core/Parser/TemplateProcessor/NamespaceDetectionTemplateProcessor.php b/Neos.FluidAdaptor/Classes/Core/Parser/TemplateProcessor/NamespaceDetectionTemplateProcessor.php index b6c18f2664..8235604bed 100644 --- a/Neos.FluidAdaptor/Classes/Core/Parser/TemplateProcessor/NamespaceDetectionTemplateProcessor.php +++ b/Neos.FluidAdaptor/Classes/Core/Parser/TemplateProcessor/NamespaceDetectionTemplateProcessor.php @@ -53,11 +53,8 @@ class NamespaceDetectionTemplateProcessor extends FluidNamespaceDetectionTemplat * Pre-process the template source before it is * returned to the TemplateParser or passed to * the next TemplateProcessorInterface instance. - * - * @param string $templateSource - * @return string */ - public function preProcessSource($templateSource) + public function preProcessSource(string $templateSource): string { $templateSource = $this->protectCDataSectionsFromParser($templateSource); $templateSource = $this->registerNamespacesFromTemplateSource($templateSource); diff --git a/Neos.FluidAdaptor/Classes/Core/Rendering/FlowAwareRenderingContextInterface.php b/Neos.FluidAdaptor/Classes/Core/Rendering/FlowAwareRenderingContextInterface.php index 7bb88d9f20..cf42683c09 100644 --- a/Neos.FluidAdaptor/Classes/Core/Rendering/FlowAwareRenderingContextInterface.php +++ b/Neos.FluidAdaptor/Classes/Core/Rendering/FlowAwareRenderingContextInterface.php @@ -24,10 +24,10 @@ interface FlowAwareRenderingContextInterface /** * @return ObjectManagerInterface */ - public function getObjectManager(); + public function getObjectManager(): ObjectManagerInterface; /** * @return ControllerContext */ - public function getControllerContext(); + public function getControllerContext(): ControllerContext; } diff --git a/Neos.FluidAdaptor/Classes/Core/Rendering/RenderingContext.php b/Neos.FluidAdaptor/Classes/Core/Rendering/RenderingContext.php index 3c68fb552b..5f3693a02d 100644 --- a/Neos.FluidAdaptor/Classes/Core/Rendering/RenderingContext.php +++ b/Neos.FluidAdaptor/Classes/Core/Rendering/RenderingContext.php @@ -12,7 +12,6 @@ */ use Neos\FluidAdaptor\Core\Cache\CacheAdaptor; -use Neos\FluidAdaptor\Core\Parser\TemplateParser; use Neos\FluidAdaptor\Core\Parser\TemplateProcessor\EscapingFlagProcessor; use Neos\Flow\Annotations as Flow; use Neos\Flow\Mvc\ActionRequest; @@ -28,6 +27,7 @@ use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\Expression\CastingExpressionNode; use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\Expression\MathExpressionNode; use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\Expression\TernaryExpressionNode; +use TYPO3Fluid\Fluid\Core\Parser\TemplateParser; use TYPO3Fluid\Fluid\Core\Parser\TemplateProcessor\PassthroughSourceModifierTemplateProcessor; use TYPO3Fluid\Fluid\Core\Rendering\RenderingContext as FluidRenderingContext; @@ -52,14 +52,14 @@ class RenderingContext extends FluidRenderingContext implements FlowAwareRenderi ]; /** - * @var ControllerContext + * @var ControllerContext|null */ - protected $controllerContext; + protected ControllerContext|null $controllerContext = null; /** - * @var ObjectManagerInterface + * @var ObjectManagerInterface|null */ - protected $objectManager; + protected ObjectManagerInterface|null $objectManager = null; /** * @Flow\Inject @@ -74,9 +74,9 @@ class RenderingContext extends FluidRenderingContext implements FlowAwareRenderi protected $cache; /** - * @var Configuration + * @var Configuration|null */ - protected $parserConfiguration; + protected Configuration|null $parserConfiguration = null; /** * RenderingContext constructor. @@ -93,14 +93,16 @@ public function __construct(array $options = []) new PassthroughSourceModifierTemplateProcessor(), new NamespaceDetectionTemplateProcessor() ]); - $this->setTemplatePaths(new TemplatePaths($options)); + $templatePaths = new TemplatePaths(); + $templatePaths->setOptions($options); + $this->setTemplatePaths($templatePaths); $this->setVariableProvider(new TemplateVariableContainer()); } /** * @param ObjectManagerInterface $objectManager */ - public function injectObjectManager(ObjectManagerInterface $objectManager) + public function injectObjectManager(ObjectManagerInterface $objectManager): void { $this->objectManager = $objectManager; } @@ -108,7 +110,7 @@ public function injectObjectManager(ObjectManagerInterface $objectManager) /** * @return ControllerContext */ - public function getControllerContext() + public function getControllerContext(): ControllerContext { return $this->controllerContext; } @@ -116,7 +118,7 @@ public function getControllerContext() /** * @param ControllerContext $controllerContext */ - public function setControllerContext($controllerContext) + public function setControllerContext(ControllerContext $controllerContext): void { $this->controllerContext = $controllerContext; $request = $controllerContext->getRequest(); @@ -136,7 +138,7 @@ public function setControllerContext($controllerContext) /** * @return ObjectManagerInterface */ - public function getObjectManager() + public function getObjectManager(): ObjectManagerInterface { return $this->objectManager; } @@ -146,7 +148,7 @@ public function getObjectManager() * * @return Configuration */ - public function buildParserConfiguration() + public function buildParserConfiguration(): Configuration { if ($this->parserConfiguration === null) { $this->parserConfiguration = parent::buildParserConfiguration(); @@ -164,7 +166,7 @@ public function buildParserConfiguration() * @return void * @throws \Neos\Flow\Mvc\Exception */ - public function setOption($optionName, $value) + public function setOption(string $optionName, $value): void { if ($this->templatePaths instanceof TemplatePaths) { $this->templatePaths->setOption($optionName, $value); diff --git a/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractConditionViewHelper.php b/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractConditionViewHelper.php index 052ef09e98..9d37dbbab5 100644 --- a/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractConditionViewHelper.php +++ b/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractConditionViewHelper.php @@ -85,21 +85,15 @@ protected static function evaluateCondition($arguments, RenderingContextInterfac public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) { if (static::evaluateCondition($arguments, $renderingContext)) { - if (isset($arguments['then'])) { - return $arguments['then']; - } - if (isset($arguments['__thenClosure'])) { - return $arguments['__thenClosure'](); - } - } elseif (!empty($arguments['__elseClosures'])) { - $elseIfClosures = isset($arguments['__elseifClosures']) ? $arguments['__elseifClosures'] : []; + return ($arguments['then'] ?? $arguments['__thenClosure']) ?? ''; + } + if (!empty($arguments['__elseClosures'])) { + $elseIfClosures = $arguments['__elseifClosures'] ?? []; return static::evaluateElseClosures($arguments['__elseClosures'], $elseIfClosures, $renderingContext); - } elseif (array_key_exists('else', $arguments)) { - return $arguments['else']; } - return ''; + return $arguments['else'] ?? ''; } /** @@ -113,10 +107,10 @@ protected static function evaluateElseClosures(array $closures, array $condition foreach ($closures as $elseNodeIndex => $elseNodeClosure) { if (!isset($conditionClosures[$elseNodeIndex])) { return $elseNodeClosure(); - } else { - if ($conditionClosures[$elseNodeIndex]()) { - return $elseNodeClosure(); - } + } + + if ($conditionClosures[$elseNodeIndex]()) { + return $elseNodeClosure(); } } diff --git a/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractLocaleAwareViewHelper.php b/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractLocaleAwareViewHelper.php index 5f33d1e651..884bbb80d3 100644 --- a/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractLocaleAwareViewHelper.php +++ b/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractLocaleAwareViewHelper.php @@ -50,7 +50,7 @@ public function injectLocalizationService(I18n\Service $localizationService) * @throws InvalidVariableException * @return I18n\Locale|null The locale to use or NULL if locale should not be used */ - protected function getLocale() + protected function getLocale(): ?I18n\Locale { if (!$this->hasArgument('forceLocale')) { return null; diff --git a/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractTagBasedViewHelper.php b/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractTagBasedViewHelper.php index d4743808a6..9d0f2396ce 100644 --- a/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractTagBasedViewHelper.php +++ b/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractTagBasedViewHelper.php @@ -34,7 +34,7 @@ abstract class AbstractTagBasedViewHelper extends AbstractViewHelper * * @var array */ - private static $tagAttributes = []; + private static array $tagAttributes = []; /** * Tag builder instance @@ -42,7 +42,7 @@ abstract class AbstractTagBasedViewHelper extends AbstractViewHelper * @var TagBuilder * @api */ - protected $tag = null; + protected TagBuilder $tag; /** * Name of the tag to be created by this view helper @@ -68,7 +68,7 @@ public function __construct() * @param TagBuilder $tag * @return void */ - public function injectTagBuilder(TagBuilder $tag) + public function injectTagBuilder(TagBuilder $tag): void { $this->tag = $tag; $this->tag->setTagName($this->tagName); diff --git a/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractViewHelper.php b/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractViewHelper.php index 6731a63562..fe6634f302 100644 --- a/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractViewHelper.php +++ b/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractViewHelper.php @@ -35,26 +35,25 @@ abstract class AbstractViewHelper extends FluidAbstractViewHelper /** * Controller Context to use * - * @var ControllerContext - * @api + * @var ControllerContext|null */ - protected $controllerContext; + protected ControllerContext|null $controllerContext = null; /** - * @var ObjectManagerInterface + * @var ObjectManagerInterface|null */ - protected $objectManager; + protected ObjectManagerInterface|null $objectManager = null; /** - * @var LoggerInterface + * @var LoggerInterface|null */ - protected $logger; + protected LoggerInterface|null $logger; /** * @param FlowAwareRenderingContextInterface&RenderingContextInterface $renderingContext * @return void */ - public function setRenderingContext(RenderingContextInterface $renderingContext) + public function setRenderingContext(RenderingContextInterface $renderingContext): void { $this->renderingContext = $renderingContext; $this->templateVariableContainer = $renderingContext->getVariableProvider(); diff --git a/Neos.FluidAdaptor/Classes/Core/ViewHelper/Exception/RenderingContextNotAccessibleException.php b/Neos.FluidAdaptor/Classes/Core/ViewHelper/Exception/RenderingContextNotAccessibleException.php deleted file mode 100644 index e20c442856..0000000000 --- a/Neos.FluidAdaptor/Classes/Core/ViewHelper/Exception/RenderingContextNotAccessibleException.php +++ /dev/null @@ -1,23 +0,0 @@ -variables; @@ -114,14 +111,10 @@ protected function getBooleanValue(string $path): ?bool { $normalizedPath = strtolower($path); - if (in_array($normalizedPath, ['true', 'on', 'yes'])) { - return true; - } - - if (in_array($normalizedPath, ['false', 'off', 'no'])) { - return false; - } - - return null; + return match (true) { + (in_array($normalizedPath, ['true', 'on', 'yes'])) => true, + (in_array($normalizedPath, ['false', 'off', 'no'])) => false, + default => null + }; } } diff --git a/Neos.FluidAdaptor/Classes/Core/ViewHelper/ViewHelperResolver.php b/Neos.FluidAdaptor/Classes/Core/ViewHelper/ViewHelperResolver.php index 8351bfa4f1..9cd2f16033 100644 --- a/Neos.FluidAdaptor/Classes/Core/ViewHelper/ViewHelperResolver.php +++ b/Neos.FluidAdaptor/Classes/Core/ViewHelper/ViewHelperResolver.php @@ -15,6 +15,7 @@ use Neos\Flow\ObjectManagement\ObjectManagerInterface; use Neos\Flow\Package\Package; use Neos\Flow\Package\PackageManager; +use TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperInterface; /** * Class ViewHelperResolver @@ -49,9 +50,9 @@ class ViewHelperResolver extends \TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperRes * will look for classes in both namespaces starting * from the bottom. * - * @var array + * @var array */ - protected $namespaces = []; + protected array $namespaces = []; /** * @Flow\InjectConfiguration(path="namespaces") @@ -59,7 +60,7 @@ class ViewHelperResolver extends \TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperRes */ protected $namespacesFromConfiguration; - public function initializeObject($reason) + public function initializeObject($reason): void { if ($reason === ObjectManagerInterface::INITIALIZATIONCAUSE_RECREATED) { return; @@ -69,7 +70,7 @@ public function initializeObject($reason) foreach ($this->packageManager->getAvailablePackages() as $package) { foreach ($package->getNamespaces() as $namespace) { $viewHelperNamespace = $namespace; - if (strpos(strrev($namespace), '\\') !== 0) { + if (str_ends_with($namespace, '\\') === false) { $viewHelperNamespace .= '\\'; } $viewHelperNamespace .= 'ViewHelpers'; @@ -82,79 +83,13 @@ public function initializeObject($reason) } } - /** - * @param string $viewHelperClassName - * @return \TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperInterface - */ - public function createViewHelperInstanceFromClassName($viewHelperClassName) - { - return $this->objectManager->get($viewHelperClassName); - } - - /** - * Add a PHP namespace where ViewHelpers can be found and give - * it an alias/identifier. - * - * The provided namespace can be either a single namespace or - * an array of namespaces, as strings. The identifier/alias is - * always a single, alpha-numeric ASCII string. - * - * Calling this method multiple times with different PHP namespaces - * for the same alias causes that namespace to be *extended*, - * meaning that the PHP namespace you provide second, third etc. - * are also used in lookups and are used *first*, so that if any - * of the namespaces you add contains a class placed and named the - * same way as one that exists in an earlier namespace, then your - * class gets used instead of the earlier one. - * - * Example: - * - * $resolver->addNamespace('my', 'My\Package\ViewHelpers'); - * // Any ViewHelpers under this namespace can now be accessed using for example {my:example()} - * // Now, assuming you also have an ExampleViewHelper class in a different - * // namespace and wish to make that ExampleViewHelper override the other: - * $resolver->addNamespace('my', 'My\OtherPackage\ViewHelpers'); - * // Now, since ExampleViewHelper exists in both places but the - * // My\OtherPackage\ViewHelpers namespace was added *last*, Fluid - * // will find and use My\OtherPackage\ViewHelpers\ExampleViewHelper. - * - * Alternatively, setNamespaces() can be used to reset and redefine - * all previously added namespaces - which is great for cases where - * you need to remove or replace previously added namespaces. Be aware - * that setNamespaces() also removes the default "f" namespace, so - * when you use this method you should always include the "f" namespace. - * - * @param string $identifier - * @param string|array $phpNamespace - * @return void - */ - public function addNamespace($identifier, $phpNamespace) - { - if ($phpNamespace === null) { - $this->namespaces[$identifier] = null; - return; - } - - if (!is_array($phpNamespace)) { - $this->addNamespaceInternal($identifier, $phpNamespace); - return; - } - - foreach ($phpNamespace as $namespace) { - $this->addNamespaceInternal($identifier, $namespace); - } - } - - /** - * @param string $identifier - * @param string $phpNamespace - */ - protected function addNamespaceInternal($identifier, $phpNamespace) + public function createViewHelperInstanceFromClassName(string $viewHelperClassName): ViewHelperInterface { - if (!isset($this->namespaces[$identifier])) { - $this->namespaces[$identifier] = []; + $possibleViewHelper = $this->objectManager->get($viewHelperClassName); + if ($possibleViewHelper instanceof ViewHelperInterface) { + return $possibleViewHelper; } - $this->namespaces[$identifier] = array_unique(array_merge($this->namespaces[$identifier], [$phpNamespace])); + throw new \RuntimeException('Given ViewHelper class "' . $viewHelperClassName . '" does not implement ViewHelperInterface'); } } diff --git a/Neos.FluidAdaptor/Classes/Core/Widget/AbstractWidgetViewHelper.php b/Neos.FluidAdaptor/Classes/Core/Widget/AbstractWidgetViewHelper.php index e390a32db6..81e7a193ca 100644 --- a/Neos.FluidAdaptor/Classes/Core/Widget/AbstractWidgetViewHelper.php +++ b/Neos.FluidAdaptor/Classes/Core/Widget/AbstractWidgetViewHelper.php @@ -111,7 +111,7 @@ public function initializeArgumentsAndRender() $this->initialize(); $this->initializeWidgetContext(); - return $this->callRenderMethod(); + return $this->render(); } /** diff --git a/Neos.FluidAdaptor/Classes/View/AbstractTemplateView.php b/Neos.FluidAdaptor/Classes/View/AbstractTemplateView.php index 37a64bfa17..280df36ee1 100644 --- a/Neos.FluidAdaptor/Classes/View/AbstractTemplateView.php +++ b/Neos.FluidAdaptor/Classes/View/AbstractTemplateView.php @@ -85,12 +85,12 @@ abstract class AbstractTemplateView extends \TYPO3Fluid\Fluid\View\AbstractTempl 'string' ], 'templatePathAndFilename' => [ - null, + '', 'Path and filename of the template file. If set, overrides the templatePathAndFilenamePattern', 'string' ], 'layoutPathAndFilename' => [ - null, + '', 'Path and filename of the layout file. If set, overrides the layoutPathAndFilenamePattern', 'string' ] @@ -110,9 +110,6 @@ abstract class AbstractTemplateView extends \TYPO3Fluid\Fluid\View\AbstractTempl */ protected $controllerContext; - /** - * @phpstan-ignore-next-line we are incompatible with the fluid view and should use composition instead - */ public function render($actionName = null): StreamInterface { return $this->createStream(parent::render($actionName)); @@ -147,12 +144,8 @@ public static function createWithOptions(array $options): self * @param array $options * @throws Exception */ - public function __construct(?array $options = null) + public function __construct(array $options = []) { - if ($options === null) { - $options = []; - } - $this->validateOptions($options); $this->setOptions($options); @@ -168,7 +161,7 @@ public function __construct(?array $options = null) */ public function setTemplatePathAndFilename($templatePathAndFilename) { - $this->getTemplatePaths()->setTemplatePathAndFilename($templatePathAndFilename); + $this->baseRenderingContext->getTemplatePaths()->setTemplatePathAndFilename($templatePathAndFilename); } /** @@ -184,8 +177,7 @@ public function setControllerContext(ControllerContext $controllerContext) $renderingContext->setControllerContext($controllerContext); } - - $paths = $this->getTemplatePaths(); + $paths = $this->baseRenderingContext->getTemplatePaths(); $request = $controllerContext->getRequest(); if (!$request instanceof ActionRequest) { @@ -210,11 +202,11 @@ public function setControllerContext(ControllerContext $controllerContext) * @return string rendered template for the section * @throws \Neos\FluidAdaptor\View\Exception\InvalidSectionException */ - public function renderSection($sectionName, array $variables = [], $ignoreUnknown = false) + public function renderSection($sectionName, array|\ArrayAccess $variables = [], $ignoreUnknown = false) { // FIXME: We should probably give variables explicitly to this method. - if ($variables === []) { - $variables = $this->getRenderingContext()->getVariableProvider()->getAll(); + if (empty($variables)) { + $variables = $this->getCurrentRenderingContext()->getVariableProvider()->getAll(); } return parent::renderSection($sectionName, $variables, $ignoreUnknown); @@ -301,4 +293,13 @@ public function setOption($optionName, $value) $this->baseRenderingContext->setOption($optionName, $value); } } + + /** + * @deprecated Use $this->getRenderingContext()->getTemplatePaths() + * @see RenderingContext::getTemplatePaths() + */ + public function getTemplatePaths(): \TYPO3Fluid\Fluid\View\TemplatePaths + { + return $this->baseRenderingContext->getTemplatePaths(); + } } diff --git a/Neos.FluidAdaptor/Classes/View/StandaloneView.php b/Neos.FluidAdaptor/Classes/View/StandaloneView.php index 6fdb79413a..2c37d85ab6 100644 --- a/Neos.FluidAdaptor/Classes/View/StandaloneView.php +++ b/Neos.FluidAdaptor/Classes/View/StandaloneView.php @@ -75,7 +75,7 @@ public static function createWithOptions(array $options): self /** * Constructor * - * @param ActionRequest $request The current action request. If none is specified it will be created from the environment. + * @param ActionRequest|null $request The current action request. If none is specified it will be created from the environment. * @param array $options * @throws \Neos\FluidAdaptor\Exception */ @@ -90,7 +90,7 @@ public function __construct(?ActionRequest $request = null, array $options = []) * * @return void */ - public function initializeObject() + public function initializeObject(): void { if ($this->request === null) { $requestHandler = $this->bootstrap->getActiveRequestHandler(); @@ -116,7 +116,7 @@ public function initializeObject() /** * @param string $templateName */ - public function setTemplate($templateName) + public function setTemplate($templateName): void { $this->baseRenderingContext->setControllerAction($templateName); } @@ -128,7 +128,7 @@ public function setTemplate($templateName) * @return void * @api */ - public function setFormat($format) + public function setFormat($format): void { $this->request->setFormat($format); $this->baseRenderingContext->getTemplatePaths()->setFormat($format); diff --git a/Neos.FluidAdaptor/Classes/View/TemplatePaths.php b/Neos.FluidAdaptor/Classes/View/TemplatePaths.php index ee45bae7eb..bdbcd4d385 100644 --- a/Neos.FluidAdaptor/Classes/View/TemplatePaths.php +++ b/Neos.FluidAdaptor/Classes/View/TemplatePaths.php @@ -61,13 +61,6 @@ class TemplatePaths extends \TYPO3Fluid\Fluid\View\TemplatePaths */ protected $packageManager; - public function __construct(array $options = []) - { - foreach ($options as $optionName => $optionValue) { - $this->setOption($optionName, $optionValue); - } - } - /** * @param PackageManager $packageManager */ @@ -119,9 +112,9 @@ public function setTemplateRootPath($templateRootPath) /** * Resolves the template root to be used inside other paths. * - * @return array Path(s) to template root directory + * @return string[] */ - public function getTemplateRootPaths() + public function getTemplateRootPaths(): array { if ($this->templateRootPaths !== []) { return $this->templateRootPaths; @@ -140,9 +133,9 @@ public function getTemplateRootPaths() } /** - * @return array + * @return string[] */ - public function getLayoutRootPaths() + public function getLayoutRootPaths(): array { if ($this->layoutRootPaths !== []) { return $this->layoutRootPaths; @@ -160,7 +153,10 @@ public function getLayoutRootPaths() return [$layoutRootPath]; } - public function getPartialRootPaths() + /** + * @return string[] + */ + public function getPartialRootPaths(): array { if ($this->partialRootPaths !== []) { return $this->partialRootPaths; @@ -217,10 +213,9 @@ public function setPatternReplacementVariables($patternReplacementVariables) * @param string $controller * @param string $action * @param string $format - * @return mixed|string * @throws Exception\InvalidTemplateResourceException */ - public function resolveTemplateFileForControllerAndActionAndFormat($controller, $action, $format = null) + public function resolveTemplateFileForControllerAndActionAndFormat(string $controller, string $action, ?string $format = null): null|string { if ($this->templatePathAndFilename) { return $this->templatePathAndFilename; @@ -229,7 +224,7 @@ public function resolveTemplateFileForControllerAndActionAndFormat($controller, $action = ucfirst($action); $paths = $this->getTemplateRootPaths(); - if (isset($this->options['templatePathAndFilenamePattern'])) { + if (!empty($this->options['templatePathAndFilenamePattern'])) { $paths = $this->expandGenericPathPattern($this->options['templatePathAndFilenamePattern'], array_merge($this->patternReplacementVariables, [ 'controllerName' => $controller, 'action' => $action, @@ -262,15 +257,15 @@ public function resolveTemplateFileForControllerAndActionAndFormat($controller, * @return string Path and filename of layout files * @throws Exception\InvalidTemplateResourceException */ - public function getLayoutPathAndFilename($layoutName = 'Default') + public function getLayoutPathAndFilename(string $layoutName = 'Default'): string { - if (isset($this->options['layoutPathAndFilename'])) { + if (!empty($this->options['layoutPathAndFilename'])) { return $this->options['layoutPathAndFilename']; } $layoutName = ucfirst($layoutName); $paths = $this->getLayoutRootPaths(); - if (isset($this->options['layoutPathAndFilenamePattern'])) { + if (!empty($this->options['layoutPathAndFilenamePattern'])) { $paths = $this->expandGenericPathPattern($this->options['layoutPathAndFilenamePattern'], array_merge($this->patternReplacementVariables, [ 'layout' => $layoutName ]), true, true); @@ -291,14 +286,14 @@ public function getLayoutPathAndFilename($layoutName = 'Default') * @return string the full path which should be used. The path definitely exists. * @throws InvalidTemplateResourceException */ - public function getPartialPathAndFilename($partialName) + public function getPartialPathAndFilename(string $partialName): string { $patternReplacementVariables = array_merge($this->patternReplacementVariables, [ 'partial' => $partialName, ]); - if (strpos($partialName, ':') !== false) { - list($packageKey, $actualPartialName) = explode(':', $partialName); + if (str_contains($partialName, ':')) { + [$packageKey, $actualPartialName] = explode(':', $partialName); /** @var FlowPackageInterface $package */ $package = $this->packageManager->getPackage($packageKey); $patternReplacementVariables['package'] = $packageKey; @@ -321,7 +316,7 @@ public function getPartialPathAndFilename($partialName) * @param string $packageName * @return string */ - protected function getPackagePath($packageName) + protected function getPackagePath(string $packageName): string { if ($this->packageManager === null) { return ''; @@ -344,7 +339,7 @@ protected function getPackagePath($packageName) * @param string $path * @return string */ - protected function sanitizePath($path) + protected function sanitizePath($path): string { if (empty($path)) { return ''; @@ -522,17 +517,21 @@ public function setOption($optionName, $value) } } + public function setOptions(array $options = []): void + { + foreach ($options as $optionName => $optionValue) { + $this->setOption($optionName, $optionValue); + } + } + /** * Returns a unique identifier for the given file in the format * ____ * The SH1 hash is a checksum that is based on the file path and last modification date * - * @param string|null $pathAndFilename - * @param string $prefix - * @return string * @throws InvalidTemplateResourceException */ - protected function createIdentifierForFile($pathAndFilename, $prefix) + protected function createIdentifierForFile(?string $pathAndFilename, string $prefix): string { $pathAndFilename = (string)$pathAndFilename; $templateModifiedTimestamp = 0; diff --git a/Neos.FluidAdaptor/Classes/View/TemplateView.php b/Neos.FluidAdaptor/Classes/View/TemplateView.php index cae651373b..ac2a521333 100644 --- a/Neos.FluidAdaptor/Classes/View/TemplateView.php +++ b/Neos.FluidAdaptor/Classes/View/TemplateView.php @@ -11,11 +11,9 @@ * source code. */ -use Neos\Flow\Mvc\View\ViewInterface; - /** * A standard Flow view based on Fluid. */ -class TemplateView extends AbstractTemplateView implements ViewInterface +class TemplateView extends AbstractTemplateView { } diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Form/CheckboxViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Form/CheckboxViewHelper.php index d7d4e3b574..335abc9271 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Form/CheckboxViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Form/CheckboxViewHelper.php @@ -63,7 +63,7 @@ public function initializeArguments() $this->registerArgument('errorClass', 'string', 'CSS class to set if there are errors for this view helper', false, 'f3-form-error'); $this->registerArgument('checked', 'boolean', 'Specifies that the input element should be preselected', false, null); $this->registerArgument('multiple', 'boolean', 'Specifies whether this checkbox belongs to a multivalue (is part of a checkbox group)', false, null); - $this->overrideArgument('value', 'mixed', 'Value of input tag. Required for checkboxes', true); + $this->registerArgument('value', 'mixed', 'Value of input tag. Required for checkboxes', true); $this->registerUniversalTagAttributes(); } diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Form/RadioViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Form/RadioViewHelper.php index 2e57853d7e..6c6f2d5d89 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Form/RadioViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Form/RadioViewHelper.php @@ -62,7 +62,7 @@ public function initializeArguments() $this->registerTagAttribute('disabled', 'boolean', 'Specifies that the input element should be disabled when the page loads', false, false); $this->registerArgument('errorClass', 'string', 'CSS class to set if there are errors for this view helper', false, 'f3-form-error'); $this->registerArgument('checked', 'boolean', 'Specifies that the input element should be preselected', false, null); - $this->overrideArgument('value', 'mixed', 'Value of input tag. Required for radio buttons', true); + $this->registerArgument('value', 'mixed', 'Value of input tag. Required for radio buttons', true); $this->registerUniversalTagAttributes(); } diff --git a/Neos.FluidAdaptor/Tests/Unit/Core/Parser/Interceptor/ResourceInterceptorTest.php b/Neos.FluidAdaptor/Tests/Unit/Core/Parser/Interceptor/ResourceInterceptorTest.php index 6f44313956..ec838ff340 100644 --- a/Neos.FluidAdaptor/Tests/Unit/Core/Parser/Interceptor/ResourceInterceptorTest.php +++ b/Neos.FluidAdaptor/Tests/Unit/Core/Parser/Interceptor/ResourceInterceptorTest.php @@ -50,9 +50,7 @@ public function resourcesInCssUrlsAreReplacedCorrectly() self::assertCount(3, $resultingNodeTree->getChildNodes()); foreach ($resultingNodeTree->getChildNodes() as $parserNode) { if ($parserNode instanceof ResourceUriNode) { - self::assertEquals([ - 'path' => $path - ], $parserNode->getArguments()); + self::assertEquals($path, $parserNode->path); } } } @@ -122,10 +120,8 @@ public function supportedUrlsAreDetected($part1, $part2, $part3, $expectedPath, self::assertCount(3, $resultingNodeTree->getChildNodes()); foreach ($resultingNodeTree->getChildNodes() as $parserNode) { if ($parserNode instanceof ResourceUriNode) { - self::assertEquals([ - 'path' => $expectedPath, - 'package' => $expectedPackageKey - ], $parserNode->getArguments()); + self::assertEquals($expectedPath, $parserNode->path); + self::assertEquals($expectedPackageKey, $parserNode->package); } } } diff --git a/Neos.FluidAdaptor/Tests/Unit/Core/ViewHelper/AbstractViewHelperTest.php b/Neos.FluidAdaptor/Tests/Unit/Core/ViewHelper/AbstractViewHelperTest.php index 15b5a8a582..392e26ec0c 100644 --- a/Neos.FluidAdaptor/Tests/Unit/Core/ViewHelper/AbstractViewHelperTest.php +++ b/Neos.FluidAdaptor/Tests/Unit/Core/ViewHelper/AbstractViewHelperTest.php @@ -15,11 +15,11 @@ use Neos\Flow\ObjectManagement\ObjectManagerInterface; use Neos\Flow\Reflection\ReflectionService; use Neos\Flow\Tests\UnitTestCase; +use Neos\FluidAdaptor\Core\Rendering\RenderingContext; use Neos\FluidAdaptor\Core\ViewHelper\AbstractViewHelper; use Neos\FluidAdaptor\Core\ViewHelper\TemplateVariableContainer; use Neos\FluidAdaptor\View\TemplateView; use TYPO3Fluid\Fluid\Core\ViewHelper\ArgumentDefinition; -use TYPO3Fluid\Fluid\Core\ViewHelper\Exception; use TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperVariableContainer; require_once(__DIR__ . '/../Fixtures/TestViewHelper.php'); @@ -105,41 +105,6 @@ public function argumentsCanBeRegistered(): void self::assertEquals([$name => $expected], $viewHelper->prepareArguments(), 'Argument definitions not returned correctly.'); } - /** - * @test - */ - public function overrideArgumentOverwritesExistingArgumentDefinition(): void - { - $this->mockReflectionService->expects(self::any())->method('getMethodParameters')->willReturn([]); - - $viewHelper = $this->getAccessibleMock(AbstractViewHelper::class, ['render'], [], '', false); - $viewHelper->injectObjectManager($this->mockObjectManager); - - $name = 'argumentName'; - $description = 'argument description'; - $overriddenDescription = 'overwritten argument description'; - $type = 'string'; - $overriddenType = 'integer'; - $isRequired = true; - $expected = new ArgumentDefinition($name, $overriddenType, $overriddenDescription, $isRequired); - - $viewHelper->_call('registerArgument', $name, $type, $description, $isRequired); - $viewHelper->_call('overrideArgument', $name, $overriddenType, $overriddenDescription, $isRequired); - self::assertEquals($viewHelper->prepareArguments(), [$name => $expected], 'Argument definitions not returned correctly. The original ArgumentDefinition could not be overridden.'); - } - - /** - * @test - */ - public function overrideArgumentThrowsExceptionWhenTryingToOverwriteAnNonexistingArgument(): void - { - $this->expectException(Exception::class); - $viewHelper = $this->getAccessibleMock(AbstractViewHelper::class, ['render'], [], '', false); - $viewHelper->injectObjectManager($this->mockObjectManager); - - $viewHelper->_call('overrideArgument', 'argumentName', 'string', 'description', true); - } - /** * @test */ @@ -221,22 +186,22 @@ public function validateArgumentsCallsTheRightValidatorsAndThrowsExceptionIfVali public function initializeArgumentsAndRenderCallsTheCorrectSequenceOfMethods(): void { $calls = []; - $viewHelper = $this->getAccessibleMock(AbstractViewHelper::class, ['validateArguments', 'initialize', 'callRenderMethod']); + $viewHelper = $this->getAccessibleMock(AbstractViewHelper::class, ['validateArguments', 'initialize', 'render']); $viewHelper->expects(self::atLeastOnce())->method('validateArguments')->willReturnCallback(function () use (&$calls) { $calls[] = 'validateArguments'; }); $viewHelper->expects(self::atLeastOnce())->method('initialize')->willReturnCallback(function () use (&$calls) { $calls[] = 'initialize'; }); - $viewHelper->expects(self::atLeastOnce())->method('callRenderMethod')->willReturnCallback(function () use (&$calls) { - $calls[] = 'callRenderMethod'; + $viewHelper->expects(self::atLeastOnce())->method('render')->willReturnCallback(function () use (&$calls) { + $calls[] = 'render'; return 'Output'; }); $expectedOutput = 'Output'; $actualOutput = $viewHelper->initializeArgumentsAndRender(['argument1' => 'value1']); self::assertEquals($expectedOutput, $actualOutput); - self::assertEquals(['validateArguments', 'initialize', 'callRenderMethod'], $calls); + self::assertEquals(['validateArguments', 'initialize', 'render'], $calls); } /** @@ -249,6 +214,7 @@ public function setRenderingContextShouldSetInnerVariables(): void $controllerContext = $this->getMockBuilder(ControllerContext::class)->disableOriginalConstructor()->getMock(); $dummyView = new TemplateView([]); + /** @var RenderingContext $renderingContext */ $renderingContext = $dummyView->getRenderingContext(); $renderingContext->setVariableProvider($templateVariableContainer); $renderingContext->setViewHelperVariableContainer($viewHelperVariableContainer); diff --git a/Neos.FluidAdaptor/Tests/Unit/Core/Widget/AbstractWidgetViewHelperTest.php b/Neos.FluidAdaptor/Tests/Unit/Core/Widget/AbstractWidgetViewHelperTest.php index 273015755e..5edbeb758a 100644 --- a/Neos.FluidAdaptor/Tests/Unit/Core/Widget/AbstractWidgetViewHelperTest.php +++ b/Neos.FluidAdaptor/Tests/Unit/Core/Widget/AbstractWidgetViewHelperTest.php @@ -11,6 +11,8 @@ * source code. */ +use Neos\FluidAdaptor\Core\Widget\AbstractWidgetController; +use Neos\FluidAdaptor\Core\Widget\AbstractWidgetViewHelper; use Neos\FluidAdaptor\Core\Widget\Exception\MissingControllerException; use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\AbstractNode; use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\RootNode; @@ -52,25 +54,51 @@ class AbstractWidgetViewHelperTest extends \Neos\Flow\Tests\UnitTestCase */ protected $request; + /** + * @var AbstractWidgetController|__anonymous@2351 + */ + protected $testWidgetControllerClass; + /** */ protected function setUp(): void { - $this->viewHelper = $this->getAccessibleMock(\Neos\FluidAdaptor\Core\Widget\AbstractWidgetViewHelper::class, ['validateArguments', 'initialize', 'callRenderMethod', 'getWidgetConfiguration', 'getRenderingContext']); - $this->ajaxWidgetContextHolder = $this->createMock(\Neos\FluidAdaptor\Core\Widget\AjaxWidgetContextHolder::class); - $this->viewHelper->injectAjaxWidgetContextHolder($this->ajaxWidgetContextHolder); - $this->widgetContext = $this->createMock(\Neos\FluidAdaptor\Core\Widget\WidgetContext::class); - $this->viewHelper->injectWidgetContext($this->widgetContext); - $this->objectManager = $this->createMock(\Neos\Flow\ObjectManagement\ObjectManagerInterface::class); - $this->objectManager->expects(self::any())->method('get')->with(\Neos\FluidAdaptor\Core\Widget\WidgetContext::class)->will(self::returnValue($this->widgetContext)); - $this->viewHelper->injectObjectManager($this->objectManager); - + $this->objectManager->expects(self::any())->method('get')->with(\Neos\FluidAdaptor\Core\Widget\WidgetContext::class)->willReturn($this->widgetContext); $this->controllerContext = $this->getMockBuilder(\Neos\Flow\Mvc\Controller\ControllerContext::class)->disableOriginalConstructor()->getMock(); - $this->viewHelper->_set('controllerContext', $this->controllerContext); - + $this->testWidgetControllerClass = new class extends AbstractWidgetController { + }; + $testWidgetViewHelperClass = new class extends AbstractWidgetViewHelper { + public function setAjax(bool $ajax): void + { + $this->ajaxWidget = $ajax; + } + public function injectRenderingContext(RenderingContextInterface $renderingContext): void + { + $this->renderingContext = $renderingContext; + } + public function injectController($controller): void + { + $this->controller = $controller; + } + public function render(): string + { + return 'renderedResult'; + } + + public function initiateSubRequest(): void + { + parent::initiateSubRequest(); + } + }; + + $this->viewHelper = $testWidgetViewHelperClass; + $this->viewHelper->injectWidgetContext($this->widgetContext); + $this->viewHelper->injectController($this->testWidgetControllerClass); + $this->viewHelper->injectObjectManager($this->objectManager); + $this->viewHelper->injectAjaxWidgetContextHolder($this->ajaxWidgetContextHolder); $this->request = $this->getMockBuilder(\Neos\Flow\Mvc\ActionRequest::class)->disableOriginalConstructor()->getMock(); } @@ -79,6 +107,7 @@ protected function setUp(): void */ public function initializeArgumentsAndRenderCallsTheRightSequenceOfMethods() { + $this->widgetContext->expects(self::once())->method('setControllerObjectName')->with(get_class($this->testWidgetControllerClass)); $this->callViewHelper(); } @@ -87,10 +116,8 @@ public function initializeArgumentsAndRenderCallsTheRightSequenceOfMethods() */ public function initializeArgumentsAndRenderDoesNotStoreTheWidgetContextForStatelessWidgets() { - $this->viewHelper->_set('ajaxWidget', true); - $this->viewHelper->_set('storeConfigurationInSession', false); $this->ajaxWidgetContextHolder->expects(self::never())->method('store'); - + $this->widgetContext->expects(self::once())->method('setControllerObjectName')->with(get_class($this->testWidgetControllerClass)); $this->callViewHelper(); } @@ -99,9 +126,9 @@ public function initializeArgumentsAndRenderDoesNotStoreTheWidgetContextForState */ public function initializeArgumentsAndRenderStoresTheWidgetContextIfInAjaxMode() { - $this->viewHelper->_set('ajaxWidget', true); + $this->viewHelper->setAjax(true); $this->ajaxWidgetContextHolder->expects(self::once())->method('store')->with($this->widgetContext); - + $this->widgetContext->expects(self::once())->method('setControllerObjectName')->with(get_class($this->testWidgetControllerClass)); $this->callViewHelper(); } @@ -112,17 +139,8 @@ public function initializeArgumentsAndRenderStoresTheWidgetContextIfInAjaxMode() */ public function callViewHelper() { - $this->viewHelper->expects(self::any())->method('getWidgetConfiguration')->will(self::returnValue(['Some Widget Configuration'])); - $this->widgetContext->expects(self::once())->method('setNonAjaxWidgetConfiguration')->with(['Some Widget Configuration']); - + $this->widgetContext->expects(self::once())->method('setNonAjaxWidgetConfiguration')->with([]); $this->widgetContext->expects(self::once())->method('setWidgetIdentifier')->with(strtolower(str_replace('\\', '-', get_class($this->viewHelper)))); - - $this->viewHelper->_set('controller', new \stdClass()); - $this->widgetContext->expects(self::once())->method('setControllerObjectName')->with('stdClass'); - - $this->viewHelper->expects(self::once())->method('validateArguments'); - $this->viewHelper->expects(self::once())->method('initialize'); - $this->viewHelper->expects(self::once())->method('callRenderMethod')->will(self::returnValue('renderedResult')); $output = $this->viewHelper->initializeArgumentsAndRender(['arg1' => 'val1']); self::assertEquals('renderedResult', $output); } @@ -145,8 +163,7 @@ public function setChildNodesAddsChildNodesToWidgetContext() $rootNode->addChildNode($node3); $renderingContext = $this->createMock(RenderingContextInterface::class); - $this->viewHelper->_set('renderingContext', $renderingContext); - + $this->viewHelper->injectRenderingContext($renderingContext); $this->viewHelper->setChildNodes([$node1, $node2, $node3]); self::assertEquals($rootNode, $this->widgetContext->getViewHelperChildNodes()); @@ -159,8 +176,8 @@ public function initiateSubRequestThrowsExceptionIfControllerIsNoWidgetControlle { $this->expectException(MissingControllerException::class); $controller = $this->createMock(\Neos\Flow\Mvc\Controller\ControllerInterface::class); - $this->viewHelper->_set('controller', $controller); + $this->viewHelper->injectController($controller); - $this->viewHelper->_call('initiateSubRequest'); + $this->viewHelper->initiateSubRequest(); } } diff --git a/Neos.FluidAdaptor/Tests/Unit/View/Fixtures/TemplatePathsTestAccessor.php b/Neos.FluidAdaptor/Tests/Unit/View/Fixtures/TemplatePathsTestAccessor.php new file mode 100644 index 0000000000..a573151ec9 --- /dev/null +++ b/Neos.FluidAdaptor/Tests/Unit/View/Fixtures/TemplatePathsTestAccessor.php @@ -0,0 +1,25 @@ +expandGenericPathPattern($pattern, $patternReplacementVariables, $bubbleControllerAndSubpackage, $formatIsOptional); + }; + + $accessor = $accessor->bindTo($this->templatePaths, TemplatePaths::class); + + return $accessor($pattern, $patternReplacementVariables, $bubbleControllerAndSubpackage, $formatIsOptional); + } +} diff --git a/Neos.FluidAdaptor/Tests/Unit/View/StandaloneViewTest.php b/Neos.FluidAdaptor/Tests/Unit/View/StandaloneViewTest.php index f866cf119d..5d02b826d6 100644 --- a/Neos.FluidAdaptor/Tests/Unit/View/StandaloneViewTest.php +++ b/Neos.FluidAdaptor/Tests/Unit/View/StandaloneViewTest.php @@ -41,12 +41,11 @@ class StandaloneViewTest extends UnitTestCase protected function setUp(): void { - $this->standaloneView = $this->getAccessibleMock(\Neos\FluidAdaptor\View\StandaloneView::class, ['dummy']); - $this->mockRequest = $this->getMockBuilder(\Neos\Flow\Mvc\ActionRequest::class)->disableOriginalConstructor()->getMock(); - $this->mockControllerContext = $this->getMockBuilder(\Neos\Flow\Mvc\Controller\ControllerContext::class)->disableOriginalConstructor()->getMock(); - $this->mockControllerContext->expects(self::any())->method('getRequest')->will(self::returnValue($this->mockRequest)); - $this->inject($this->standaloneView, 'controllerContext', $this->mockControllerContext); + $this->standaloneView = new StandaloneView($this->mockRequest); +// $this->mockControllerContext = $this->getMockBuilder(\Neos\Flow\Mvc\Controller\ControllerContext::class)->disableOriginalConstructor()->getMock(); +// $this->mockControllerContext->expects(self::any())->method('getRequest')->will(self::returnValue($this->mockRequest)); +// $this->inject($this->standaloneView, 'controllerContext', $this->mockControllerContext); } /** @@ -59,7 +58,7 @@ public function getLayoutPathAndFilenameThrowsExceptionIfSpecifiedLayoutRootPath mkdir('vfs://MyLayouts'); \file_put_contents('vfs://MyLayouts/NotAFolder', 'foo'); $this->standaloneView->setLayoutRootPath('vfs://MyLayouts/NotAFolder'); - $this->standaloneView->getTemplatePaths()->getLayoutSource(); + $this->standaloneView->getRenderingContext()->getTemplatePaths()->getLayoutSource(); } /** @@ -71,7 +70,7 @@ public function getLayoutPathAndFilenameThrowsExceptionIfLayoutFileIsADirectory( vfsStreamWrapper::register(); mkdir('vfs://MyLayouts/NotAFile'); $this->standaloneView->setLayoutRootPath('vfs://MyLayouts'); - $this->standaloneView->getTemplatePaths()->getLayoutSource('NotAFile'); + $this->standaloneView->getRenderingContext()->getTemplatePaths()->getLayoutSource('NotAFile'); } /** @@ -84,7 +83,7 @@ public function getPartialPathAndFilenameThrowsExceptionIfSpecifiedPartialRootPa mkdir('vfs://MyPartials'); \file_put_contents('vfs://MyPartials/NotAFolder', 'foo'); $this->standaloneView->setPartialRootPath('vfs://MyPartials/NotAFolder'); - $this->standaloneView->getTemplatePaths()->getPartialSource('SomePartial'); + $this->standaloneView->getRenderingContext()->getTemplatePaths()->getPartialSource('SomePartial'); } /** @@ -96,6 +95,6 @@ public function getPartialPathAndFilenameThrowsExceptionIfPartialFileIsADirector vfsStreamWrapper::register(); mkdir('vfs://MyPartials/NotAFile'); $this->standaloneView->setPartialRootPath('vfs://MyPartials'); - $this->standaloneView->getTemplatePaths()->getPartialSource('NotAFile'); + $this->standaloneView->getRenderingContext()->getTemplatePaths()->getPartialSource('NotAFile'); } } diff --git a/Neos.FluidAdaptor/Tests/Unit/View/TemplatePathsTest.php b/Neos.FluidAdaptor/Tests/Unit/View/TemplatePathsTest.php index 25675dcd0c..a2a3284e7a 100644 --- a/Neos.FluidAdaptor/Tests/Unit/View/TemplatePathsTest.php +++ b/Neos.FluidAdaptor/Tests/Unit/View/TemplatePathsTest.php @@ -4,6 +4,7 @@ use GuzzleHttp\Psr7\ServerRequest; use GuzzleHttp\Psr7\Uri; use Neos\FluidAdaptor\View\Exception\InvalidTemplateResourceException; +use Neos\FluidAdaptor\Tests\Unit\View\Fixtures\TemplatePathsTestAccessor; use org\bovigo\vfs\vfsStreamWrapper; use Neos\Flow\Mvc\ActionRequest; use Neos\Flow\Mvc\Controller\ControllerContext; @@ -43,7 +44,11 @@ protected function setupMockControllerContextForPathResolving($packageKey, $subP return $mockControllerContext; } - public function expandGenericPathPatternDataProvider() + /** + * Test data provider + * @return array[] + */ + public function expandGenericPathPatternDataProvider(): array { return [ // bubbling controller & subpackage parts and optional format @@ -476,8 +481,8 @@ public function expandGenericPathPatternTests($package, $subPackage, $controller $options['layoutRootPaths'] = $layoutRootPaths; } - /** @var TemplatePaths $templatePaths */ - $templatePaths = $this->getAccessibleMock(TemplatePaths::class, ['dummy'], [$options], '', true); + $templatePaths = new TemplatePaths(); + $templatePaths->setOptions($options); $patternReplacementVariables = [ 'packageKey' => $package, 'subPackageKey' => $subPackage, @@ -485,7 +490,8 @@ public function expandGenericPathPatternTests($package, $subPackage, $controller 'format' => $format ]; - $actualResult = $templatePaths->_call('expandGenericPathPattern', $pattern, $patternReplacementVariables, $bubbleControllerAndSubpackage, $formatIsOptional); + $accessor = new TemplatePathsTestAccessor($templatePaths); + $actualResult = $accessor->expandGenericPathPattern($pattern, $patternReplacementVariables, $bubbleControllerAndSubpackage, $formatIsOptional); self::assertEquals($expectedResult, $actualResult); } @@ -498,11 +504,11 @@ public function expandGenericPathPatternWorksWithBubblingDisabledAndFormatNotOpt 'templateRootPaths' => ['Resources/Private/'] ]; - /** @var TemplatePaths $templatePaths */ - $templatePaths = $this->getAccessibleMock(TemplatePaths::class, null, [$options], '', true); - + $templatePaths = new TemplatePaths(); + $templatePaths->setOptions($options); $expected = ['Resources/Private/Templates/My/@action.html']; - $actual = $templatePaths->_call('expandGenericPathPattern', '@templateRoot/Templates/@subpackage/@controller/@action.@format', [ + $accessor = new TemplatePathsTestAccessor($templatePaths); + $actual = $accessor->expandGenericPathPattern('@templateRoot/Templates/@subpackage/@controller/@action.@format', [ 'subPackageKey' => null, 'controllerName' => 'My', 'format' => 'html' @@ -519,10 +525,10 @@ public function expandGenericPathPatternWorksWithSubpackageAndBubblingDisabledAn 'templateRootPaths' => ['Resources/Private/'] ]; - /** @var TemplatePaths $templatePaths */ - $templatePaths = $this->getAccessibleMock(TemplatePaths::class, null, [$options], '', true); - - $actual = $templatePaths->_call('expandGenericPathPattern', '@templateRoot/Templates/@subpackage/@controller/@action.@format', [ + $templatePaths = new TemplatePaths(); + $templatePaths->setOptions($options); + $accessor = new TemplatePathsTestAccessor($templatePaths); + $actual = $accessor->expandGenericPathPattern('@templateRoot/Templates/@subpackage/@controller/@action.@format', [ 'subPackageKey' => 'MySubPackage', 'controllerName' => 'My', 'format' => 'html' @@ -543,10 +549,10 @@ public function expandGenericPathPatternWorksWithSubpackageAndBubblingDisabledAn 'templateRootPaths' => ['Resources/Private/'] ]; - /** @var TemplatePaths $templatePaths */ - $templatePaths = $this->getAccessibleMock(TemplatePaths::class, null, [$options], '', true); - - $actual = $templatePaths->_call('expandGenericPathPattern', '@templateRoot/Templates/@subpackage/@controller/@action.@format', [ + $templatePaths = new TemplatePaths(); + $templatePaths->setOptions($options); + $accessor = new TemplatePathsTestAccessor($templatePaths); + $actual = $accessor->expandGenericPathPattern('@templateRoot/Templates/@subpackage/@controller/@action.@format', [ 'subPackageKey' => 'MySubPackage', 'controllerName' => 'My', 'format' => 'html' @@ -568,10 +574,10 @@ public function expandGenericPathPatternWorksWithSubpackageAndBubblingEnabledAnd 'templateRootPaths' => ['Resources/Private/'] ]; - /** @var TemplatePaths $templatePaths */ - $templatePaths = $this->getAccessibleMock(TemplatePaths::class, null, [$options], '', true); - - $actual = $templatePaths->_call('expandGenericPathPattern', '@templateRoot/Templates/@subpackage/@controller/@action.@format', [ + $templatePaths = new TemplatePaths(); + $templatePaths->setOptions($options); + $accessor = new TemplatePathsTestAccessor($templatePaths); + $actual = $accessor->expandGenericPathPattern('@templateRoot/Templates/@subpackage/@controller/@action.@format', [ 'subPackageKey' => 'MySubPackage', 'controllerName' => 'My', 'format' => 'html' @@ -597,16 +603,9 @@ public function pathToPartialIsResolvedCorrectly() mkdir('vfs://MyPartials'); \file_put_contents('vfs://MyPartials/SomePartial', 'contentsOfSomePartial'); - $paths = [ - 'vfs://NonExistentDir/UnknowFile.html', - 'vfs://MyPartials/SomePartial.html', - 'vfs://MyPartials/SomePartial' - ]; - - $templatePaths = $this->getAccessibleMock(TemplatePaths::class, ['expandGenericPathPattern'], [[ - 'partialPathAndFilenamePattern' => '@partialRoot/@subpackage/@partial.@format' - ]], '', true); - $templatePaths->expects(self::once())->method('expandGenericPathPattern')->with('@partialRoot/@subpackage/@partial.@format', ['partial' => 'SomePartial', 'format' => 'html'], true, true)->will(self::returnValue($paths)); + $templatePaths = new TemplatePaths(); + $templatePaths->setOption('partialPathAndFilenamePattern', '@partialRoot/@subpackage/@partial.@format'); + $templatePaths->setPatternReplacementVariables(['partialRoot' => 'vfs://MyPartials']); self::assertSame('contentsOfSomePartial', $templatePaths->getPartialSource('SomePartial')); } @@ -620,24 +619,17 @@ public function getTemplateSourceChecksDifferentPathPatternsAndReturnsTheFirstPa mkdir('vfs://MyTemplates'); file_put_contents('vfs://MyTemplates/MyCoolAction.html', 'contentsOfMyCoolAction'); - $paths = [ - 'vfs://NonExistentDir/UnknownFile.html', - 'vfs://MyTemplates/@action.html', - 'vfs://MyTemplates/MyCoolAction.html' - ]; + $templatePaths = new TemplatePaths(); + $templatePaths->setOptions([ + 'templatePathAndFilenamePattern' => '@templateRoot/@subpackage/@controller/@action.@format' + ]); - $templatePaths = $this->getAccessibleMock(TemplatePaths::class, ['expandGenericPathPattern'], [ - [ - 'templatePathAndFilenamePattern' => '@templateRoot/@subpackage/@controller/@action.@format' - ] - ], '', true); - - $templatePaths->expects(self::once())->method('expandGenericPathPattern')->with('@templateRoot/@subpackage/@controller/@action.@format', [ + $templatePaths->setPatternReplacementVariables([ + 'templateRoot' => 'vfs://MyTemplates', 'controllerName' => '', 'action' => 'MyCoolAction', 'format' => 'html' - ], false, false)->will(self::returnValue($paths)); - + ]); self::assertSame('contentsOfMyCoolAction', $templatePaths->getTemplateSource('', 'myCoolAction')); } @@ -653,18 +645,14 @@ public function getTemplatePathAndFilenameThrowsExceptionIfNoPathCanBeResolved() 'vfs://NonExistentDir/AnotherUnknownFile.html', ]; - $templatePaths = $this->getAccessibleMock(TemplatePaths::class, ['expandGenericPathPattern'], [ - [ - 'templatePathAndFilenamePattern' => '@templateRoot/@subpackage/@controller/@action.@format' - ] - ], '', true); - - $templatePaths->expects(self::once())->method('expandGenericPathPattern')->with('@templateRoot/@subpackage/@controller/@action.@format', [ + $templatePaths = new TemplatePaths(); + $templatePaths->setOption('templatePathAndFilenamePattern', '@templateRoot/@subpackage/@controller/@action.@format'); + $templatePaths->setPatternReplacementVariables([ + 'templateRoot' => 'vfs://MyTemplates', 'controllerName' => '', 'action' => 'MyCoolAction', 'format' => 'html' - ], false, false)->will(self::returnValue($paths)); - + ]); $templatePaths->getTemplateSource('', 'myCoolAction'); } @@ -681,17 +669,8 @@ public function getTemplatePathAndFilenameThrowsExceptionIfResolvedPathPointsToA 'vfs://MyTemplates/NotAFile' ]; - $templatePaths = $this->getAccessibleMock(TemplatePaths::class, ['expandGenericPathPattern'], [ - [ - 'templatePathAndFilenamePattern' => '@templateRoot/@subpackage/@controller/@action.@format' - ] - ], '', true); - - $templatePaths->expects(self::once())->method('expandGenericPathPattern')->with('@templateRoot/@subpackage/@controller/@action.@format', [ - 'controllerName' => '', - 'action' => 'MyCoolAction', - 'format' => 'html' - ], false, false)->will(self::returnValue($paths)); + $templatePaths = new TemplatePaths(); + $templatePaths->setOption('templatePathAndFilenamePattern', '@templateRoot/@subpackage/@controller/@action.@format'); $templatePaths->getTemplateSource('', 'myCoolAction'); } @@ -705,9 +684,10 @@ public function resolveTemplatePathAndFilenameReturnsTheExplicitlyConfiguredTemp mkdir('vfs://MyTemplates'); file_put_contents('vfs://MyTemplates/MyCoolAction.html', 'contentsOfMyCoolAction'); - $templatePaths = $this->getAccessibleMock(TemplatePaths::class, ['dummy'], [['templatePathAndFilename' => 'vfs://MyTemplates/MyCoolAction.html']]); + $templatePaths = new TemplatePaths(); + $templatePaths->setOptions(['templatePathAndFilename' => 'vfs://MyTemplates/MyCoolAction.html']); - self::assertSame('contentsOfMyCoolAction', $templatePaths->_call('getTemplateSource')); + self::assertSame('contentsOfMyCoolAction', $templatePaths->getTemplateSource()); } /** @@ -717,22 +697,9 @@ public function getLayoutPathAndFilenameThrowsExceptionIfNoPathCanBeResolved() { $this->expectException(InvalidTemplateResourceException::class); vfsStreamWrapper::register(); - $paths = [ - 'vfs://NonExistentDir/UnknownFile.html', - 'vfs://NonExistentDir/AnotherUnknownFile.html', - ]; - - /** @var TemplatePaths $templatePaths */ - $templatePaths = $this->getAccessibleMock(TemplatePaths::class, ['expandGenericPathPattern'], [ - [ - 'layoutPathAndFilenamePattern' => '@layoutRoot/@layout.@format' - ] - ], '', true); - $templatePaths->expects(self::once())->method('expandGenericPathPattern')->with('@layoutRoot/@layout.@format', [ - 'layout' => 'Default', - 'format' => 'html' - ], true, true)->will(self::returnValue($paths)); + $templatePaths = new TemplatePaths(); + $templatePaths->setOption('templatePathAndFilenamePattern', '@layoutRoot/@layout.@format'); $templatePaths->getLayoutSource(); } @@ -745,22 +712,11 @@ public function getLayoutPathAndFilenameThrowsExceptionIfResolvedPathPointsToADi $this->expectException(InvalidTemplateResourceException::class); vfsStreamWrapper::register(); mkdir('vfs://MyTemplates/NotAFile'); - $paths = [ - 'vfs://NonExistentDir/UnknownFile.html', - 'vfs://MyTemplates/NotAFile' - ]; - - /** @var TemplatePaths $templatePaths */ - $templatePaths = $this->getAccessibleMock(TemplatePaths::class, ['expandGenericPathPattern'], [ - [ - 'layoutPathAndFilenamePattern' => '@layoutRoot/@layout.@format' - ] - ], '', true); - $templatePaths->expects(self::once())->method('expandGenericPathPattern')->with('@layoutRoot/@layout.@format', [ - 'layout' => 'SomeLayout', - 'format' => 'html' - ], true, true)->will(self::returnValue($paths)); + $templatePaths = new TemplatePaths(); + $templatePaths->setOptions([ + 'layoutPathAndFilenamePattern' => '@layoutRoot/@layout.@format' + ]); $templatePaths->getLayoutSource('SomeLayout'); } @@ -772,22 +728,11 @@ public function getPartialPathAndFilenameThrowsExceptionIfNoPathCanBeResolved() { $this->expectException(InvalidTemplateResourceException::class); vfsStreamWrapper::register(); - $paths = [ - 'vfs://NonExistentDir/UnknownFile.html', - 'vfs://NonExistentDir/AnotherUnknownFile.html', - ]; - - /** @var TemplatePaths $templatePaths */ - $templatePaths = $this->getAccessibleMock(TemplatePaths::class, ['expandGenericPathPattern'], [ - [ - 'partialPathAndFilenamePattern' => '@partialRoot/@subpackage/@partial.@format' - ] - ], '', true); - $templatePaths->expects(self::once())->method('expandGenericPathPattern')->with('@partialRoot/@subpackage/@partial.@format', [ - 'partial' => 'SomePartial', - 'format' => 'html' - ], true, true)->will(self::returnValue($paths)); + $templatePaths = new TemplatePaths(); + $templatePaths->setOptions([ + 'partialPathAndFilenamePattern' => '@partialRoot/@subpackage/@partial.@format' + ]); $templatePaths->getPartialSource('SomePartial'); } @@ -800,22 +745,11 @@ public function getPartialPathAndFilenameThrowsExceptionIfResolvedPathPointsToAD $this->expectException(InvalidTemplateResourceException::class); vfsStreamWrapper::register(); mkdir('vfs://MyTemplates/NotAFile'); - $paths = [ - 'vfs://NonExistentDir/UnknownFile.html', - 'vfs://MyTemplates/NotAFile' - ]; - - /** @var TemplatePaths $templatePaths */ - $templatePaths = $this->getAccessibleMock(TemplatePaths::class, ['expandGenericPathPattern'], [ - [ - 'partialPathAndFilenamePattern' => '@partialRoot/@subpackage/@partial.@format' - ] - ], '', true); - $templatePaths->expects(self::once())->method('expandGenericPathPattern')->with('@partialRoot/@subpackage/@partial.@format', [ - 'partial' => 'SomePartial', - 'format' => 'html' - ], true, true)->will(self::returnValue($paths)); + $templatePaths = new TemplatePaths(); + $templatePaths->setOptions([ + 'partialPathAndFilenamePattern' => '@partialRoot/@subpackage/@partial.@format' + ]); $templatePaths->getPartialSource('SomePartial'); } diff --git a/Neos.FluidAdaptor/Tests/Unit/View/TemplateViewTest.php b/Neos.FluidAdaptor/Tests/Unit/View/TemplateViewTest.php index b8d741b72a..b1b2d64301 100644 --- a/Neos.FluidAdaptor/Tests/Unit/View/TemplateViewTest.php +++ b/Neos.FluidAdaptor/Tests/Unit/View/TemplateViewTest.php @@ -62,7 +62,7 @@ public function getTemplateRootPathsReturnsUserSpecifiedTemplatePaths() $templateRootPaths = ['/foo/bar/', 'baz/']; $templateView->setOption('templateRootPaths', $templateRootPaths); - $actual = $templateView->getTemplatePaths()->getTemplateRootPaths(); + $actual = $templateView->getRenderingContext()->getTemplatePaths()->getTemplateRootPaths(); self::assertEquals($templateRootPaths, $actual, 'A set template root path was not returned correctly.'); } @@ -76,7 +76,7 @@ public function getPartialRootPathsReturnsUserSpecifiedPartialPath() $partialRootPaths = ['/foo/bar/', 'baz/']; $templateView->setOption('partialRootPaths', $partialRootPaths); - $actual = $templateView->getTemplatePaths()->getPartialRootPaths(); + $actual = $templateView->getRenderingContext()->getTemplatePaths()->getPartialRootPaths(); self::assertEquals($partialRootPaths, $actual, 'A set partial root path was not returned correctly.'); } @@ -90,7 +90,7 @@ public function getLayoutRootPathsReturnsUserSpecifiedPartialPaths() $layoutRootPaths = ['/foo/bar/', 'baz/']; $templateView->setOption('layoutRootPaths', $layoutRootPaths); - $actual = $templateView->getTemplatePaths()->getLayoutRootPaths(); + $actual = $templateView->getRenderingContext()->getTemplatePaths()->getLayoutRootPaths(); self::assertEquals($layoutRootPaths, $actual, 'A set layout root path was not returned correctly.'); } } diff --git a/Neos.FluidAdaptor/composer.json b/Neos.FluidAdaptor/composer.json index aa1350940e..e19adeda67 100644 --- a/Neos.FluidAdaptor/composer.json +++ b/Neos.FluidAdaptor/composer.json @@ -11,7 +11,7 @@ "neos/cache": "self.version", "neos/utility-files": "self.version", "neos/utility-objecthandling": "self.version", - "typo3fluid/fluid": "^2.8.0", + "typo3fluid/fluid": "^4.2.0", "psr/log": "^2.0 || ^3.0" }, "autoload": { diff --git a/Neos.Utility.ObjectHandling/Tests/Unit/ObjectAccessTest.php b/Neos.Utility.ObjectHandling/Tests/Unit/ObjectAccessTest.php index 1ed54a7d1f..2140dda444 100644 --- a/Neos.Utility.ObjectHandling/Tests/Unit/ObjectAccessTest.php +++ b/Neos.Utility.ObjectHandling/Tests/Unit/ObjectAccessTest.php @@ -42,7 +42,9 @@ protected function setUp(): void $this->dummyObject = new DummyClassWithGettersAndSetters(); $this->dummyObject->setProperty('string1'); $this->dummyObject->setAnotherProperty(42); + $original = error_reporting(E_ALL & ~E_DEPRECATED); $this->dummyObject->shouldNotBePickedUp = true; + error_reporting($original); } /** @@ -560,7 +562,7 @@ public function getPropertyUsingDirectAccessWorksOnPrivatePropertyOfProxyParent( public function setPropertyUsingDirectAccessWorksOnPrivatePropertyOfProxyParent() { $proxyObject = new ProxiedClassWithPrivateProperty(); - + ObjectAccess::setProperty($proxyObject, 'property', 'changed', true); self::assertEquals('changed', $proxyObject->getProperty()); } diff --git a/composer.json b/composer.json index 9bf75ac0c7..0b6b3fa6af 100644 --- a/composer.json +++ b/composer.json @@ -46,7 +46,7 @@ "symfony/console": "^5.1||^6.0", "composer/composer": "^2.7.7", "egulias/email-validator": "^3.0||^4.0", - "typo3fluid/fluid": "^2.8.0", + "typo3fluid/fluid": "^4.2.0", "guzzlehttp/psr7": "^1.8.4 || ^2.1.1", "ext-mbstring": "*" },