diff --git a/Neos.Flow.Log/Classes/Backend/AbstractBackend.php b/Neos.Flow.Log/Classes/Backend/AbstractBackend.php index 6279d6cd85..1e879d90db 100644 --- a/Neos.Flow.Log/Classes/Backend/AbstractBackend.php +++ b/Neos.Flow.Log/Classes/Backend/AbstractBackend.php @@ -42,7 +42,7 @@ abstract class AbstractBackend implements BackendInterface */ public function __construct($options = []) { - if (is_array($options) || $options instanceof \ArrayAccess) { + if (is_iterable($options)) { foreach ($options as $optionKey => $optionValue) { $methodName = 'set' . ucfirst($optionKey); if (method_exists($this, $methodName)) { diff --git a/Neos.Flow.Log/Classes/Backend/AnsiConsoleBackend.php b/Neos.Flow.Log/Classes/Backend/AnsiConsoleBackend.php index 5749b5df81..30784f9aef 100644 --- a/Neos.Flow.Log/Classes/Backend/AnsiConsoleBackend.php +++ b/Neos.Flow.Log/Classes/Backend/AnsiConsoleBackend.php @@ -40,7 +40,7 @@ class AnsiConsoleBackend extends ConsoleBackend const END = "\033[0m"; /** - * @var array + * @var array */ protected $tagFormats = []; @@ -75,12 +75,7 @@ public function open(): void /** * Appends the given message along with the additional information into the log. * - * @param string $message - * @param int $severity - * @param array $additionalData - * @param string $packageKey - * @param string $className - * @param string $methodName + * @param array|null $additionalData * @return void */ public function append(string $message, int $severity = LOG_INFO, $additionalData = null, ?string $packageKey = null, ?string $className = null, ?string $methodName = null): void @@ -118,7 +113,7 @@ protected function formatOutput($output) } else { return str_replace('|', $matches[3], $format); } - }, $output); + }, $output) ?: ''; } while ($lastOutput !== $output); return $output; } @@ -126,7 +121,7 @@ protected function formatOutput($output) /** * @param boolean $disableAnsi */ - public function setDisableAnsi($disableAnsi) + public function setDisableAnsi($disableAnsi): void { $this->disableAnsi = $disableAnsi; } diff --git a/Neos.Flow.Log/Classes/Backend/ConsoleBackend.php b/Neos.Flow.Log/Classes/Backend/ConsoleBackend.php index def5dd734e..1398b288c9 100644 --- a/Neos.Flow.Log/Classes/Backend/ConsoleBackend.php +++ b/Neos.Flow.Log/Classes/Backend/ConsoleBackend.php @@ -25,7 +25,7 @@ class ConsoleBackend extends AbstractBackend { /** * An array of severity labels, indexed by their integer constant - * @var array + * @var array */ protected $severityLabels; @@ -61,10 +61,11 @@ public function open(): void LOG_DEBUG => 'DEBUG ', ]; - $this->streamHandle = fopen('php://' . $this->streamName, 'w'); - if (!is_resource($this->streamHandle)) { + $streamHandle = fopen('php://' . $this->streamName, 'w'); + if (!is_resource($streamHandle)) { throw new CouldNotOpenResourceException('Could not open stream "' . $this->streamName . '" for write access.', 1310986609); } + $this->streamHandle = $streamHandle; } /** diff --git a/Neos.Flow.Log/Classes/Backend/FileBackend.php b/Neos.Flow.Log/Classes/Backend/FileBackend.php index affc67f73e..fecc2a7978 100644 --- a/Neos.Flow.Log/Classes/Backend/FileBackend.php +++ b/Neos.Flow.Log/Classes/Backend/FileBackend.php @@ -27,7 +27,7 @@ class FileBackend extends AbstractBackend { /** * An array of severity labels, indexed by their integer constant - * @var array + * @var array */ protected $severityLabels; @@ -192,6 +192,9 @@ public function open(): void protected function rotateLogFile(): void { $lockResource = fopen($this->logFileUrl . '.lock', 'w+'); + if ($lockResource === false) { + throw new \RuntimeException(sprintf('Fatal: cannot open/create file "%s".', $this->logFileUrl . '.lock'), 1765550110); + } $exclusiveNonBlockingLockResult = flock($lockResource, LOCK_EX | LOCK_NB); if ($exclusiveNonBlockingLockResult === false) { diff --git a/Neos.Flow.Log/Classes/PlainTextFormatter.php b/Neos.Flow.Log/Classes/PlainTextFormatter.php index 0a15efb126..4e00147030 100644 --- a/Neos.Flow.Log/Classes/PlainTextFormatter.php +++ b/Neos.Flow.Log/Classes/PlainTextFormatter.php @@ -22,8 +22,8 @@ public function __construct($variable) } /** - * @param $spaces - * @return string + * @param int $spaces + * @return ?string */ public function format($spaces = 4) { diff --git a/Neos.Flow.Log/Classes/Psr/Logger.php b/Neos.Flow.Log/Classes/Psr/Logger.php index 6ebad73f56..c1a18be6f8 100644 --- a/Neos.Flow.Log/Classes/Psr/Logger.php +++ b/Neos.Flow.Log/Classes/Psr/Logger.php @@ -45,7 +45,7 @@ class Logger implements LoggerInterface /** * Constructs the PSR-3 Logger. * - * @param iterable $backends + * @param iterable $backends */ public function __construct(iterable $backends) { @@ -61,7 +61,7 @@ public function __construct(iterable $backends) /** * @param mixed $level * @param string|\Stringable $message - * @param array $context + * @param array $context * @api */ public function log($level, string|\Stringable $message, array $context = []): void @@ -80,8 +80,8 @@ public function log($level, string|\Stringable $message, array $context = []): v } /** - * @param array $context - * @return array list of packageKey, className and methodName either string or null + * @param array $context + * @return array list of packageKey, className and methodName either string or null */ protected function extractLegacyDataFromContext(array $context): array { @@ -93,8 +93,8 @@ protected function extractLegacyDataFromContext(array $context): array } /** - * @param array $context - * @return array + * @param array $context + * @return array */ protected function removeLegacyDataFromContext(array $context): array { diff --git a/Neos.Flow/Classes/Reflection/ReflectionService.php b/Neos.Flow/Classes/Reflection/ReflectionService.php index 36f7b8b76a..e7f786c605 100644 --- a/Neos.Flow/Classes/Reflection/ReflectionService.php +++ b/Neos.Flow/Classes/Reflection/ReflectionService.php @@ -325,8 +325,9 @@ public function getAllImplementationClassNamesForInterface(string $interfaceName * Searches for and returns all names of classes inheriting the specified class. * If no class inheriting the given class was found, an empty array is returned. * - * @param class-string $className - * @return array + * @template T of object + * @param class-string $className + * @return list> * @throws ClassLoadingForReflectionFailedException * @throws InvalidClassException * @throws \ReflectionException diff --git a/Neos.FluidAdaptor/Classes/Core/Cache/CacheAdaptor.php b/Neos.FluidAdaptor/Classes/Core/Cache/CacheAdaptor.php index 43bb16e5a4..305c09501e 100644 --- a/Neos.FluidAdaptor/Classes/Core/Cache/CacheAdaptor.php +++ b/Neos.FluidAdaptor/Classes/Core/Cache/CacheAdaptor.php @@ -49,6 +49,7 @@ public function get($name) * * @param string $name * @param string $value + * @return void */ public function set($name, $value) { diff --git a/Neos.FluidAdaptor/Classes/Core/Parser/Interceptor/ResourceInterceptor.php b/Neos.FluidAdaptor/Classes/Core/Parser/Interceptor/ResourceInterceptor.php index 286870a6ac..9334df24ad 100644 --- a/Neos.FluidAdaptor/Classes/Core/Parser/Interceptor/ResourceInterceptor.php +++ b/Neos.FluidAdaptor/Classes/Core/Parser/Interceptor/ResourceInterceptor.php @@ -97,7 +97,7 @@ public function process(NodeInterface $node, $interceptorPosition, ParsingState if (strpos($node->getText(), 'Public/') === false) { return $node; } - $textParts = preg_split(self::PATTERN_SPLIT_AT_RESOURCE_URIS, $node->getText(), -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); + $textParts = preg_split(self::PATTERN_SPLIT_AT_RESOURCE_URIS, $node->getText(), -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) ?: []; $node = new RootNode(); foreach ($textParts as $part) { $matches = []; @@ -109,7 +109,7 @@ public function process(NodeInterface $node, $interceptorPosition, ParsingState if ($this->defaultPackageKey !== null) { $arguments['package'] = new TextNode($this->defaultPackageKey); } - if (isset($matches['Package']) && FlowPackageKey::isPackageKeyValid($matches['Package'])) { + if (FlowPackageKey::isPackageKeyValid($matches['Package'])) { $arguments['package'] = new TextNode($matches['Package']); } @@ -127,7 +127,7 @@ public function process(NodeInterface $node, $interceptorPosition, ParsingState /** * This interceptor wants to hook into text nodes. * - * @return array Array of INTERCEPT_* constants + * @return array Array of INTERCEPT_* constants */ public function getInterceptionPoints() { diff --git a/Neos.FluidAdaptor/Classes/Core/Parser/SyntaxTree/Expression/LegacyNamespaceExpressionNode.php b/Neos.FluidAdaptor/Classes/Core/Parser/SyntaxTree/Expression/LegacyNamespaceExpressionNode.php index 1af2886355..cd63f4f625 100644 --- a/Neos.FluidAdaptor/Classes/Core/Parser/SyntaxTree/Expression/LegacyNamespaceExpressionNode.php +++ b/Neos.FluidAdaptor/Classes/Core/Parser/SyntaxTree/Expression/LegacyNamespaceExpressionNode.php @@ -24,14 +24,14 @@ class LegacyNamespaceExpressionNode extends AbstractExpressionNode implements Ex * Pattern which detects namespace declarations made inline. * syntax, e.g. {namespace neos=TYPO3\Neos\ViewHelpers}. */ - public static $detectionExpression = '/{namespace\\s*([a-z0-9]+)\\s*=\\s*([a-z0-9_\\\\]+)\\s*}/i'; + public static string $detectionExpression = '/{namespace\\s*([a-z0-9]+)\\s*=\\s*([a-z0-9_\\\\]+)\\s*}/i'; /** * Evaluates the expression stored in this node, in the context of $renderingcontext. * * @param RenderingContextInterface $renderingContext * @param string $expression - * @param array $matches + * @param array $matches * @return mixed */ public static function evaluateExpression(RenderingContextInterface $renderingContext, $expression, array $matches) diff --git a/Neos.FluidAdaptor/Classes/Core/Parser/SyntaxTree/ResourceUriNode.php b/Neos.FluidAdaptor/Classes/Core/Parser/SyntaxTree/ResourceUriNode.php index db44103330..df88c3dfdc 100644 --- a/Neos.FluidAdaptor/Classes/Core/Parser/SyntaxTree/ResourceUriNode.php +++ b/Neos.FluidAdaptor/Classes/Core/Parser/SyntaxTree/ResourceUriNode.php @@ -35,18 +35,18 @@ class ResourceUriNode extends ViewHelperNode protected $viewHelperResolver; /** - * @var string + * @var class-string */ protected $viewHelperClassName = ResourceViewHelper::class; /** * @param ViewHelperResolver $viewHelperResolver + * @return void */ public function injectViewHelperResolver(ViewHelperResolver $viewHelperResolver) { $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); } diff --git a/Neos.FluidAdaptor/Classes/Core/Parser/TemplateParser.php b/Neos.FluidAdaptor/Classes/Core/Parser/TemplateParser.php index 1ad1054885..a75e2989bd 100644 --- a/Neos.FluidAdaptor/Classes/Core/Parser/TemplateParser.php +++ b/Neos.FluidAdaptor/Classes/Core/Parser/TemplateParser.php @@ -16,6 +16,7 @@ public function isEscapingEnabled() /** * @param boolean $escapingEnabled + * @return void */ public function setEscapingEnabled($escapingEnabled) { diff --git a/Neos.FluidAdaptor/Classes/Core/Parser/TemplateProcessor/EscapingFlagProcessor.php b/Neos.FluidAdaptor/Classes/Core/Parser/TemplateProcessor/EscapingFlagProcessor.php index fbdc9a72a1..d53ad3264d 100644 --- a/Neos.FluidAdaptor/Classes/Core/Parser/TemplateProcessor/EscapingFlagProcessor.php +++ b/Neos.FluidAdaptor/Classes/Core/Parser/TemplateProcessor/EscapingFlagProcessor.php @@ -25,10 +25,11 @@ class EscapingFlagProcessor implements TemplateProcessorInterface */ protected $renderingContext; - public static $SCAN_PATTERN_ESCAPINGMODIFIER = '/{escapingEnabled\s*=\s*(?Ptrue|false)\s*}/i'; + public static string $SCAN_PATTERN_ESCAPINGMODIFIER = '/{escapingEnabled\s*=\s*(?Ptrue|false)\s*}/i'; /** * @param RenderingContextInterface $renderingContext + * @return void */ public function setRenderingContext(RenderingContextInterface $renderingContext) { @@ -56,7 +57,7 @@ public function preProcessSource($templateSource) if (strtolower($matches[0]['enabled']) === 'false') { $this->renderingContext->getTemplateParser()->setEscapingEnabled(false); } - $templateSource = preg_replace(self::$SCAN_PATTERN_ESCAPINGMODIFIER, '', $templateSource); + $templateSource = preg_replace(self::$SCAN_PATTERN_ESCAPINGMODIFIER, '', $templateSource) ?: ''; return $templateSource; } diff --git a/Neos.FluidAdaptor/Classes/Core/Parser/TemplateProcessor/NamespaceDetectionTemplateProcessor.php b/Neos.FluidAdaptor/Classes/Core/Parser/TemplateProcessor/NamespaceDetectionTemplateProcessor.php index b6c18f2664..3c813c0c01 100644 --- a/Neos.FluidAdaptor/Classes/Core/Parser/TemplateProcessor/NamespaceDetectionTemplateProcessor.php +++ b/Neos.FluidAdaptor/Classes/Core/Parser/TemplateProcessor/NamespaceDetectionTemplateProcessor.php @@ -29,7 +29,7 @@ class NamespaceDetectionTemplateProcessor extends FluidNamespaceDetectionTemplat /** * Extension of the default pattern for dynamic tags including namespaces with uppercase letters. */ - public static $EXTENDED_SPLIT_PATTERN_TEMPLATE_DYNAMICTAGS = '/ + public static string $EXTENDED_SPLIT_PATTERN_TEMPLATE_DYNAMICTAGS = '/ ( (?: <\/? # Start dynamic tags (?:(?:[a-zA-Z0-9\\.]*):[a-zA-Z0-9\\.]+) # A tag consists of the namespace prefix and word characters @@ -75,7 +75,7 @@ public function preProcessSource($templateSource) */ public function protectCDataSectionsFromParser(string $templateSource) { - $parts = preg_split('/(\<\!\[CDATA\[|\]\]\>)/', $templateSource, -1, PREG_SPLIT_DELIM_CAPTURE); + $parts = preg_split('/(\<\!\[CDATA\[|\]\]\>)/', $templateSource, -1, PREG_SPLIT_DELIM_CAPTURE) ?: []; $balance = 0; $content = ''; $resultingParts = []; @@ -127,7 +127,7 @@ public function protectCDataSectionsFromParser(string $templateSource) public function throwExceptionsForUnhandledNamespaces(string $templateSource): void { $viewHelperResolver = $this->renderingContext->getViewHelperResolver(); - $splitTemplate = preg_split(static::$EXTENDED_SPLIT_PATTERN_TEMPLATE_DYNAMICTAGS, $templateSource, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + $splitTemplate = preg_split(static::$EXTENDED_SPLIT_PATTERN_TEMPLATE_DYNAMICTAGS, $templateSource, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY) ?: []; foreach ($splitTemplate as $templateElement) { if (preg_match(Patterns::$SCAN_PATTERN_TEMPLATE_VIEWHELPERTAG, $templateElement, $matchedVariables) > 0) { if (!$viewHelperResolver->isNamespaceValidOrIgnored($matchedVariables['NamespaceIdentifier'])) { @@ -148,11 +148,9 @@ public function throwExceptionsForUnhandledNamespaces(string $templateSource): v foreach ($sections as $section) { if (preg_match(Patterns::$SCAN_PATTERN_SHORTHANDSYNTAX_OBJECTACCESSORS, $section, $matchedVariables) > 0) { preg_match_all(Patterns::$SPLIT_PATTERN_SHORTHANDSYNTAX_VIEWHELPER, $section, $shorthandViewHelpers, PREG_SET_ORDER); - if (is_array($shorthandViewHelpers) === true) { - foreach ($shorthandViewHelpers as $shorthandViewHelper) { - if (!$viewHelperResolver->isNamespaceValidOrIgnored($shorthandViewHelper['NamespaceIdentifier'])) { - throw new UnknownNamespaceException('Unknown Namespace: ' . $shorthandViewHelper['NamespaceIdentifier']); - } + foreach ($shorthandViewHelpers as $shorthandViewHelper) { + if (!$viewHelperResolver->isNamespaceValidOrIgnored($shorthandViewHelper['NamespaceIdentifier'])) { + throw new UnknownNamespaceException('Unknown Namespace: ' . $shorthandViewHelper['NamespaceIdentifier']); } } } diff --git a/Neos.FluidAdaptor/Classes/Core/Rendering/RenderingContext.php b/Neos.FluidAdaptor/Classes/Core/Rendering/RenderingContext.php index 3c68fb552b..2df3c433fc 100644 --- a/Neos.FluidAdaptor/Classes/Core/Rendering/RenderingContext.php +++ b/Neos.FluidAdaptor/Classes/Core/Rendering/RenderingContext.php @@ -25,6 +25,7 @@ use Neos\FluidAdaptor\Core\ViewHelper\ViewHelperResolver; use Neos\FluidAdaptor\View\TemplatePaths; use TYPO3Fluid\Fluid\Core\Parser\Configuration; +use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\Expression\AbstractExpressionNode; use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\Expression\CastingExpressionNode; use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\Expression\MathExpressionNode; use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\Expression\TernaryExpressionNode; @@ -42,7 +43,7 @@ class RenderingContext extends FluidRenderingContext implements FlowAwareRenderi * which will be consulted when an expression does not match * any built-in parser expression types. * - * @var array + * @var array> */ protected $expressionNodeTypes = [ LegacyNamespaceExpressionNode::class, @@ -81,7 +82,7 @@ class RenderingContext extends FluidRenderingContext implements FlowAwareRenderi /** * RenderingContext constructor. * - * @param array $options + * @param array $options */ public function __construct(array $options = []) { @@ -99,6 +100,7 @@ public function __construct(array $options = []) /** * @param ObjectManagerInterface $objectManager + * @return void */ public function injectObjectManager(ObjectManagerInterface $objectManager) { @@ -116,7 +118,7 @@ public function getControllerContext() /** * @param ControllerContext $controllerContext */ - public function setControllerContext($controllerContext) + public function setControllerContext($controllerContext): void { $this->controllerContext = $controllerContext; $request = $controllerContext->getRequest(); diff --git a/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractConditionViewHelper.php b/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractConditionViewHelper.php index 052ef09e98..95010126c0 100644 --- a/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractConditionViewHelper.php +++ b/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractConditionViewHelper.php @@ -45,6 +45,7 @@ abstract class AbstractConditionViewHelper extends AbstractViewHelper /** * Initializes the "then" and "else" arguments + * @return void */ public function initializeArguments() { @@ -66,18 +67,19 @@ public function initializeArguments() * subclasses that will be using this base class in the future. Let this * be a warning if someone considers changing this method signature! * - * @param array|NULL $arguments + * @param array|NULL $arguments * @param RenderingContextInterface $renderingContext * @return boolean * @api */ protected static function evaluateCondition($arguments, RenderingContextInterface $renderingContext) { - return (boolean)$arguments['condition']; + // fallback value derived from registerArgument default value + return (boolean)($arguments['condition'] ?? false); } /** - * @param array $arguments + * @param array $arguments * @param \Closure $renderChildrenClosure * @param RenderingContextInterface $renderingContext * @return mixed @@ -103,8 +105,8 @@ public static function renderStatic(array $arguments, \Closure $renderChildrenCl } /** - * @param array $closures - * @param array $conditionClosures + * @param array $closures + * @param array $conditionClosures * @param RenderingContextInterface $renderingContext * @return string */ @@ -236,7 +238,7 @@ public function compile($argumentsName, $closureName, &$initializationPhpCode, V /** * @param boolean $isConditionFullfilled - * @param array $arguments + * @param array $arguments * @param RenderingContextInterface $renderingContext * @return mixed */ diff --git a/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractLocaleAwareViewHelper.php b/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractLocaleAwareViewHelper.php index 5f33d1e651..db22b521e4 100644 --- a/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractLocaleAwareViewHelper.php +++ b/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractLocaleAwareViewHelper.php @@ -38,6 +38,7 @@ public function __construct() /** * @param I18n\Service $localizationService + * @return void */ public function injectLocalizationService(I18n\Service $localizationService) { diff --git a/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractTagBasedViewHelper.php b/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractTagBasedViewHelper.php index d4743808a6..2ce96b048d 100644 --- a/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractTagBasedViewHelper.php +++ b/Neos.FluidAdaptor/Classes/Core/ViewHelper/AbstractTagBasedViewHelper.php @@ -32,7 +32,7 @@ abstract class AbstractTagBasedViewHelper extends AbstractViewHelper /** * Names of all registered tag attributes * - * @var array + * @var array */ private static $tagAttributes = []; @@ -156,7 +156,7 @@ protected function registerUniversalTagAttributes() * which in the default implementation will throw an error * about "undeclared argument used". * - * @param array $arguments + * @param array|array|null> $arguments * @return void */ public function handleAdditionalArguments(array $arguments) diff --git a/Neos.FluidAdaptor/Classes/Core/ViewHelper/ViewHelperResolver.php b/Neos.FluidAdaptor/Classes/Core/ViewHelper/ViewHelperResolver.php index 8351bfa4f1..3ec15a4742 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,16 +50,20 @@ 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 = []; /** * @Flow\InjectConfiguration(path="namespaces") - * @var array + * @var array */ protected $namespacesFromConfiguration; + /** + * @param int $reason + * @return void + */ public function initializeObject($reason) { if ($reason === ObjectManagerInterface::INITIALIZATIONCAUSE_RECREATED) { @@ -83,8 +88,9 @@ public function initializeObject($reason) } /** - * @param string $viewHelperClassName - * @return \TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperInterface + * @template T of ViewHelperInterface + * @param class-string $viewHelperClassName + * @return T */ public function createViewHelperInstanceFromClassName($viewHelperClassName) { @@ -125,7 +131,7 @@ public function createViewHelperInstanceFromClassName($viewHelperClassName) * when you use this method you should always include the "f" namespace. * * @param string $identifier - * @param string|array $phpNamespace + * @param string|array|null $phpNamespace * @return void */ public function addNamespace($identifier, $phpNamespace) @@ -148,6 +154,7 @@ public function addNamespace($identifier, $phpNamespace) /** * @param string $identifier * @param string $phpNamespace + * @return void */ protected function addNamespaceInternal($identifier, $phpNamespace) { diff --git a/Neos.FluidAdaptor/Classes/Core/Widget/AbstractWidgetController.php b/Neos.FluidAdaptor/Classes/Core/Widget/AbstractWidgetController.php index c7b38b4a80..4c07eab1e2 100644 --- a/Neos.FluidAdaptor/Classes/Core/Widget/AbstractWidgetController.php +++ b/Neos.FluidAdaptor/Classes/Core/Widget/AbstractWidgetController.php @@ -36,7 +36,7 @@ abstract class AbstractWidgetController extends ActionController /** * Configuration for this widget. * - * @var array + * @var array * @api */ protected $widgetConfiguration; @@ -60,7 +60,6 @@ abstract class AbstractWidgetController extends ActionController */ public function processRequest(ActionRequest $request): ResponseInterface { - /** @var WidgetContext $widgetContext */ $widgetContext = $request->getInternalArgument('__widgetContext'); if (!$widgetContext instanceof WidgetContext) { throw new WidgetContextNotFoundException('The widget context could not be found in the request.', 1307450180); diff --git a/Neos.FluidAdaptor/Classes/Core/Widget/AbstractWidgetViewHelper.php b/Neos.FluidAdaptor/Classes/Core/Widget/AbstractWidgetViewHelper.php index e390a32db6..6a98bf293f 100644 --- a/Neos.FluidAdaptor/Classes/Core/Widget/AbstractWidgetViewHelper.php +++ b/Neos.FluidAdaptor/Classes/Core/Widget/AbstractWidgetViewHelper.php @@ -20,6 +20,7 @@ use Neos\FluidAdaptor\Core\ViewHelper\AbstractViewHelper; use Neos\FluidAdaptor\Core\ViewHelper\Facets\ChildNodeAccessInterface; use TYPO3Fluid\Fluid\Core\Compiler\TemplateCompiler; +use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\NodeInterface; use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\RootNode; use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode; @@ -142,7 +143,12 @@ private function initializeWidgetContext() $this->widgetContext->setNonAjaxWidgetConfiguration($this->getNonAjaxWidgetConfiguration()); $this->initializeWidgetIdentifier(); - $controllerObjectName = ($this->controller instanceof DependencyProxy) ? $this->controller->_getClassName() : get_class($this->controller); + /** @phpstan-ignore-next-line the mind of the great phpstan can and will not comprehend this */ + if ($this->controller instanceof \Neos\Flow\ObjectManagement\DependencyInjection\DependencyProxy) { + $controllerObjectName = $this->controller->_getClassName(); + } else { + $controllerObjectName = get_class($this->controller); + } $this->widgetContext->setControllerObjectName($controllerObjectName); } @@ -150,7 +156,7 @@ private function initializeWidgetContext() * Stores the syntax tree child nodes in the Widget Context, so they can be * rendered with lateron. * - * @param array $childNodes The SyntaxTree Child nodes of this ViewHelper. + * @param array $childNodes The SyntaxTree Child nodes of this ViewHelper. * @return void */ public function setChildNodes(array $childNodes) @@ -166,7 +172,7 @@ public function setChildNodes(array $childNodes) /** * Generate the configuration for this widget. Override to adjust. * - * @return array + * @return array * @api */ protected function getWidgetConfiguration() @@ -179,7 +185,7 @@ protected function getWidgetConfiguration() * * By default, returns getWidgetConfiguration(). Should become API later. * - * @return array + * @return array */ protected function getAjaxWidgetConfiguration() { @@ -191,7 +197,7 @@ protected function getAjaxWidgetConfiguration() * * By default, returns getWidgetConfiguration(). Should become API later. * - * @return array + * @return array */ protected function getNonAjaxWidgetConfiguration() { @@ -210,6 +216,7 @@ protected function getNonAjaxWidgetConfiguration() */ protected function initiateSubRequest() { + /** @phpstan-ignore-next-line the mind of the great phpstan can and will not comprehend this */ if ($this->controller instanceof DependencyProxy) { $this->controller->_activateDependency(); } diff --git a/Neos.FluidAdaptor/Classes/Core/Widget/AjaxWidgetContextHolder.php b/Neos.FluidAdaptor/Classes/Core/Widget/AjaxWidgetContextHolder.php index f78a163c2f..81a7077866 100644 --- a/Neos.FluidAdaptor/Classes/Core/Widget/AjaxWidgetContextHolder.php +++ b/Neos.FluidAdaptor/Classes/Core/Widget/AjaxWidgetContextHolder.php @@ -30,7 +30,7 @@ class AjaxWidgetContextHolder * An array $ajaxWidgetIdentifier => $widgetContext * which stores the widget context. * - * @var array + * @var array */ protected $widgetContexts = []; diff --git a/Neos.FluidAdaptor/Classes/Core/Widget/WidgetContext.php b/Neos.FluidAdaptor/Classes/Core/Widget/WidgetContext.php index de1beed414..2952e3e7f5 100644 --- a/Neos.FluidAdaptor/Classes/Core/Widget/WidgetContext.php +++ b/Neos.FluidAdaptor/Classes/Core/Widget/WidgetContext.php @@ -48,7 +48,7 @@ class WidgetContext * controller as $this->widgetConfiguration, if being inside an AJAX * request * - * @var array + * @var array */ protected $ajaxWidgetConfiguration; @@ -57,7 +57,7 @@ class WidgetContext * controller as $this->widgetConfiguration, if being inside a non-AJAX * request * - * @var array + * @var array */ protected $nonAjaxWidgetConfiguration; /** @@ -71,7 +71,7 @@ class WidgetContext * The child nodes of the Widget ViewHelper. * Only available inside non-AJAX requests. * - * @var RootNode + * @var ?RootNode * @Flow\Transient */ protected $viewHelperChildNodes; @@ -80,7 +80,7 @@ class WidgetContext * The rendering context of the ViewHelperChildNodes. * Only available inside non-AJAX requests. * - * @var RenderingContextInterface + * @var ?RenderingContextInterface * @Flow\Transient */ protected $viewHelperChildNodeRenderingContext; @@ -120,7 +120,7 @@ public function setAjaxWidgetIdentifier($ajaxWidgetIdentifier) } /** - * @return array + * @return array */ public function getWidgetConfiguration() { @@ -132,7 +132,7 @@ public function getWidgetConfiguration() } /** - * @param array $ajaxWidgetConfiguration + * @param array $ajaxWidgetConfiguration * @return void */ public function setAjaxWidgetConfiguration(array $ajaxWidgetConfiguration) @@ -141,7 +141,7 @@ public function setAjaxWidgetConfiguration(array $ajaxWidgetConfiguration) } /** - * @param array $nonAjaxWidgetConfiguration + * @param array $nonAjaxWidgetConfiguration * @return void */ public function setNonAjaxWidgetConfiguration(array $nonAjaxWidgetConfiguration) @@ -178,7 +178,7 @@ public function setViewHelperChildNodes(RootNode $viewHelperChildNodes, Renderin } /** - * @return RootNode + * @return ?RootNode */ public function getViewHelperChildNodes() { @@ -186,7 +186,7 @@ public function getViewHelperChildNodes() } /** - * @return RenderingContextInterface + * @return RenderingContextInterface|null */ public function getViewHelperChildNodeRenderingContext() { diff --git a/Neos.FluidAdaptor/Classes/Service/AbstractGenerator.php b/Neos.FluidAdaptor/Classes/Service/AbstractGenerator.php index 0b37087aab..6001780143 100644 --- a/Neos.FluidAdaptor/Classes/Service/AbstractGenerator.php +++ b/Neos.FluidAdaptor/Classes/Service/AbstractGenerator.php @@ -54,7 +54,7 @@ public function __construct() * Get all class names inside this namespace and return them as array. * * @param string $namespace - * @return array Array of all class names inside a given namespace. + * @return array> Array of all class names inside a given namespace. */ protected function getClassNamesInNamespace($namespace) { @@ -101,7 +101,7 @@ protected function getTagNameForClass($className, $namespace) * @param \SimpleXMLElement $parentXmlNode Parent XML Node to add the child to * @param string $childNodeName Name of the child node * @param string $childNodeValue Value of the child node. Will be placed inside CDATA. - * @return \SimpleXMLElement the new element + * @return ?\SimpleXMLElement the new element */ protected function addChildWithCData(\SimpleXMLElement $parentXmlNode, $childNodeName, $childNodeValue) { @@ -110,8 +110,12 @@ protected function addChildWithCData(\SimpleXMLElement $parentXmlNode, $childNod $childNode = $domDocument->appendChild($domDocument->createElement($childNodeName)); $childNode->appendChild($domDocument->createCDATASection($childNodeValue)); - $childNodeTarget = $parentDomNode->ownerDocument->importNode($childNode, true); - $parentDomNode->appendChild($childNodeTarget); - return simplexml_import_dom($childNodeTarget); + $childNodeTarget = $parentDomNode->ownerDocument?->importNode($childNode, true); + if ($childNodeTarget instanceof \DOMNode) { + $parentDomNode->appendChild($childNodeTarget); + return simplexml_import_dom($childNodeTarget); + } + + return null; } } diff --git a/Neos.FluidAdaptor/Classes/Service/XsdGenerator.php b/Neos.FluidAdaptor/Classes/Service/XsdGenerator.php index c67220d2e9..be4fda8617 100644 --- a/Neos.FluidAdaptor/Classes/Service/XsdGenerator.php +++ b/Neos.FluidAdaptor/Classes/Service/XsdGenerator.php @@ -54,7 +54,11 @@ public function generateXsd($viewHelperNamespace, $xsdNamespace) $this->generateXmlForClassName($className, $viewHelperNamespace, $xmlRootNode); } - return $xmlRootNode->asXML(); + $result = $xmlRootNode->asXML(); + + return is_string($result) + ? $result + : throw new \Exception('Failed to generate xsd', 1743851104); } /** @@ -75,15 +79,22 @@ protected function generateXmlForClassName($className, $viewHelperNamespace, \Si $tagName = $this->getTagNameForClass($className, $viewHelperNamespace); $xsdElement = $xmlRootNode->addChild('xsd:element'); + /** @phpstan-ignore argument.type (offsetSet accepts mixed) */ $xsdElement->offsetSet('name', $tagName); - $this->docCommentParser->parseDocComment($reflectionClass->getDocComment()); + $docComment = $reflectionClass->getDocComment(); + if ($docComment !== false) { + $this->docCommentParser->parseDocComment($docComment); + } $this->addDocumentation($this->docCommentParser->getDescription(), $xsdElement); $xsdComplexType = $xsdElement->addChild('xsd:complexType'); + /** @phpstan-ignore argument.type (offsetSet accepts mixed) */ $xsdComplexType->offsetSet('mixed', 'true'); $xsdSequence = $xsdComplexType->addChild('xsd:sequence'); $xsdAny = $xsdSequence->addChild('xsd:any'); + /** @phpstan-ignore argument.type (offsetSet accepts mixed) */ $xsdAny->offsetSet('minOccurs', '0'); + /** @phpstan-ignore argument.type (offsetSet accepts mixed) */ $xsdAny->offsetSet('maxOccurs', 'unbounded'); $this->addAttributes($className, $xsdComplexType); @@ -106,10 +117,13 @@ protected function addAttributes($className, \SimpleXMLElement $xsdElement) foreach ($argumentDefinitions as $argumentDefinition) { /** @var \SimpleXMLElement $xsdAttribute */ $xsdAttribute = $xsdElement->addChild('xsd:attribute'); + /** @phpstan-ignore argument.type (offsetSet accepts mixed) */ $xsdAttribute->offsetSet('type', 'xsd:string'); + /** @phpstan-ignore argument.type (offsetSet accepts mixed) */ $xsdAttribute->offsetSet('name', $argumentDefinition->getName()); $this->addDocumentation($argumentDefinition->getDescription(), $xsdAttribute); if ($argumentDefinition->isRequired()) { + /** @phpstan-ignore argument.type (offsetSet accepts mixed) */ $xsdAttribute->offsetSet('use', 'required'); } } diff --git a/Neos.FluidAdaptor/Classes/View/AbstractTemplateView.php b/Neos.FluidAdaptor/Classes/View/AbstractTemplateView.php index 37a64bfa17..bcfc4dfb8b 100644 --- a/Neos.FluidAdaptor/Classes/View/AbstractTemplateView.php +++ b/Neos.FluidAdaptor/Classes/View/AbstractTemplateView.php @@ -12,7 +12,6 @@ */ use Neos\FluidAdaptor\Exception; -use Neos\Flow\Mvc\ActionRequest; use Neos\Flow\Mvc\Controller\ControllerContext; use Neos\Flow\Mvc\View\ViewInterface; use Neos\FluidAdaptor\Core\Rendering\RenderingContext; @@ -36,7 +35,7 @@ abstract class AbstractTemplateView extends \TYPO3Fluid\Fluid\View\AbstractTempl * ... * ) * - * @var array + * @var array */ protected $supportedOptions = [ 'templateRootPathPattern' => [ @@ -101,7 +100,7 @@ abstract class AbstractTemplateView extends \TYPO3Fluid\Fluid\View\AbstractTempl * * @see $supportedOptions * - * @var array + * @var array */ protected $options = []; @@ -124,6 +123,9 @@ public function assign($key, $value): self return parent::assign($key, $value); } + /** + * @param array $values + */ public function assignMultiple(array $values): self { // layer to fix incompatibility error with typo3 fluid interface @@ -133,7 +135,7 @@ public function assignMultiple(array $values): self /** * Factory method to create an instance with given options. * - * @param array $options + * @param array $options * @return static */ public static function createWithOptions(array $options): self @@ -144,7 +146,7 @@ public static function createWithOptions(array $options): self /** * Set default options based on the supportedOptions provided * - * @param array $options + * @param array|null $options * @throws Exception */ public function __construct(?array $options = null) @@ -184,14 +186,9 @@ public function setControllerContext(ControllerContext $controllerContext) $renderingContext->setControllerContext($controllerContext); } - $paths = $this->getTemplatePaths(); $request = $controllerContext->getRequest(); - if (!$request instanceof ActionRequest) { - return; - } - $paths->setFormat($request->getFormat()); if ($paths->getTemplateRootPaths() === [] && $paths->getLayoutRootPaths() === [] && $paths->getPartialRootPaths() === []) { @@ -205,7 +202,7 @@ public function setControllerContext(ControllerContext $controllerContext) * Renders a given section. * * @param string $sectionName Name of section to render - * @param array $variables The variables to use + * @param array $variables The variables to use * @param boolean $ignoreUnknown Ignore an unknown section and just return an empty string * @return string rendered template for the section * @throws \Neos\FluidAdaptor\View\Exception\InvalidSectionException @@ -217,13 +214,14 @@ public function renderSection($sectionName, array $variables = [], $ignoreUnknow $variables = $this->getRenderingContext()->getVariableProvider()->getAll(); } + /** @phpstan-ignore argument.type (we assume Fluid actually supports \ArrayAccess here, too) */ return parent::renderSection($sectionName, $variables, $ignoreUnknown); } /** * Validate options given to this view. * - * @param array $options + * @param array $options * @return void * @throws Exception */ @@ -250,7 +248,7 @@ function ($supportedOptionData, $supportedOptionName, $options) { * Merges the given options with the default values * and sets the resulting options in this object. * - * @param array $options + * @param array $options * @return void */ protected function setOptions(array $options) diff --git a/Neos.FluidAdaptor/Classes/View/StandaloneView.php b/Neos.FluidAdaptor/Classes/View/StandaloneView.php index 6fdb79413a..bcf401ae2f 100644 --- a/Neos.FluidAdaptor/Classes/View/StandaloneView.php +++ b/Neos.FluidAdaptor/Classes/View/StandaloneView.php @@ -51,7 +51,7 @@ class StandaloneView extends AbstractTemplateView protected $environment; /** - * @var ActionRequest + * @var ?ActionRequest */ protected $request; @@ -64,7 +64,7 @@ class StandaloneView extends AbstractTemplateView /** * Factory method to create an instance with given options. * - * @param array $options + * @param array $options * @return static */ public static function createWithOptions(array $options): self @@ -75,8 +75,8 @@ 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 array $options + * @param ?ActionRequest $request The current action request. If none is specified it will be created from the environment. + * @param array $options * @throws \Neos\FluidAdaptor\Exception */ public function __construct(?ActionRequest $request = null, array $options = []) @@ -115,6 +115,7 @@ public function initializeObject() /** * @param string $templateName + * @return void */ public function setTemplate($templateName) { @@ -130,6 +131,9 @@ public function setTemplate($templateName) */ public function setFormat($format) { + if (!$this->request) { + throw new \Exception('Cannot set format without a request', 1743856310); + } $this->request->setFormat($format); $this->baseRenderingContext->getTemplatePaths()->setFormat($format); } @@ -137,18 +141,18 @@ public function setFormat($format) /** * Returns the format of the current request (defaults is "html") * - * @return string $format + * @return ?string $format * @api */ public function getFormat() { - return $this->request->getFormat(); + return $this->request?->getFormat(); } /** * Returns the current request object * - * @return ActionRequest + * @return ?ActionRequest */ public function getRequest() { @@ -177,12 +181,20 @@ public function setTemplatePathAndFilename($templatePathAndFilename) /** * Returns the absolute path to a Fluid template file if it was specified with setTemplatePathAndFilename() before * - * @return string Fluid template path + * @return ?string Fluid template path * @api */ public function getTemplatePathAndFilename() { - return $this->baseRenderingContext->getTemplatePaths()->resolveTemplateFileForControllerAndActionAndFormat($this->request->getControllerName(), $this->request->getControllerActionName(), $this->request->getFormat()); + return $this->request + ? $this->baseRenderingContext + ->getTemplatePaths() + ->resolveTemplateFileForControllerAndActionAndFormat( + $this->request->getControllerName(), + $this->request->getControllerActionName(), + $this->request->getFormat() + ) + : null; } /** @@ -225,7 +237,7 @@ public function setLayoutRootPaths(array $layoutRootPaths) /** * Resolves the layout root to be used inside other paths. * - * @return array Fluid layout root paths + * @return array Fluid layout root paths * @throws InvalidTemplateResourceException * @api */ @@ -262,7 +274,7 @@ public function setPartialRootPaths(array $partialRootPaths) /** * Returns the absolute path to the folder that contains Fluid partial files * - * @return array Fluid partial root paths + * @return array Fluid partial root paths * @throws InvalidTemplateResourceException * @api */ diff --git a/Neos.FluidAdaptor/Classes/View/TemplatePaths.php b/Neos.FluidAdaptor/Classes/View/TemplatePaths.php index ee45bae7eb..0fac66a3e2 100644 --- a/Neos.FluidAdaptor/Classes/View/TemplatePaths.php +++ b/Neos.FluidAdaptor/Classes/View/TemplatePaths.php @@ -52,7 +52,7 @@ class TemplatePaths extends \TYPO3Fluid\Fluid\View\TemplatePaths ]; /** - * @var array + * @var array */ protected $options = []; @@ -61,6 +61,9 @@ class TemplatePaths extends \TYPO3Fluid\Fluid\View\TemplatePaths */ protected $packageManager; + /** + * @param array $options + */ public function __construct(array $options = []) { foreach ($options as $optionName => $optionValue) { @@ -70,6 +73,7 @@ public function __construct(array $options = []) /** * @param PackageManager $packageManager + * @return void */ public function injectPackageManager(PackageManager $packageManager) { @@ -86,6 +90,7 @@ public function getTemplateRootPathPattern(): string /** * @param string $templateRootPathPattern + * @return void */ public function setTemplateRootPathPattern(string $templateRootPathPattern) { @@ -94,6 +99,7 @@ public function setTemplateRootPathPattern(string $templateRootPathPattern) /** * @param string $layoutRootPathPattern + * @return void */ public function setLayoutRootPathPattern(string $layoutRootPathPattern) { @@ -102,6 +108,7 @@ public function setLayoutRootPathPattern(string $layoutRootPathPattern) /** * @param string $partialRootPathPattern + * @return void */ public function setPartialRootPathPattern(string $partialRootPathPattern) { @@ -110,6 +117,7 @@ public function setPartialRootPathPattern(string $partialRootPathPattern) /** * @param string $templateRootPath + * @return void */ public function setTemplateRootPath($templateRootPath) { @@ -119,7 +127,7 @@ public function setTemplateRootPath($templateRootPath) /** * Resolves the template root to be used inside other paths. * - * @return array Path(s) to template root directory + * @return array Path(s) to template root directory */ public function getTemplateRootPaths() { @@ -140,7 +148,7 @@ public function getTemplateRootPaths() } /** - * @return array + * @return array */ public function getLayoutRootPaths() { @@ -160,6 +168,9 @@ public function getLayoutRootPaths() return [$layoutRootPath]; } + /** + * @return array + */ public function getPartialRootPaths() { if ($this->partialRootPaths !== []) { @@ -180,6 +191,7 @@ public function getPartialRootPaths() /** * @param string $layoutRootPath + * @return void */ public function setLayoutRootPath($layoutRootPath) { @@ -188,6 +200,7 @@ public function setLayoutRootPath($layoutRootPath) /** * @param string $partialRootPath + * @return void */ public function setPartialRootPath($partialRootPath) { @@ -204,6 +217,7 @@ public function getPatternReplacementVariables() /** * @param string[] $patternReplacementVariables + * @return void */ public function setPatternReplacementVariables($patternReplacementVariables) { @@ -389,10 +403,10 @@ protected function sanitizePath($path) * replaced by the current request format, and once with ."@format" stripped off. * * @param string $pattern Pattern to be resolved - * @param array $patternReplacementVariables The variables to replace in the pattern + * @param array $patternReplacementVariables The variables to replace in the pattern * @param boolean $bubbleControllerAndSubpackage if true, then we successively split off parts from "@controller" and "@subpackage" until both are empty. * @param boolean $formatIsOptional if true, then half of the resulting strings will have ."@format" stripped off, and the other half will have it. - * @return array unix style paths + * @return array unix style paths */ protected function expandGenericPathPattern($pattern, array $patternReplacementVariables, $bubbleControllerAndSubpackage, $formatIsOptional) { @@ -426,10 +440,10 @@ protected function expandGenericPathPattern($pattern, array $patternReplacementV } /** - * @param array $paths + * @param array $paths * @param string $variableName * @param string $variableValue - * @return array + * @return array */ protected function replacePatternVariable($paths, $variableName, $variableValue) { @@ -441,11 +455,11 @@ protected function replacePatternVariable($paths, $variableName, $variableValue) } /** - * @param array $paths + * @param array $paths * @param string $controllerName * @param string $subPackageKey * @param bool $bubbleControllerAndSubpackage - * @return array + * @return array */ protected function expandSubPackageAndController(array $paths, string $controllerName, string $subPackageKey = '', bool $bubbleControllerAndSubpackage = false): array { @@ -460,7 +474,7 @@ protected function expandSubPackageAndController(array $paths, string $controlle $numberOfSubpackageParts = count($subpackageKeyParts); $subpackageReplacements = []; for ($i = 0; $i <= $numberOfSubpackageParts; $i++) { - $subpackageReplacements[] = implode('/', ($i < 0 ? $subpackageKeyParts : array_slice($subpackageKeyParts, $i))); + $subpackageReplacements[] = implode('/', array_slice($subpackageKeyParts, $i)); } $paths = $this->expandPatterns($paths, '@subpackage', $subpackageReplacements); @@ -476,10 +490,10 @@ protected function expandSubPackageAndController(array $paths, string $controlle * Expands the given $patterns by adding an array element for each $replacement * replacing occurrences of $search. * - * @param array $patterns + * @param array $patterns * @param string $search - * @param array $replacements - * @return array + * @param array $replacements + * @return array */ protected function expandPatterns(array $patterns, string $search, array $replacements): array { diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/DebugViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/DebugViewHelper.php index 0b189fa7b2..39d42bc727 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/DebugViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/DebugViewHelper.php @@ -78,6 +78,6 @@ public function render() $expressionToExamine = (is_object($expressionToExamine) ? get_class($expressionToExamine) : gettype($expressionToExamine)); } - return \Neos\Flow\var_dump($expressionToExamine, $this->arguments['title'], true); + return \Neos\Flow\var_dump($expressionToExamine, $this->arguments['title'], true) ?: ''; } } diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/FlashMessagesViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/FlashMessagesViewHelper.php index 5198e6ed28..73ccbe633e 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/FlashMessagesViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/FlashMessagesViewHelper.php @@ -105,7 +105,7 @@ public function render() * Render the flash messages as unsorted list. This is triggered if no "as" argument is given * to the ViewHelper. * - * @param list $flashMessages + * @param array $flashMessages * @return string */ protected function renderAsList(array $flashMessages) @@ -131,7 +131,7 @@ protected function renderAsList(array $flashMessages) * the flash messages are stored in the template inside the variable specified * in "as". * - * @param array $flashMessages + * @param array $flashMessages * @param string $as * @return string */ diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Form/AbstractFormFieldViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Form/AbstractFormFieldViewHelper.php index 489844b745..a3da57a863 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Form/AbstractFormFieldViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Form/AbstractFormFieldViewHelper.php @@ -84,7 +84,6 @@ protected function getNameWithoutPrefix(): string $name = $this->arguments['name']; } if ($this->hasArgument('value')) { - /** @var object $value */ $value = $this->arguments['value']; $multiple = $this->hasArgument('multiple') && $this->arguments['multiple'] === true; if (!$multiple @@ -223,7 +222,7 @@ protected function getPropertyPath(): string return $formObjectName . '.' . $this->arguments['property']; } - return rtrim(preg_replace('/(\]\[|\[|\])/', '.', $this->getNameWithoutPrefix()), '.'); + return rtrim(preg_replace('/(\]\[|\[|\])/', '.', $this->getNameWithoutPrefix()) ?: '', '.'); } /** diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Form/AbstractFormViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Form/AbstractFormViewHelper.php index 60aa6d6da6..8b0809235c 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Form/AbstractFormViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Form/AbstractFormViewHelper.php @@ -41,7 +41,7 @@ public function injectPersistenceManager(PersistenceManagerInterface $persistenc /** * Prefixes / namespaces the given name with the form field prefix * - * @param string $fieldName field name to be prefixed + * @param ?string $fieldName field name to be prefixed * @return string namespaced field name */ protected function prefixFieldName($fieldName) @@ -68,13 +68,13 @@ protected function prefixFieldName($fieldName) * Renders a hidden form field containing the technical identity of the given object. * * @param object $object Object to create the identity field for - * @param string $name Name + * @param ?string $name Name * @return string A hidden field containing the Identity (UUID in Flow) of the given object or empty string if the object is unknown to the persistence framework * @see \Neos\Flow\Mvc\Controller\Argument::setValue() */ protected function renderHiddenIdentityField($object, $name) { - if (!is_object($object) || $this->persistenceManager->isNewObject($object)) { + if (!is_object($object) || $this->persistenceManager->isNewObject($object) || $name === null) { return ''; } $identifier = $this->persistenceManager->getIdentifierByObject($object); diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Form/CheckboxViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Form/CheckboxViewHelper.php index d7d4e3b574..67f85cf55b 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Form/CheckboxViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Form/CheckboxViewHelper.php @@ -98,7 +98,8 @@ public function render() if ($checked === null) { $checked = false; foreach ($propertyValue as $value) { - if (TypeHandling::isSimpleType(TypeHandling::getTypeForValue($value))) { + $typeForValue = TypeHandling::getTypeForValue($value); + if (TypeHandling::isSimpleType($typeForValue)) { $checked = $valueAttribute === $value; } else { // assume an entity diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Form/SelectViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Form/SelectViewHelper.php index a2dde44370..f9c0f08933 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Form/SelectViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Form/SelectViewHelper.php @@ -200,7 +200,7 @@ public function render() /** * Render the option tags. * - * @param array $options the options for the form. + * @param array $options the options for the form. * @return string rendered tags. */ protected function renderOptionTags($options) @@ -227,7 +227,7 @@ protected function renderOptionTags($options) /** * Render the option tags. * - * @return array an associative array of options, key will be the value of the option tag + * @return array an associative array of options, key will be the value of the option tag * @throws ViewHelper\Exception */ protected function getOptions() @@ -354,6 +354,7 @@ protected function getOptionValueScalar($valueElement) } elseif ($this->persistenceManager->getIdentifierByObject($valueElement) !== null) { return $this->persistenceManager->getIdentifierByObject($valueElement); } else { + /** @phpstan-ignore cast.string (we'll try anyway -.-) */ return (string)$valueElement; } } else { diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/FormViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/FormViewHelper.php index d13b5ab8bd..16820d64f4 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/FormViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/FormViewHelper.php @@ -299,7 +299,7 @@ protected function renderHiddenReferrerFields() $result = chr(10); $request = $this->controllerContext->getRequest(); $argumentNamespace = null; - if ($request instanceof ActionRequest && $request->isMainRequest() === false) { + if ($request->isMainRequest() === false) { $argumentNamespace = $request->getArgumentNamespace(); $referrer = [ @@ -316,10 +316,6 @@ protected function renderHiddenReferrerFields() $request = $request->getParentRequest(); } - if ($request === null) { - throw new \RuntimeException('No ActionRequest could be found to evaluate form argument namespace.', 1565945918); - } - $arguments = $request->getArguments(); if ($argumentNamespace !== null && isset($arguments[$argumentNamespace])) { // A sub request was there; thus we can unset the sub requests arguments, diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Format/BytesViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Format/BytesViewHelper.php index 76a4b946e1..a538a7d88d 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Format/BytesViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Format/BytesViewHelper.php @@ -72,7 +72,7 @@ class BytesViewHelper extends AbstractLocaleAwareViewHelper /** * @param float $bytes - * @return array + * @return array{0: float, 1: string} */ protected static function maximizeUnit(float $bytes): array { diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Format/CaseViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Format/CaseViewHelper.php index 9dc3ecd2c2..8eefa16a80 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Format/CaseViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Format/CaseViewHelper.php @@ -123,7 +123,7 @@ public function render() } /** - * @param array $arguments + * @param array $arguments * @param \Closure $renderChildrenClosure * @param RenderingContextInterface $renderingContext * @return string diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Format/CropViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Format/CropViewHelper.php index 4ab2986948..e9de2cb5be 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Format/CropViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Format/CropViewHelper.php @@ -78,7 +78,7 @@ public function render() } /** - * @param array $arguments + * @param array $arguments * @param \Closure $renderChildrenClosure * @param RenderingContextInterface $renderingContext * @return string diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Format/HtmlentitiesDecodeViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Format/HtmlentitiesDecodeViewHelper.php index 0316b42dcc..660c7f2fee 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Format/HtmlentitiesDecodeViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Format/HtmlentitiesDecodeViewHelper.php @@ -79,7 +79,7 @@ public function render() /** * Applies html_entity_decode() on the specified value. * - * @param array $arguments + * @param array $arguments * @param \Closure $renderChildrenClosure * @param RenderingContextInterface $renderingContext * @return string|mixed diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Format/HtmlentitiesViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Format/HtmlentitiesViewHelper.php index a1d67c8532..0f0dbe84ed 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Format/HtmlentitiesViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Format/HtmlentitiesViewHelper.php @@ -79,7 +79,7 @@ public function render() /** * Applies htmlentities() on the specified value. * - * @param array $arguments + * @param array $arguments * @param \Closure $renderChildrenClosure * @param RenderingContextInterface $renderingContext * @return string|mixed diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Format/JsonViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Format/JsonViewHelper.php index 87c216d4d5..d8c7b228e4 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Format/JsonViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Format/JsonViewHelper.php @@ -86,7 +86,7 @@ public function render() $options = $options | JSON_FORCE_OBJECT; } - return json_encode($value, $options); + return json_encode($value, $options | JSON_THROW_ON_ERROR); } /** diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Format/PaddingViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Format/PaddingViewHelper.php index 476db7b55e..cc37d1f089 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Format/PaddingViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Format/PaddingViewHelper.php @@ -79,7 +79,7 @@ public function render() /** * Applies str_pad() on the specified value. * - * @param array $arguments + * @param array $arguments * @param \Closure $renderChildrenClosure * @param RenderingContextInterface $renderingContext * @return string diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Format/UrlencodeViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Format/UrlencodeViewHelper.php index f312b713b2..f0650790bb 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Format/UrlencodeViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Format/UrlencodeViewHelper.php @@ -72,7 +72,7 @@ public function render() /** * Applies rawurlencode() on the specified value. * - * @param array $arguments + * @param array $arguments * @param \Closure $renderChildrenClosure * @param RenderingContextInterface $renderingContext * @return string|mixed diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/RenderChildrenViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/RenderChildrenViewHelper.php index 9d35aca2ef..1041792388 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/RenderChildrenViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/RenderChildrenViewHelper.php @@ -74,7 +74,7 @@ public function render(): string $widgetChildNodes = $this->getWidgetChildNodes(); $this->addArgumentsToTemplateVariableContainer($this->arguments['arguments']); - $output = $widgetChildNodes->evaluate($renderingContext); + $output = $widgetChildNodes?->evaluate($renderingContext) ?: ''; $this->removeArgumentsFromTemplateVariableContainer($this->arguments['arguments']); return $output; @@ -97,10 +97,10 @@ protected function getWidgetRenderingContext(): RenderingContextInterface } /** - * @return RootNode + * @return ?RootNode * @throws WidgetContextNotFoundException */ - protected function getWidgetChildNodes(): RootNode + protected function getWidgetChildNodes(): ?RootNode { return $this->getWidgetContext()->getViewHelperChildNodes(); } @@ -123,7 +123,7 @@ protected function getWidgetContext(): WidgetContext /** * Add the given arguments to the TemplateVariableContainer of the widget. * - * @param array $arguments + * @param array $arguments * @return void * @throws RenderingContextNotFoundException * @throws WidgetContextNotFoundException @@ -139,7 +139,7 @@ protected function addArgumentsToTemplateVariableContainer(array $arguments): vo /** * Remove the given arguments from the TemplateVariableContainer of the widget. * - * @param array $arguments + * @param array $arguments * @return void * @throws RenderingContextNotFoundException * @throws WidgetContextNotFoundException diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Security/IfAccessViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Security/IfAccessViewHelper.php index 225621a2e7..5a4737fd35 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Security/IfAccessViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Security/IfAccessViewHelper.php @@ -15,7 +15,6 @@ use Neos\Flow\Security\Authorization\PrivilegeManagerInterface; use Neos\Flow\Security\Context; use Neos\FluidAdaptor\Core\Rendering\FlowAwareRenderingContextInterface; -use Neos\FluidAdaptor\Core\Rendering\RenderingContext; use Neos\FluidAdaptor\Core\ViewHelper\AbstractConditionViewHelper; use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface; @@ -56,6 +55,7 @@ class IfAccessViewHelper extends AbstractConditionViewHelper { /** * Initializes the "then" and "else" arguments + * @return void */ public function initializeArguments() { @@ -80,9 +80,9 @@ public function render() } /** - * @param array $arguments + * @param array $arguments * @param \Closure $renderChildrenClosure - * @param RenderingContextInterface $renderingContext + * @param FlowAwareRenderingContextInterface&RenderingContextInterface $renderingContext * @return mixed */ public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) @@ -91,28 +91,31 @@ public static function renderStatic(array $arguments, \Closure $renderChildrenCl } /** - * @param array|null $arguments + * @param array|null $arguments * @param FlowAwareRenderingContextInterface&RenderingContextInterface $renderingContext * @return boolean */ protected static function evaluateCondition($arguments, RenderingContextInterface $renderingContext) { $objectManager = $renderingContext->getObjectManager(); - /** @var Context $securityContext */ + /** @var ?Context $securityContext */ $securityContext = $objectManager->get(Context::class); if ($securityContext !== null && !$securityContext->canBeInitialized()) { return false; } + $privilegeTarget = $arguments['privilegeTarget'] ?? null; + if (!is_string($privilegeTarget)) { + throw new \Exception('Missing privilegeTarget argument.', 1743848049); + } $privilegeManager = static::getPrivilegeManager($renderingContext); - return $privilegeManager->isPrivilegeTargetGranted($arguments['privilegeTarget'], $arguments['parameters'] ?? []); + return $privilegeManager->isPrivilegeTargetGranted($privilegeTarget, $arguments['parameters'] ?? []); } /** - * @param RenderingContext $renderingContext * @return PrivilegeManagerInterface */ - protected static function getPrivilegeManager(RenderingContext $renderingContext) + protected static function getPrivilegeManager(FlowAwareRenderingContextInterface $renderingContext) { $objectManager = $renderingContext->getObjectManager(); return $objectManager->get(PrivilegeManagerInterface::class); diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Security/IfAuthenticatedViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Security/IfAuthenticatedViewHelper.php index a7a78ae4b9..f7f6c6cb1f 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Security/IfAuthenticatedViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Security/IfAuthenticatedViewHelper.php @@ -66,7 +66,7 @@ public function render() } /** - * @param null $arguments + * @param array|null $arguments * @param FlowAwareRenderingContextInterface&RenderingContextInterface $renderingContext * @return bool */ diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Security/IfHasRoleViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Security/IfHasRoleViewHelper.php index 9be411ea51..b5669429e4 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Security/IfHasRoleViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Security/IfHasRoleViewHelper.php @@ -78,6 +78,7 @@ class IfHasRoleViewHelper extends AbstractConditionViewHelper { /** * Initializes the "then" and "else" arguments + * @return void */ public function initializeArguments() { @@ -104,7 +105,7 @@ public function render() } /** - * @param array|null $arguments + * @param array|null $arguments * @param FlowAwareRenderingContextInterface&RenderingContextInterface $renderingContext * @return boolean */ @@ -120,8 +121,8 @@ protected static function evaluateCondition($arguments, RenderingContextInterfac return false; } - $role = $arguments['role']; - $account = $arguments['account']; + $role = $arguments['role'] ?? null; + $account = $arguments['account'] ?? null; $packageKey = isset($arguments['packageKey']) ? $arguments['packageKey'] : $renderingContext->getControllerContext()->getRequest()->getControllerPackageKey(); if (is_string($role)) { diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/TranslateViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/TranslateViewHelper.php index c4c0d06f0b..d15b0f6a95 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/TranslateViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/TranslateViewHelper.php @@ -15,7 +15,6 @@ use Neos\Flow\I18n\Exception\InvalidLocaleIdentifierException; use Neos\Flow\I18n\Locale; use Neos\Flow\I18n\Translator; -use Neos\Flow\Mvc\ActionRequest; use Neos\FluidAdaptor\Core\ViewHelper; use Neos\FluidAdaptor\Core\ViewHelper\Exception as ViewHelperException; @@ -122,9 +121,7 @@ public function render() } if ($package === null) { $request = $this->renderingContext->getControllerContext()->getRequest(); - if ($request instanceof ActionRequest) { - $package = $request->getControllerPackageKey(); - } + $package = $request->getControllerPackageKey(); if (empty($package)) { throw new ViewHelperException( 'The current package key can\'t be resolved. Make sure to initialize the Fluid view with a proper ActionRequest and/or specify the "package" argument when using the f:translate ViewHelper', @@ -150,6 +147,7 @@ public function render() /** * @param Translator $translator + * @return void */ public function injectTranslator(Translator $translator) { diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Uri/ResourceViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Uri/ResourceViewHelper.php index 6254572c13..7caf99eec5 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Uri/ResourceViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Uri/ResourceViewHelper.php @@ -100,7 +100,7 @@ public function render() } /** - * @param array $arguments + * @param array $arguments * @param \Closure $renderChildrenClosure * @param FlowAwareRenderingContextInterface&RenderingContextInterface $renderingContext * @return string diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Validation/IfHasErrorsViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Validation/IfHasErrorsViewHelper.php index 3efab8366c..40f593e560 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Validation/IfHasErrorsViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Validation/IfHasErrorsViewHelper.php @@ -70,7 +70,7 @@ public function render() } /** - * @param null $arguments + * @param array $arguments * @param FlowAwareRenderingContextInterface&RenderingContextInterface $renderingContext * @return boolean */ diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Widget/Controller/AutocompleteController.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Widget/Controller/AutocompleteController.php index 9dd40909a6..a9468b212a 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Widget/Controller/AutocompleteController.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Widget/Controller/AutocompleteController.php @@ -21,7 +21,7 @@ class AutocompleteController extends AbstractWidgetController { /** - * @var array + * @var array */ protected $configuration = ['limit' => 10]; @@ -82,6 +82,6 @@ public function autocompleteAction($term) 'value' => $val ]; } - return json_encode($output); + return json_encode($output, JSON_THROW_ON_ERROR); } } diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Widget/Controller/PaginateController.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Widget/Controller/PaginateController.php index 1778c2c0a1..535ffe094d 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Widget/Controller/PaginateController.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Widget/Controller/PaginateController.php @@ -26,7 +26,7 @@ class PaginateController extends AbstractWidgetController protected $objects; /** - * @var array + * @var array */ protected $configuration = ['itemsPerPage' => 10, 'insertAbove' => false, 'insertBelow' => true, 'maximumNumberOfLinks' => 99]; @@ -56,12 +56,12 @@ class PaginateController extends AbstractWidgetController protected $numberOfPages = 1; /** - * @var float + * @var integer */ protected $displayRangeStart; /** - * @var float + * @var integer */ protected $displayRangeEnd; @@ -117,22 +117,30 @@ protected function calculateDisplayRange() $maximumNumberOfLinks = $this->numberOfPages; } $delta = floor($maximumNumberOfLinks / 2); - $this->displayRangeStart = $this->currentPage - $delta; - $this->displayRangeEnd = $this->currentPage + $delta + ($maximumNumberOfLinks % 2 === 0 ? 1 : 0); - if ($this->displayRangeStart < 1) { - $this->displayRangeEnd -= $this->displayRangeStart - 1; + $displayRangeStart = $this->currentPage - $delta; + $displayRangeEnd = $this->currentPage + $delta + ($maximumNumberOfLinks % 2 === 0 ? 1 : 0); + if ($displayRangeStart < 1) { + $displayRangeEnd -= $displayRangeStart - 1; } - if ($this->displayRangeEnd > $this->numberOfPages) { - $this->displayRangeStart -= ($this->displayRangeEnd - $this->numberOfPages); + if ($displayRangeEnd > $this->numberOfPages) { + $displayRangeStart -= ($displayRangeEnd - $this->numberOfPages); } - $this->displayRangeStart = (integer)max($this->displayRangeStart, 1); - $this->displayRangeEnd = (integer)min($this->displayRangeEnd, $this->numberOfPages); + $this->displayRangeStart = (integer)max($displayRangeStart, 1); + $this->displayRangeEnd = (integer)min($displayRangeEnd, $this->numberOfPages); } /** - * Returns an array with the keys "pages", "current", "numberOfPages", "nextPage" & "previousPage" - * - * @return array + * @return array{ + * pages: list, + * current: int, + * numberOfPages: int, + * displayRangeStart: float, + * displayRangeEnd: float, + * hasLessPages: bool, + * hasMorePages: bool, + * nextPage?: int, + * previousPage?: int, + * } */ protected function buildPagination() { diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Widget/LinkViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Widget/LinkViewHelper.php index 55de2b8c53..5a6800624a 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Widget/LinkViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Widget/LinkViewHelper.php @@ -120,7 +120,7 @@ protected function getAjaxUri(): string } else { $arguments['__widgetId'] = $widgetContext->getAjaxWidgetIdentifier(); } - return '?' . http_build_query($arguments, null, '&'); + return '?' . http_build_query(data: $arguments, arg_separator: '&'); } /** diff --git a/Neos.FluidAdaptor/Classes/ViewHelpers/Widget/UriViewHelper.php b/Neos.FluidAdaptor/Classes/ViewHelpers/Widget/UriViewHelper.php index f96c6702e2..a57cb01bcf 100644 --- a/Neos.FluidAdaptor/Classes/ViewHelpers/Widget/UriViewHelper.php +++ b/Neos.FluidAdaptor/Classes/ViewHelpers/Widget/UriViewHelper.php @@ -104,7 +104,7 @@ protected function getAjaxUri(): string } else { $arguments['__widgetId'] = $widgetContext->getAjaxWidgetIdentifier(); } - return '?' . http_build_query($arguments, null, '&'); + return '?' . http_build_query(data: $arguments, arg_separator: '&'); } /** diff --git a/Neos.Http.Factories/Classes/FlowUploadedFile.php b/Neos.Http.Factories/Classes/FlowUploadedFile.php index e9f5e296cb..04ca49a8db 100644 --- a/Neos.Http.Factories/Classes/FlowUploadedFile.php +++ b/Neos.Http.Factories/Classes/FlowUploadedFile.php @@ -14,7 +14,7 @@ class FlowUploadedFile extends UploadedFile * This is either the persistent identifier of a previously submitted resource file * or an array with the "__identity" key set to the persistent identifier. * - * @var array|string + * @var array{__identity: string}|string */ protected $originallySubmittedResource; @@ -27,7 +27,7 @@ class FlowUploadedFile extends UploadedFile * This is either the persistent identifier of a previously submitted resource file * or an array with the "__identity" key set to the persistent identifier. * - * @return array|string + * @return array{__identity: string}|string */ public function getOriginallySubmittedResource() { @@ -40,7 +40,8 @@ public function getOriginallySubmittedResource() * This is either the persistent identifier of a previously submitted resource file * or an array with the "__identity" key set to the persistent identifier. * - * @param array|string $originallySubmittedResource + * @param array{__identity: string}|string $originallySubmittedResource + * @return void */ public function setOriginallySubmittedResource($originallySubmittedResource) { @@ -57,6 +58,7 @@ public function getCollectionName() /** * @param string $collectionName + * @return void */ public function setCollectionName($collectionName) { diff --git a/Neos.Http.Factories/Classes/RequestFactoryTrait.php b/Neos.Http.Factories/Classes/RequestFactoryTrait.php index 364bfb21de..b840389da0 100644 --- a/Neos.Http.Factories/Classes/RequestFactoryTrait.php +++ b/Neos.Http.Factories/Classes/RequestFactoryTrait.php @@ -13,6 +13,7 @@ trait RequestFactoryTrait { /** + * @param non-empty-string $method * @inheritDoc */ public function createRequest(string $method, $uri): RequestInterface diff --git a/Neos.Http.Factories/Classes/ServerRequestFactoryTrait.php b/Neos.Http.Factories/Classes/ServerRequestFactoryTrait.php index b4be972e24..1208f5569f 100644 --- a/Neos.Http.Factories/Classes/ServerRequestFactoryTrait.php +++ b/Neos.Http.Factories/Classes/ServerRequestFactoryTrait.php @@ -56,6 +56,7 @@ public function __construct( /** * @inheritDoc + * @param array $serverParams */ public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface { diff --git a/Neos.Http.Factories/Classes/StreamFactoryTrait.php b/Neos.Http.Factories/Classes/StreamFactoryTrait.php index 6c79adcc84..f8201880bc 100644 --- a/Neos.Http.Factories/Classes/StreamFactoryTrait.php +++ b/Neos.Http.Factories/Classes/StreamFactoryTrait.php @@ -18,6 +18,9 @@ trait StreamFactoryTrait public function createStream(string $content = ''): StreamInterface { $fileHandle = fopen('php://temp', 'r+'); + if (!is_resource($fileHandle)) { + throw new \Exception('unable to open php://temp', 1743846274); + } fwrite($fileHandle, $content); rewind($fileHandle); @@ -30,11 +33,15 @@ public function createStream(string $content = ''): StreamInterface public function createStreamFromFile(string $filename, string $mode = 'r'): StreamInterface { $fileHandle = fopen($filename, $mode); + if (!is_resource($fileHandle)) { + throw new \Exception('unable to open ' . $filename, 1743846243); + } return $this->createStreamFromResource($fileHandle); } /** * @inheritDoc + * @param resource $resource */ public function createStreamFromResource($resource): StreamInterface { diff --git a/Neos.Kickstarter/Classes/Command/KickstartCommandController.php b/Neos.Kickstarter/Classes/Command/KickstartCommandController.php index 246b927c0c..7150c5ae49 100644 --- a/Neos.Kickstarter/Classes/Command/KickstartCommandController.php +++ b/Neos.Kickstarter/Classes/Command/KickstartCommandController.php @@ -47,6 +47,7 @@ class KickstartCommandController extends CommandController * * @param string $packageKey The package key, for example "MyCompany.MyPackageName" * @param string $packageType Optional package type, e.g. "neos-plugin" + * @return void * @see neos.flow:package:create */ public function packageCommand($packageKey, $packageType = PackageInterface::DEFAULT_COMPOSER_TYPE) @@ -99,6 +100,7 @@ public function packageCommand($packageKey, $packageType = PackageInterface::DEF * @param boolean $generateFusion If Fusion templates should be generated instead of Fluid. * @param boolean $generateRelated Also create the mentioned package, related model and repository if necessary. * @param boolean $force Overwrite any existing controller or template code. Regardless of this flag, the package, model and repository will never be overwritten. + * @return void * @see neos.kickstarter:kickstart:commandcontroller */ public function actionControllerCommand($packageKey, $controllerName, $generateActions = false, $generateTemplates = true, $generateFusion = false, $generateRelated = false, $force = false) @@ -193,6 +195,7 @@ public function actionControllerCommand($packageKey, $controllerName, $generateA * @param string $packageKey The package key of the package for the new controller * @param string $controllerName The name for the new controller. This may also be a comma separated list of controller names. * @param boolean $force Overwrite any existing controller. + * @return void * @see neos.kickstarter:kickstart:actioncontroller */ public function commandControllerCommand($packageKey, $controllerName, $force = false) @@ -220,6 +223,7 @@ public function commandControllerCommand($packageKey, $controllerName, $force = * @param string $packageKey The package key of the package for the domain model * @param string $modelName The name of the new domain model class * @param boolean $force Overwrite any existing model. + * @return void * @see neos.kickstarter:kickstart:repository */ public function modelCommand($packageKey, $modelName, $force = false) @@ -262,6 +266,7 @@ public function modelCommand($packageKey, $modelName, $force = false) * @param string $packageKey The package key * @param string $modelName The name of the domain model class * @param boolean $force Overwrite any existing repository. + * @return void * @see neos.kickstarter:kickstart:model */ public function repositoryCommand($packageKey, $modelName, $force = false) @@ -282,6 +287,7 @@ public function repositoryCommand($packageKey, $modelName, $force = false) * Generates a documentation skeleton for the given package. * * @param string $packageKey The package key of the package for the documentation + * @return void */ public function documentationCommand($packageKey) { @@ -303,7 +309,7 @@ public function documentationCommand($packageKey) * * @param string $packageKey The package key of the package for the translation * @param string $sourceLanguageKey The language key of the default language - * @param array $targetLanguageKeys Comma separated language keys for the target translations + * @param array $targetLanguageKeys Comma separated language keys for the target translations * @return void */ public function translationCommand($packageKey, $sourceLanguageKey, array $targetLanguageKeys = []) @@ -337,6 +343,7 @@ protected function validatePackageKey($packageKey) * Check the given model name to be not one of the reserved words of PHP. * * @param string $modelName + * @return void * @see http://www.php.net/manual/en/reserved.keywords.php */ protected function validateModelName($modelName) diff --git a/Neos.Kickstarter/Classes/Service/GeneratorService.php b/Neos.Kickstarter/Classes/Service/GeneratorService.php index e872b5f181..7ff7b55ba2 100644 --- a/Neos.Kickstarter/Classes/Service/GeneratorService.php +++ b/Neos.Kickstarter/Classes/Service/GeneratorService.php @@ -51,9 +51,9 @@ class GeneratorService protected $reflectionService; /** - * @var array + * @var array */ - protected $generatedFiles = []; + protected array $generatedFiles = []; /** * Generate a controller with the given name for the given package @@ -63,7 +63,7 @@ class GeneratorService * @param string $controllerName The name of the new controller * @param boolean $fusionView If the controller should default to a FusionView * @param boolean $overwrite Overwrite any existing files? - * @return array An array of generated filenames + * @return array An array of generated filenames */ public function generateActionController($packageKey, $subpackage, $controllerName, $fusionView = false, $overwrite = false) { @@ -102,7 +102,7 @@ public function generateActionController($packageKey, $subpackage, $controllerNa * @param string $controllerName The name of the new controller * @param boolean $fusionView If the controller should default to a FusionView * @param boolean $overwrite Overwrite any existing files? - * @return array An array of generated filenames + * @return array An array of generated filenames */ public function generateCrudController($packageKey, $subpackage, $controllerName, $fusionView = false, $overwrite = false) { @@ -143,7 +143,7 @@ public function generateCrudController($packageKey, $subpackage, $controllerName * @param string $packageKey The package key of the controller's package * @param string $controllerName The name of the new controller * @param boolean $overwrite Overwrite any existing files? - * @return array An array of generated filenames + * @return array An array of generated filenames */ public function generateCommandController($packageKey, $controllerName, $overwrite = false) { @@ -179,7 +179,7 @@ public function generateCommandController($packageKey, $controllerName, $overwri * @param string $viewName The name of the view * @param string $templateName The name of the view * @param boolean $overwrite Overwrite any existing files? - * @return array An array of generated filenames + * @return array An array of generated filenames */ public function generateView($packageKey, $subpackage, $controllerName, $viewName, $templateName, $overwrite = false) { @@ -199,7 +199,9 @@ public function generateView($packageKey, $subpackage, $controllerName, $viewNam $contextVariables['modelFullClassName'] = '\\' . trim($baseNamespace, '\\') . ($subpackage != '' ? '\\' . $subpackage : '') . '\Domain\Model\\' . $controllerName; $contextVariables['modelClassName'] = ucfirst($contextVariables['modelName']); - $modelClassSchema = $this->reflectionService->getClassSchema($contextVariables['modelFullClassName']); + $modelClassSchema = class_exists($contextVariables['modelFullClassName']) + ? $this->reflectionService->getClassSchema($contextVariables['modelFullClassName']) + : null; if ($modelClassSchema !== null) { $contextVariables['properties'] = $modelClassSchema->getProperties(); if (isset($contextVariables['properties']['Persistence_Object_Identifier'])) { @@ -229,7 +231,7 @@ public function generateView($packageKey, $subpackage, $controllerName, $viewNam * @param string $packageKey The package key of the controller's package * @param string $layoutName The name of the layout * @param boolean $overwrite Overwrite any existing files? - * @return array An array of generated filenames + * @return array An array of generated filenames */ public function generateLayout($packageKey, $layoutName, $overwrite = false) { @@ -261,7 +263,7 @@ public function generateLayout($packageKey, $layoutName, $overwrite = false) * @param string $viewName The name of the view * @param string $templateName The name of the view * @param boolean $overwrite Overwrite any existing files? - * @return array An array of generated filenames + * @return array An array of generated filenames */ public function generateFusion(string $packageKey, string $subpackage, string $controllerName, string $viewName, string $templateName, bool $overwrite = false): array { @@ -281,7 +283,9 @@ public function generateFusion(string $packageKey, string $subpackage, string $c $contextVariables['modelFullClassName'] = '\\' . trim($baseNamespace, '\\') . ($subpackage != '' ? '\\' . $subpackage : '') . '\Domain\Model\\' . $controllerName; $contextVariables['modelClassName'] = ucfirst($contextVariables['modelName']); - $modelClassSchema = $this->reflectionService->getClassSchema($contextVariables['modelFullClassName']); + $modelClassSchema = class_exists($contextVariables['modelFullClassName']) + ? $this->reflectionService->getClassSchema($contextVariables['modelFullClassName']) + : null; if ($modelClassSchema !== null) { $contextVariables['properties'] = $modelClassSchema->getProperties(); if (isset($contextVariables['properties']['Persistence_Object_Identifier'])) { @@ -311,7 +315,7 @@ public function generateFusion(string $packageKey, string $subpackage, string $c * @param string $packageKey The package key of the controller's package * @param string $layoutName The name of the layout * @param boolean $overwrite Overwrite any existing files? - * @return array An array of generated filenames + * @return array An array of generated filenames */ public function generatePrototype(string $packageKey, string $layoutName, bool $overwrite = false): array { @@ -340,9 +344,9 @@ public function generatePrototype(string $packageKey, string $layoutName, bool $ * * @param string $packageKey The package key of the controller's package * @param string $modelName The name of the new model - * @param array $fieldDefinitions The field definitions + * @param array $fieldDefinitions The field definitions * @param boolean $overwrite Overwrite any existing files? - * @return array An array of generated filenames + * @return array An array of generated filenames */ public function generateModel($packageKey, $modelName, array $fieldDefinitions, $overwrite = false) { @@ -378,7 +382,7 @@ public function generateModel($packageKey, $modelName, array $fieldDefinitions, * @param string $packageKey The package key of the controller's package * @param string $modelName The name of the new model fpr which to generate the test * @param boolean $overwrite Overwrite any existing files? - * @return array An array of generated filenames + * @return array An array of generated filenames */ public function generateTestsForModel($packageKey, $modelName, $overwrite = false) { @@ -411,7 +415,7 @@ public function generateTestsForModel($packageKey, $modelName, $overwrite = fals * @param string $packageKey The package key * @param string $modelName The name of the model * @param boolean $overwrite Overwrite any existing files? - * @return array An array of generated filenames + * @return array An array of generated filenames */ public function generateRepository($packageKey, $modelName, $overwrite = false) { @@ -443,7 +447,7 @@ public function generateRepository($packageKey, $modelName, $overwrite = false) * Generate a documentation skeleton for the package key * * @param string $packageKey The package key - * @return array An array of generated filenames + * @return array An array of generated filenames */ public function generateDocumentation($packageKey) { @@ -459,7 +463,7 @@ public function generateDocumentation($packageKey) $templatePathAndFilename = 'resource://Neos.Kickstarter/Private/Generator/Documentation/Makefile'; $fileContent = file_get_contents($templatePathAndFilename); $targetPathAndFilename = $documentationPath . '/Makefile'; - $this->generateFile($targetPathAndFilename, $fileContent); + $this->generateFile($targetPathAndFilename, $fileContent ?: ''); $templatePathAndFilename = 'resource://Neos.Kickstarter/Private/Generator/Documentation/index.rst'; $fileContent = $this->renderTemplate($templatePathAndFilename, $contextVariables); @@ -481,8 +485,8 @@ public function generateDocumentation($packageKey) * * @param string $packageKey * @param string $sourceLanguageKey - * @param array $targetLanguageKeys - * @return array An array of generated filenames + * @param array $targetLanguageKeys + * @return array An array of generated filenames */ public function generateTranslation($packageKey, $sourceLanguageKey, array $targetLanguageKeys = []) { @@ -516,9 +520,9 @@ public function generateTranslation($packageKey, $sourceLanguageKey, array $targ /** * Normalize types and prefix types with namespaces * - * @param array $fieldDefinitions The field definitions + * @param array $fieldDefinitions The field definitions * @param string $namespace The namespace - * @return array The normalized and type converted field definitions + * @return array The normalized and type converted field definitions */ protected function normalizeFieldDefinitions(array $fieldDefinitions, $namespace = '') { @@ -574,7 +578,7 @@ protected function generateFile($targetPathAndFilename, $fileContent, $force = f * Render the given template file with the given variables * * @param string $templatePathAndFilename - * @param array $contextVariables + * @param array $contextVariables * @return string * @throws \Neos\FluidAdaptor\Core\Exception */ @@ -588,7 +592,7 @@ protected function renderTemplate($templatePathAndFilename, array $contextVariab /** * @param PackageInterface $package - * @return array + * @return array */ protected function getPrimaryNamespaceAndEntryPath(PackageInterface $package) { diff --git a/Neos.Kickstarter/Classes/Utility/Inflector.php b/Neos.Kickstarter/Classes/Utility/Inflector.php index ed402234f7..49fa0eb222 100644 --- a/Neos.Kickstarter/Classes/Utility/Inflector.php +++ b/Neos.Kickstarter/Classes/Utility/Inflector.php @@ -56,6 +56,6 @@ public function humanizeCamelCase($camelCased, $lowercase = false) */ protected function spacify($camelCased, $glue = ' ') { - return preg_replace('/([a-z0-9])([A-Z])/', '$1' . $glue . '$2', $camelCased); + return preg_replace('/([a-z0-9])([A-Z])/', '$1' . $glue . '$2', $camelCased) ?: ''; } } diff --git a/Neos.Utility.Arrays/Classes/Arrays.php b/Neos.Utility.Arrays/Classes/Arrays.php index 71a44f2aeb..910ff7e032 100644 --- a/Neos.Utility.Arrays/Classes/Arrays.php +++ b/Neos.Utility.Arrays/Classes/Arrays.php @@ -22,9 +22,9 @@ abstract class Arrays * Explodes a $string delimited by $delimiter and passes each item in the array through intval(). * Corresponds to explode(), but with conversion to integers for all values. * - * @param string $delimiter Delimiter string to explode with + * @param non-empty-string $delimiter Delimiter string to explode with * @param string $string The string to explode - * @return array Exploded values, all converted to integers + * @return array Exploded values, all converted to integers */ public static function integerExplode(string $delimiter, string $string): array { @@ -41,10 +41,10 @@ public static function integerExplode(string $delimiter, string $string): array * Explodes a string and trims all values for whitespace in the ends. * If $onlyNonEmptyValues is set, then all blank ('') values are removed. * - * @param string $delimiter Delimiter string to explode with + * @param non-empty-string $delimiter Delimiter string to explode with * @param string $string The string to explode * @param boolean $onlyNonEmptyValues If disabled, even empty values (='') will be set in output - * @return array Exploded values + * @return array Exploded values */ public static function trimExplode(string $delimiter, string $string, bool $onlyNonEmptyValues = true): array { @@ -64,11 +64,11 @@ public static function trimExplode(string $delimiter, string $string, bool $only * in the first array ($firstArray) with the values of the second array ($secondArray) in case of identical keys, * ie. keeping the values of the second. * - * @param array $firstArray First array - * @param array $secondArray Second array, overruling the first array + * @param array $firstArray First array + * @param array $secondArray Second array, overruling the first array * @param boolean $dontAddNewKeys If set, keys that are NOT found in $firstArray (first array) will not be set. Thus only existing value can/will be overruled from second array. * @param boolean $emptyValuesOverride If set (which is the default), values from $secondArray will overrule if they are empty (according to PHP's empty() function) - * @return array Resulting array where $secondArray values has overruled $firstArray values + * @return array Resulting array where $secondArray values has overruled $firstArray values */ public static function arrayMergeRecursiveOverrule(array $firstArray, array $secondArray, bool $dontAddNewKeys = false, bool $emptyValuesOverride = true): array { @@ -109,13 +109,13 @@ public static function arrayMergeRecursiveOverrule(array $firstArray, array $sec * Merges two arrays recursively and "binary safe" (integer keys are overridden as well), overruling similar values in the first array ($firstArray) with the values of the second array ($secondArray) * In case of identical keys, ie. keeping the values of the second. The given $toArray closure will be used if one of the two array keys contains an array and the other not. It should return an array. * - * @param array $firstArray First array - * @param array $secondArray Second array, overruling the first array + * @param array $firstArray First array + * @param array $secondArray Second array, overruling the first array * @param \Closure $toArray The given callable will get a value that is not an array and has to return an array. * This is to allow custom merging of simple types with (sub) arrays * @param \Closure|null $overrideFirst The given callable will determine whether the value of the first array should be overridden. * It should have the following signature $callable($key, ?array $firstValue = null, ?array $secondValue = null): bool - * @return array Resulting array where $secondArray values has overruled $firstArray values + * @return array Resulting array where $secondArray values has overruled $firstArray values */ public static function arrayMergeRecursiveOverruleWithCallback(array $firstArray, array $secondArray, \Closure $toArray, ?\Closure $overrideFirst = null): array { @@ -157,8 +157,7 @@ public static function arrayMergeRecursiveOverruleWithCallback(array $firstArray /** * Returns true if the given array contains elements of varying types * - * @param array $array - * @return boolean + * @param array $array */ public static function containsMultipleTypes(array $array): bool { @@ -179,12 +178,13 @@ public static function containsMultipleTypes(array $array): bool * Replacement for array_reduce that allows any type for $initial (instead * of only integer) * - * @param array $array the array to reduce - * @param string $function the reduce function with the same order of parameters as in the native array_reduce (i.e. accumulator first, then current array element) + * @phpstan-param callable-string $function + * @param array $array the array to reduce + * @param callable $function the reduce function with the same order of parameters as in the native array_reduce (i.e. accumulator first, then current array element) * @param mixed $initial the initial accumulator value * @return mixed */ - public static function array_reduce(array $array, string $function, $initial = null) + public static function array_reduce(array $array, callable $function, $initial = null) { $accumulator = $initial; foreach ($array as $value) { @@ -196,8 +196,8 @@ public static function array_reduce(array $array, string $function, $initial = n /** * Returns the value of a nested array by following the specifed path. * - * @param array $array The array to traverse - * @param array|string $path The path to follow. Either a simple array of keys or a string in the format 'foo.bar.baz' + * @param array $array The array to traverse + * @param array|string $path The path to follow. Either a simple array of keys or a string in the format 'foo.bar.baz' * @return mixed The value found, NULL if the path didn't exist (note there is no way to distinguish between a found NULL value and "path not found") */ public static function getValueByPath(array $array, array|string $path): mixed @@ -222,8 +222,8 @@ public static function getValueByPath(array $array, array|string $path): mixed * See {@see ValueAccessor} * * @internal experimental feature, not stable API - * @param array $array The array to traverse - * @param array|string $path The path to follow. Either a simple array of keys or a string in the format 'foo.bar.baz' + * @param array $array The array to traverse + * @param array|string $path The path to follow. Either a simple array of keys or a string in the format 'foo.bar.baz' * @return ValueAccessor */ public static function getAccessorByPath(array $array, array|string $path): ValueAccessor @@ -235,16 +235,17 @@ public static function getAccessorByPath(array $array, array|string $path): Valu /** * Sets the given value in a nested array or object by following the specified path. * - * @param array|\ArrayAccess $subject The array or ArrayAccess instance to work on - * @param array|string $path The path to follow. Either a simple array of keys or a string in the format 'foo.bar.baz' + * @param array|\ArrayAccess $subject The array or ArrayAccess instance to work on + * @param array|string $path The path to follow. Either a simple array of keys or a string in the format 'foo.bar.baz' * @param mixed $value The value to set - * @return array|\ArrayAccess The modified array or object + * @return array|\ArrayAccess The modified array or object * @throws \InvalidArgumentException */ public static function setValueByPath($subject, $path, $value) { + /** @phpstan-ignore booleanAnd.alwaysFalse (annotations may be wrong) */ if (!is_array($subject) && !($subject instanceof \ArrayAccess)) { - throw new \InvalidArgumentException('setValueByPath() expects $subject to be array or an object implementing \ArrayAccess, "' . (is_object($subject) ? get_class($subject) : gettype($subject)) . '" given.', 1306424308); + throw new \InvalidArgumentException('setValueByPath() expects $subject to be array or an object implementing \ArrayAccess, "' . get_debug_type($subject) . '" given.', 1306424308); } if (is_string($path)) { $path = explode('.', $path); @@ -266,9 +267,9 @@ public static function setValueByPath($subject, $path, $value) /** * Unsets an element/part of a nested array by following the specified path. * - * @param array $array The array - * @param array|string $path The path to follow. Either a simple array of keys or a string in the format 'foo.bar.baz' - * @return array The modified array + * @param array $array The array + * @param array|string $path The path to follow. Either a simple array of keys or a string in the format 'foo.bar.baz' + * @return array The modified array * @throws \InvalidArgumentException */ public static function unsetValueByPath(array $array, $path): array @@ -293,7 +294,7 @@ public static function unsetValueByPath(array $array, $path): array /** * Sorts multidimensional arrays by recursively calling ksort on its elements. * - * @param array $array the array to sort + * @param array $array the array to sort * @param integer $sortFlags may be used to modify the sorting behavior using these values (see http://www.php.net/manual/en/function.sort.php) * @return boolean true on success, false on failure * @see asort() @@ -314,7 +315,7 @@ public static function sortKeysRecursively(array &$array, int $sortFlags = \SORT * Recursively convert an object hierarchy into an associative array. * * @param mixed $subject An object or array of objects - * @return array The subject represented as an array + * @return array The subject represented as an array * @throws \InvalidArgumentException */ public static function convertObjectToArray($subject): array @@ -336,8 +337,8 @@ public static function convertObjectToArray($subject): array /** * Recursively removes empty array elements. * - * @param array $array - * @return array the modified array + * @param array $array + * @return array the modified array */ public static function removeEmptyElementsRecursively(array $array): array { diff --git a/Neos.Utility.Arrays/Classes/PositionalArraySorter.php b/Neos.Utility.Arrays/Classes/PositionalArraySorter.php index e900ddd58d..fd05be60ed 100644 --- a/Neos.Utility.Arrays/Classes/PositionalArraySorter.php +++ b/Neos.Utility.Arrays/Classes/PositionalArraySorter.php @@ -44,18 +44,33 @@ */ final class PositionalArraySorter { + /** + * @var array + */ private array $startKeys; + /** + * @var array + */ private array $middleKeys; + /** + * @var array + */ private array $endKeys; + /** + * @var array + */ private array $beforeKeys; + /** + * @var array + */ private array $afterKeys; /** - * @param array $subject The source array to sort + * @param array $subject The source array to sort * @param string $positionPropertyPath optional property path to the string that contains the position * @param bool $removeNullValues if set to TRUE (default), null-values of the subject are removed */ @@ -69,7 +84,7 @@ public function __construct( /** * Returns a sorted copy of the subject array * - * @return array + * @return array * @throws Exception\InvalidPositionException */ public function toArray(): array @@ -87,7 +102,7 @@ public function toArray(): array * * TODO Detect circles in after / before dependencies (#52185) * - * @return array an ordered list of keys + * @return array an ordered list of keys * @throws Exception\InvalidPositionException if the positional string has an unsupported format */ public function getSortedKeys(): array @@ -112,6 +127,8 @@ public function getSortedKeys(): array * Extracts all "middle" keys from $arrayKeysWithPosition. Those are all keys with a numeric position. * The result is a multidimensional arrays where the KEY of each array is a PRIORITY and the VALUE is an array of matching KEYS * This also removes matching keys from the given $arrayKeysWithPosition + * + * @param array $arrayKeysWithPosition */ private function extractMiddleKeys(array &$arrayKeysWithPosition): void { @@ -130,6 +147,8 @@ private function extractMiddleKeys(array &$arrayKeysWithPosition): void * Extracts all "start" keys from $arrayKeysWithPosition. Those are all keys with a position starting with "start" * The result is a multidimensional arrays where the KEY of each array is a PRIORITY and the VALUE is an array of matching KEYS * This also removes matching keys from the given $arrayKeysWithPosition + * + * @param array $arrayKeysWithPosition */ private function extractStartKeys(array &$arrayKeysWithPosition): void { @@ -152,6 +171,8 @@ private function extractStartKeys(array &$arrayKeysWithPosition): void * Extracts all "end" keys from $arrayKeysWithPosition. Those are all keys with a position starting with "end" * The result is a multidimensional arrays where the KEY of each array is a PRIORITY and the VALUE is an array of matching KEYS * This also removes matching keys from the given $arrayKeysWithPosition + * + * @param array $arrayKeysWithPosition */ private function extractEndKeys(array &$arrayKeysWithPosition): void { @@ -174,6 +195,9 @@ private function extractEndKeys(array &$arrayKeysWithPosition): void * Extracts all "before" keys from $arrayKeysWithPosition. Those are all keys with a position starting with "before" * The result is a multidimensional arrays where the KEY of each array is a PRIORITY and the VALUE is an array of matching KEYS * This also removes matching keys from the given $arrayKeysWithPosition + * + * @param array $arrayKeysWithPosition + * @param array $existingKeys */ private function extractBeforeKeys(array &$arrayKeysWithPosition, array $existingKeys): void { @@ -201,6 +225,9 @@ private function extractBeforeKeys(array &$arrayKeysWithPosition, array $existin * Extracts all "after" keys from $arrayKeysWithPosition. Those are all keys with a position starting with "after" * The result is a multidimensional arrays where the KEY of each array is a PRIORITY and the VALUE is an array of matching KEYS * This also removes matching keys from the given $arrayKeysWithPosition + * + * @param array $arrayKeysWithPosition + * @param array $existingKeys */ private function extractAfterKeys(array &$arrayKeysWithPosition, array $existingKeys): void { @@ -228,7 +255,7 @@ private function extractAfterKeys(array &$arrayKeysWithPosition, array $existing * Collect the array keys inside $this->subject with each position meta-argument. * If there is no position but the array is numerically ordered, we use the array index as position. * - * @return array an associative array where each key of $subject has a position string assigned + * @return array an associative array where each key of $subject has a position string assigned */ private function collectArrayKeysAndPositions(): array { @@ -253,6 +280,8 @@ private function collectArrayKeysAndPositions(): array /** * Flattens start-, middle-, end-, before- and afterKeys to a single dimension and merges them together to a single array + * + * @return array */ private function generateSortedKeysMap(): array { diff --git a/Neos.Utility.Arrays/Classes/ValueAccessor.php b/Neos.Utility.Arrays/Classes/ValueAccessor.php index 060ee0c8d7..54e0cd1179 100644 --- a/Neos.Utility.Arrays/Classes/ValueAccessor.php +++ b/Neos.Utility.Arrays/Classes/ValueAccessor.php @@ -47,6 +47,7 @@ public static function forValue(mixed $value): self /** * @internal You should use {@see ValueAccessor::forValue} instead + * @param array $path */ public static function forValueInPath(mixed $value, array|string $path): self { @@ -97,6 +98,9 @@ public function classString(): string throw $this->createTypeError("is not a class-string"); } + /** + * @return array + */ public function array(): array { if (is_array($this->value)) { @@ -161,6 +165,9 @@ public function classStringOrNull(): ?string throw $this->createTypeError("is not a class-string"); } + /** + * @return array|null + */ public function arrayOrNull(): ?array { if (is_array($this->value) || is_null($this->value)) { @@ -182,6 +189,10 @@ public function instanceOfOrNull(string $className): ?object throw $this->createTypeError(sprintf('is not an instance of %s or null', $className)); } + /** + * @param string $message + * @return \UnexpectedValueException + */ private function createTypeError($message): \UnexpectedValueException { return new \UnexpectedValueException(get_debug_type($this->value) . ' ' . $message . ($this->additionalErrorMessage ? ' ' . $this->additionalErrorMessage : '')); diff --git a/Neos.Utility.Files/Classes/Files.php b/Neos.Utility.Files/Classes/Files.php index b0ff9b5b91..228e4dbe87 100644 --- a/Neos.Utility.Files/Classes/Files.php +++ b/Neos.Utility.Files/Classes/Files.php @@ -32,7 +32,7 @@ public static function getUnixStylePath(string $path): string if (strpos($path, ':') === false) { return str_replace(['//', '\\'], '/', $path); } - return preg_replace('/^([a-z]{2,}):\//', '$1://', str_replace(['//', '\\'], '/', $path)); + return preg_replace('/^([a-z]{2,}):\//', '$1://', str_replace(['//', '\\'], '/', $path)) ?: ''; } /** @@ -53,7 +53,7 @@ public static function getNormalizedPath(string $path): string * Note: trailing slashes will be removed, leading slashes won't. * Usage: concatenatePaths(array('dir1/dir2', 'dir3', 'file')) * - * @param array $paths the file paths to be combined. Last array element may include the filename. + * @param array $paths the file paths to be combined. Last array element may include the filename. * @return string concatenated path without trailing slash. * @see getUnixStylePath() * @api @@ -80,10 +80,10 @@ public static function concatenatePaths(array $paths): string * directories. * * @param string $path Path to the directory which shall be read - * @param string $suffix If specified, only filenames with this extension are returned (eg. ".php" or "foo.bar") + * @param ?string $suffix If specified, only filenames with this extension are returned (eg. ".php" or "foo.bar") * @param boolean $returnRealPath If turned on, all paths are resolved by calling realpath() * @param boolean $returnDotFiles If turned on, also files beginning with a dot will be returned - * @return array Filenames including full path + * @return array Filenames including full path * @api */ public static function readDirectoryRecursively(string $path, ?string $suffix = null, bool $returnRealPath = false, bool $returnDotFiles = false): array @@ -122,7 +122,14 @@ public static function getRecursiveDirectoryGenerator(string $path, ?string $suf if (is_dir($pathAndFilename)) { array_push($directories, self::getNormalizedPath($pathAndFilename)); } elseif ($suffix === null || strpos(strrev($filename), strrev($suffix)) === 0) { - yield static::getUnixStylePath(($returnRealPath === true) ? realpath($pathAndFilename) : $pathAndFilename); + if ($returnRealPath) { + $nonRealPathAndFilename = $pathAndFilename; + $pathAndFilename = realpath($pathAndFilename); + if ($pathAndFilename === false) { + throw new \RuntimeException(sprintf('Cannot get realpath for "%s". $returnRealPath cannot be used with stream wrappers.', $nonRealPathAndFilename), 1765548187); + } + } + yield static::getUnixStylePath($pathAndFilename); } } closedir($handle); @@ -153,6 +160,9 @@ public static function emptyDirectoryRecursively(string $path) } else { $directoryIterator = new \RecursiveDirectoryIterator($path); foreach ($directoryIterator as $fileInfo) { + if (is_string($fileInfo)) { + continue; + } if (!$fileInfo->isDir()) { if (self::unlink($fileInfo->getPathname()) !== true) { throw new FilesException('Could not unlink file "' . $fileInfo->getPathname() . '".', 1169047619); @@ -322,14 +332,12 @@ public static function copyDirectoryRecursively(string $sourceDirectory, string */ public static function getFileContents(string $pathAndFilename, int $flags = 0, $context = null, int $offset = 0, int $maximumLength = -1) { - if ($flags === true) { - $flags = FILE_USE_INCLUDE_PATH; - } + $useIncludePath = ($flags & FILE_USE_INCLUDE_PATH) === 1; try { if ($maximumLength > -1) { - $content = file_get_contents($pathAndFilename, $flags, $context, $offset, $maximumLength); + $content = file_get_contents($pathAndFilename, $useIncludePath, $context, $offset, $maximumLength); } else { - $content = file_get_contents($pathAndFilename, $flags, $context, $offset); + $content = file_get_contents($pathAndFilename, $useIncludePath, $context, $offset); } } catch (ErrorException $ignoredException) { $content = false; @@ -386,7 +394,7 @@ public static function is_link(string $pathAndFilename): bool return false; } $normalizedPathAndFilename = strtolower(rtrim(self::getUnixStylePath($pathAndFilename), '/')); - $normalizedTargetPathAndFilename = strtolower(self::getUnixStylePath(realpath($pathAndFilename))); + $normalizedTargetPathAndFilename = strtolower(self::getUnixStylePath(realpath($pathAndFilename) ?: '')); if ($normalizedTargetPathAndFilename === '') { return false; } @@ -431,24 +439,26 @@ public static function unlink(string $pathAndFilename): bool /** * Supported file size units for the byte conversion functions below * - * @var array + * @var array */ - protected static $sizeUnits = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + protected static array $sizeUnits = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; /** * Converts an integer with a byte count into human-readable form * - * @param float|integer $bytes - * @param integer $decimals number of decimal places in the resulting string - * @param string $decimalSeparator decimal separator of the resulting string - * @param string $thousandsSeparator thousands separator of the resulting string + * @param float|int $bytes + * @param int|null $decimals number of decimal places in the resulting string + * @param string|null $decimalSeparator decimal separator of the resulting string + * @param string|null $thousandsSeparator thousands separator of the resulting string * @return string the size string, e.g. "1,024 MB" */ public static function bytesToSizeString($bytes, ?int $decimals = null, ?string $decimalSeparator = null, ?string $thousandsSeparator = null): string { + /** @phpstan-ignore booleanAnd.alwaysFalse (annotations may be wrong) */ if (!is_int($bytes) && !is_float($bytes)) { if (is_numeric($bytes)) { $bytes = (float)$bytes; + /** @phpstan-ignore else.unreachable (annotations may be wrong) */ } else { $bytes = 0; } @@ -502,7 +512,7 @@ public static function sizeStringToBytes(string $sizeString): float if ($pow === false) { throw new FilesException(sprintf('Unknown file size unit "%s"', $matches['unit']), 1417695299); } - return $size * pow(2, (10 * $pow)); + return $size * pow(2, (10 * (int)$pow)); } /** diff --git a/Neos.Utility.MediaTypes/Classes/MediaTypes.php b/Neos.Utility.MediaTypes/Classes/MediaTypes.php index 249d21ced8..104b94a91c 100644 --- a/Neos.Utility.MediaTypes/Classes/MediaTypes.php +++ b/Neos.Utility.MediaTypes/Classes/MediaTypes.php @@ -33,7 +33,7 @@ abstract class MediaTypes /** * A map of file extensions to Internet Media Types * - * @var array + * @var array */ private static $extensionToMediaType = [ '3dml' => 'text/vnd.in3d.3dml', @@ -1027,7 +1027,7 @@ abstract class MediaTypes /** * A map of Internet Media Types to file extensions * - * @var array + * @var array> */ private static $mediaTypeToFileExtension = [ 'application/andrew-inset' => ['ez'], @@ -1821,13 +1821,13 @@ public static function getMediaTypeFromFilename(string $filename): string * Returns a Media Type based on the file content * * @param string $fileContent The file content do determine the media type from - * @return string The IANA Internet Media Type + * @return string|null The IANA Internet Media Type */ - public static function getMediaTypeFromFileContent(string $fileContent): string + public static function getMediaTypeFromFileContent(string $fileContent): ?string { $fileInfo = new \finfo(FILEINFO_MIME); - $mediaType = self::trimMediaType($fileInfo->buffer($fileContent)); - return isset(self::$mediaTypeToFileExtension[$mediaType]) ? $mediaType : 'application/octet-stream'; + $mediaType = self::trimMediaType($fileInfo->buffer($fileContent) ?: ''); + return ($mediaType === null || isset(self::$mediaTypeToFileExtension[$mediaType])) ? $mediaType : 'application/octet-stream'; } /** @@ -1846,7 +1846,7 @@ public static function getFilenameExtensionFromMediaType(string $mediaType): str * Returns all possible filename extensions based on the given Media Type. * * @param string $mediaType The IANA Internet Media Type, for example "text/html" - * @return array The corresponding filename extensions, for example ("html", "htm") + * @return array The corresponding filename extensions, for example ("html", "htm") * @api */ public static function getFilenameExtensionsFromMediaType(string $mediaType): array @@ -1867,7 +1867,7 @@ public static function getFilenameExtensionsFromMediaType(string $mediaType): ar * "parameters" => an array of parameter names and values, array("charset" => "UTF-8") * * @param string $rawMediaType The raw media type, for example "application/json; charset=UTF-8" - * @return array An associative array with parsed information + * @return array{type: string, subtype: string, parameters: array} An associative array with parsed information */ public static function parseMediaType(string $rawMediaType): array { @@ -1921,7 +1921,7 @@ public static function mediaRangeMatches(string $mediaRange, string $mediaType): * and subtype in the format "type/subtype". * * @param string $rawMediaType The full media type, for example "application/json; charset=UTF-8" - * @return string Just the type and subtype, for example "application/json" + * @return string|null Just the type and subtype, for example "application/json" */ public static function trimMediaType(string $rawMediaType) { diff --git a/Neos.Utility.ObjectHandling/Classes/ObjectAccess.php b/Neos.Utility.ObjectHandling/Classes/ObjectAccess.php index 89decda676..e5f0c166ed 100644 --- a/Neos.Utility.ObjectHandling/Classes/ObjectAccess.php +++ b/Neos.Utility.ObjectHandling/Classes/ObjectAccess.php @@ -31,15 +31,15 @@ abstract class ObjectAccess { /** * Internal RuntimeCache for getGettablePropertyNames() - * @var array + * @var array,array> */ - protected static $gettablePropertyNamesCache = []; + protected static array $gettablePropertyNamesCache = []; /** * Internal RuntimeCache for getPropertyInternal() - * @var array + * @var array */ - protected static $propertyGetterCache = []; + protected static array $propertyGetterCache = []; const ACCESS_GET = 0; const ACCESS_SET = 1; @@ -58,8 +58,8 @@ abstract class ObjectAccess * - if public property exists, return the value of it. * - else, throw exception * - * @param mixed $subject Object or array to get the property from - * @param string|integer $propertyName Name or index of the property to retrieve + * @param object|array $subject Object or array to get the property from + * @param string|int $propertyName Name or index of the property to retrieve * @param boolean $forceDirectAccess Directly access property using reflection(!) * @return mixed Value of the property * @throws \InvalidArgumentException in case $subject was not an object or $propertyName was not a string @@ -67,9 +67,11 @@ abstract class ObjectAccess */ public static function getProperty($subject, $propertyName, bool $forceDirectAccess = false) { + /** @phpstan-ignore booleanAnd.alwaysFalse (annotations may be wrong) */ if (!is_object($subject) && !is_array($subject)) { throw new \InvalidArgumentException('$subject must be an object or array, ' . gettype($subject) . ' given.', 1237301367); } + /** @phpstan-ignore booleanAnd.alwaysFalse (annotations may be wrong) */ if (!is_string($propertyName) && !is_int($propertyName)) { throw new \InvalidArgumentException('Given property name/index is not of type string or integer.', 1231178303); } @@ -91,14 +93,14 @@ public static function getProperty($subject, $propertyName, bool $forceDirectAcc * of type string you should use getProperty() instead. * * @param mixed $subject Object or array to get the property from - * @param string $propertyName name of the property to retrieve + * @param string|int $propertyName name of the property to retrieve * @param boolean $forceDirectAccess directly access property using reflection(!) * @param boolean $propertyExists (by reference) will be set to true if the specified property exists and is gettable * @return mixed Value of the property * @throws PropertyNotAccessibleException * @see getProperty() */ - protected static function getPropertyInternal($subject, string $propertyName, bool $forceDirectAccess, bool &$propertyExists) + protected static function getPropertyInternal($subject, string|int $propertyName, bool $forceDirectAccess, bool &$propertyExists) { if ($subject === null) { return null; @@ -111,6 +113,10 @@ protected static function getPropertyInternal($subject, string $propertyName, bo return null; } + if (is_int($propertyName)) { + throw new \InvalidArgumentException('Cannot use integer property names for objects', 1743799241); + } + $propertyExists = true; $className = TypeHandling::getTypeForValue($subject); @@ -230,7 +236,7 @@ public static function getPropertyPath($subject, string $propertyPath) * on it without checking if it existed. * - else, return false * - * @param mixed $subject The target object or array + * @param array|object $subject The target object or array * @param string|integer $propertyName Name or index of the property to set * @param mixed $propertyValue Value of the property * @param boolean $forceDirectAccess directly access property using reflection(!) @@ -239,6 +245,7 @@ public static function getPropertyPath($subject, string $propertyPath) */ public static function setProperty(&$subject, $propertyName, $propertyValue, bool $forceDirectAccess = false): bool { + /** @phpstan-ignore booleanAnd.alwaysFalse (annotations may be wrong) */ if (!is_string($propertyName) && !is_int($propertyName)) { throw new \InvalidArgumentException('Given property name/index is not of type string or integer.', 1231178878); } @@ -261,8 +268,8 @@ public static function setProperty(&$subject, $propertyName, $propertyValue, boo $propertyReflection = new \ReflectionProperty($className, $propertyName); $propertyReflection->setAccessible(true); $propertyReflection->setValue($subject, $propertyValue); - } elseif ($subject instanceof ProxyInterface && property_exists(get_parent_class($className), $propertyName)) { - $propertyReflection = new \ReflectionProperty(get_parent_class($className), $propertyName); + } elseif ($subject instanceof ProxyInterface && property_exists(get_parent_class($className) ?: $className, $propertyName)) { + $propertyReflection = new \ReflectionProperty(get_parent_class($className) ?: $className, $propertyName); $propertyReflection->setAccessible(true); $propertyReflection->setValue($subject, $propertyValue); } else { @@ -290,7 +297,7 @@ public static function setProperty(&$subject, $propertyName, $propertyValue, boo * - public properties which can be directly get. * * @param object $object Object to receive property names for - * @return array Array of all gettable property names + * @return array Array of all gettable property names * @throws \InvalidArgumentException */ public static function getGettablePropertyNames($object): array @@ -336,7 +343,7 @@ public static function getGettablePropertyNames($object): array * - public properties which can be directly set. * * @param object $object Object to receive property names for - * @return array Array of all settable property names + * @return array Array of all settable property names * @throws \InvalidArgumentException */ public static function getSettablePropertyNames($object): array @@ -376,6 +383,7 @@ public static function isPropertySettable($object, string $propertyName): bool throw new \InvalidArgumentException('$object must be an object, ' . gettype($object) . ' given.', 1259828920); } + /** @var string $className safe for objects */ $className = TypeHandling::getTypeForValue($object); if (($object instanceof \stdClass && array_key_exists($propertyName, get_object_vars($object))) || array_key_exists($propertyName, get_class_vars($className))) { return true; @@ -412,7 +420,7 @@ public static function isPropertyGettable($object, string $propertyName): bool * $object that are accessible through this class. * * @param object $object Object to get all properties from. - * @return array Associative array of all properties. + * @return array Associative array of all properties. * @throws \InvalidArgumentException * @todo What to do with ArrayAccess */ diff --git a/Neos.Utility.ObjectHandling/Classes/TypeHandling.php b/Neos.Utility.ObjectHandling/Classes/TypeHandling.php index c078b86b71..a134b02504 100644 --- a/Neos.Utility.ObjectHandling/Classes/TypeHandling.php +++ b/Neos.Utility.ObjectHandling/Classes/TypeHandling.php @@ -31,16 +31,16 @@ abstract class TypeHandling const LITERAL_TYPE_PATTERN = '/^(?:integer|int|float|double|boolean|bool|string)$/'; /** - * @var array + * @var array>> */ - protected static $collectionTypes = ['array', \Traversable::class]; + protected static array $collectionTypes = ['array', \Traversable::class]; /** * Returns an array with type information, including element type for * collection types (array, SplObjectStorage, ...) * * @param string $type Type of the property (see PARSE_TYPE_PATTERN) - * @return array An array with information about the type + * @return array{type: string, elementType: ?string, nullable: bool} An array with information about the type * @throws InvalidTypeException */ public static function parseType(string $type): array @@ -52,7 +52,7 @@ public static function parseType(string $type): array $typeWithoutNull = self::stripNullableType($type); $isNullable = $typeWithoutNull !== $type || $type === 'null'; - $type = self::normalizeType($matches['type']); + $type = self::normalizeType($matches['type'] ?? ''); $elementType = isset($matches['elementType']) ? self::normalizeType($matches['elementType']) : null; if ($elementType !== null && !self::isCollectionType($type)) { @@ -116,7 +116,7 @@ public static function isSimpleType(string $type): bool /** * Returns true if the $type is a collection type. * - * @param string $type + * @param string|class-string $type * @return boolean */ public static function isCollectionType(string $type): bool @@ -127,8 +127,11 @@ public static function isCollectionType(string $type): bool if (class_exists($type) === true || interface_exists($type) === true) { foreach (self::$collectionTypes as $collectionType) { - if (is_subclass_of($type, $collectionType) === true) { - return true; + if (class_exists($collectionType) || interface_exists($collectionType)) { + /** @var class-string<\Traversable> $collectionType */ + if (is_subclass_of($type, $collectionType) === true) { + return true; + } } } } @@ -185,7 +188,7 @@ public static function stripNullableType($type) if (stripos($type, 'null') === false) { return $type; } - return preg_replace('/(\\|null|null\\|)/i', '', $type); + return preg_replace('/(\\|null|null\\|)/i', '', $type) ?: ''; } /** @@ -199,12 +202,12 @@ public static function getTypeForValue($value): string if (is_object($value)) { if ($value instanceof Proxy) { $type = get_parent_class($value); - } else { - $type = get_class($value); + if ($type !== false) { + return $type; + } } - } else { - $type = gettype($value); + return get_class($value); } - return $type; + return gettype($value); } } diff --git a/Neos.Utility.Pdo/Classes/PdoHelper.php b/Neos.Utility.Pdo/Classes/PdoHelper.php index 873ef34621..40ac1dac76 100644 --- a/Neos.Utility.Pdo/Classes/PdoHelper.php +++ b/Neos.Utility.Pdo/Classes/PdoHelper.php @@ -33,7 +33,7 @@ abstract class PdoHelper * @param \PDO $databaseHandle * @param string $pdoDriver * @param string $pathAndFilename - * @param array $replacePairs every key in this array will be replaced with the corresponding value in the loaded SQL (example: ['###CACHE_TABLE_NAME###' => 'caches', '###TAGS_TABLE_NAME###' => 'tags']) + * @param array $replacePairs every key in this array will be replaced with the corresponding value in the loaded SQL (example: ['###CACHE_TABLE_NAME###' => 'caches', '###TAGS_TABLE_NAME###' => 'tags']) * @return void */ public static function importSql(\PDO $databaseHandle, string $pdoDriver, string $pathAndFilename, array $replacePairs = []) @@ -46,13 +46,13 @@ public static function importSql(\PDO $databaseHandle, string $pdoDriver, string } else { $sql = file($pathAndFilename, FILE_IGNORE_NEW_LINES & FILE_SKIP_EMPTY_LINES); // Remove MySQL style key length delimiters (yuck!) if we are not setting up a MySQL db - if ($pdoDriver !== 'mysql') { + if ($sql !== false && $pdoDriver !== 'mysql') { $sql = preg_replace('/"\([0-9]+\)/', '"', $sql); } } $statement = ''; - foreach ($sql as $line) { + foreach ($sql ?: [] as $line) { $statement .= ' ' . trim(strtr($line, $replacePairs)); if (substr($statement, -1) === ';') { $databaseHandle->exec($statement); diff --git a/Neos.Utility.Schema/Classes/SchemaGenerator.php b/Neos.Utility.Schema/Classes/SchemaGenerator.php index 07a977c120..5ac82327d2 100644 --- a/Neos.Utility.Schema/Classes/SchemaGenerator.php +++ b/Neos.Utility.Schema/Classes/SchemaGenerator.php @@ -26,7 +26,7 @@ class SchemaGenerator * Generate a schema for the given value * * @param mixed $value value to create a schema for - * @return array schema as array structure + * @return array schema as array structure */ public function generate($value): array { @@ -62,8 +62,8 @@ public function generate($value): array /** * Create a schema for a dictionary * - * @param array $dictionaryValue - * @return array + * @param array $dictionaryValue + * @return array{type: string, properties: array} */ protected function generateDictionarySchema(array $dictionaryValue): array { @@ -78,8 +78,8 @@ protected function generateDictionarySchema(array $dictionaryValue): array /** * Create a schema for an array structure * - * @param array $arrayValue - * @return array schema + * @param array $arrayValue + * @return array schema */ protected function generateArraySchema(array $arrayValue): array { @@ -96,7 +96,7 @@ protected function generateArraySchema(array $arrayValue): array * Create a schema for a given string * * @param string $stringValue - * @return array + * @return array */ protected function generateStringSchema(string $stringValue): array { @@ -122,7 +122,7 @@ protected function generateStringSchema(string $stringValue): array * Compact an array of items to avoid adding the same value more than once. * If the result contains only one item, that item is returned directly. * - * @param array $values array of values + * @param array $values array of values * @return mixed */ protected function filterDuplicatesFromArray(array $values) diff --git a/Neos.Utility.Schema/Classes/SchemaValidator.php b/Neos.Utility.Schema/Classes/SchemaValidator.php index 64fec01df2..82427d9827 100644 --- a/Neos.Utility.Schema/Classes/SchemaValidator.php +++ b/Neos.Utility.Schema/Classes/SchemaValidator.php @@ -69,7 +69,7 @@ class SchemaValidator * * @param mixed $value value to validate * @param mixed $schema type as string, schema or array of schemas - * @param array $types the additional type schemas + * @param array $types the additional type schemas * @return ErrorResult */ public function validate($value, $schema, array $types = []): ErrorResult @@ -147,8 +147,8 @@ public function validate($value, $schema, array $types = []): ErrorResult * Validate a value for a given type * * @param mixed $value - * @param array $schema - * @param array $types + * @param array $schema + * @param array $types * @return ErrorResult */ protected function validateType($value, array $schema, array $types = []): ErrorResult @@ -209,8 +209,8 @@ protected function validateType($value, array $schema, array $types = []): Error * Validate a value with a given list of allowed types * * @param mixed $value - * @param array $schema - * @param array $types + * @param array $schema + * @param array $types * @return ErrorResult */ protected function validateTypeArray($value, array $schema, array $types = []): ErrorResult @@ -254,7 +254,7 @@ protected function validateTypeArray($value, array $schema, array $types = []): * - divisibleBy : value is divisibleBy the given number * * @param mixed $value - * @param array $schema + * @param array $schema * @return ErrorResult */ protected function validateNumberType($value, array $schema): ErrorResult @@ -305,7 +305,7 @@ protected function validateNumberType($value, array $schema): ErrorResult * * @see SchemaValidator::validateNumberType * @param mixed $value - * @param array $schema + * @param array $schema * @return ErrorResult */ protected function validateIntegerType($value, array $schema): ErrorResult @@ -323,7 +323,7 @@ protected function validateIntegerType($value, array $schema): ErrorResult * Validate a boolean value with the given schema * * @param mixed $value - * @param array $schema + * @param array $schema * @return ErrorResult */ protected function validateBooleanType($value, array $schema): ErrorResult @@ -346,8 +346,8 @@ protected function validateBooleanType($value, array $schema): ErrorResult * - uniqueItems : allow only unique values * * @param mixed $value - * @param array $schema - * @param array $types + * @param array $schema + * @param array $types * @return ErrorResult */ protected function validateArrayType($value, array $schema, array $types = []): ErrorResult @@ -404,8 +404,8 @@ protected function validateArrayType($value, array $schema, array $types = []): * - additionalProperties : if false is given all additionalProperties are forbidden, if a schema is given all additional properties have to match the schema * * @param mixed $value - * @param array $schema - * @param array $types + * @param array $schema + * @param array $types * @return ErrorResult */ protected function validateDictionaryType($value, array $schema, array $types = []): ErrorResult @@ -496,8 +496,8 @@ protected function validateDictionaryType($value, array $schema, array $types = * [date-time|date|time|uri|email|ipv4|ipv6|ip-address|host-name|class-name|interface-name] * * @param mixed $value - * @param array $schema - * @param array $types + * @param array $schema + * @param array $types * @return ErrorResult */ protected function validateStringType($value, array $schema, array $types = []): ErrorResult @@ -530,6 +530,7 @@ protected function validateStringType($value, array $schema, array $types = []): switch ($schema['format']) { case 'date-time': // YYYY-MM-DDThh:mm:ssZ ISO8601 + /** @phpstan-ignore staticMethod.resultUnused (we only care about the error) */ \DateTime::createFromFormat(\DateTime::ISO8601, $value); $parseErrors = \DateTime::getLastErrors(); if ($parseErrors && $parseErrors['error_count'] > 0) { @@ -538,6 +539,7 @@ protected function validateStringType($value, array $schema, array $types = []): break; case 'date': // YYYY-MM-DD + /** @phpstan-ignore staticMethod.resultUnused (we only care about the error) */ \DateTime::createFromFormat('Y-m-d', $value); $parseErrors = \DateTime::getLastErrors(); if ($parseErrors && $parseErrors['error_count'] > 0) { @@ -546,6 +548,7 @@ protected function validateStringType($value, array $schema, array $types = []): break; case 'time': // hh:mm:ss + /** @phpstan-ignore staticMethod.resultUnused (we only care about the error) */ \DateTime::createFromFormat('H:i:s', $value); $parseErrors = \DateTime::getLastErrors(); if ($parseErrors && $parseErrors['error_count'] > 0) { @@ -604,7 +607,7 @@ protected function validateStringType($value, array $schema, array $types = []): * Validate a null value with the given schema * * @param mixed $value - * @param array $schema + * @param array $schema * @return ErrorResult */ protected function validateNullType($value, array $schema): ErrorResult @@ -620,7 +623,7 @@ protected function validateNullType($value, array $schema): ErrorResult * Validate any value with the given schema. Return always a valid Result. * * @param mixed $value - * @param array $schema + * @param array $schema * @return ErrorResult */ protected function validateAnyType($value, array $schema): ErrorResult @@ -665,7 +668,7 @@ protected function createError(string $expectation, $value = null): Error * Determine whether the given php array is a schema or not * * @todo there should be a more sophisticated way to detect schemas - * @param array $phpArray + * @param array $phpArray * @return boolean */ protected function isSchema(array $phpArray): bool @@ -677,7 +680,7 @@ protected function isSchema(array $phpArray): bool /** * Determine whether the given php array is a plain numerically indexed array * - * @param array $phpArray + * @param array $phpArray * @return boolean */ protected function isNumericallyIndexedArray(array $phpArray): bool @@ -693,7 +696,7 @@ protected function isNumericallyIndexedArray(array $phpArray): bool /** * Determine whether the given php array is a Dictionary (has no numeric identifiers) * - * @param array $phpArray + * @param array $phpArray * @return boolean */ protected function isDictionary(array $phpArray): bool diff --git a/Neos.Utility.Unicode/Classes/Functions.php b/Neos.Utility.Unicode/Classes/Functions.php index a13429ebb5..12cfd22a11 100644 --- a/Neos.Utility.Unicode/Classes/Functions.php +++ b/Neos.Utility.Unicode/Classes/Functions.php @@ -31,7 +31,7 @@ public static function strtotitle(string $string): string { $result = ''; $splitIntoLowerCaseWords = preg_split("/([\n\r\t ])/", self::strtolower($string), -1, PREG_SPLIT_DELIM_CAPTURE); - foreach ($splitIntoLowerCaseWords as $delimiterOrValue) { + foreach ($splitIntoLowerCaseWords ?: [] as $delimiterOrValue) { $result .= self::strtoupper(self::substr($delimiterOrValue, 0, 1)) . self::substr($delimiterOrValue, 1); } return $result; @@ -133,7 +133,7 @@ public static function lcfirst(string $string): string * @param string $haystack UTF-8 string to search in * @param string $needle UTF-8 string to search for * @param integer $offset Positition to start the search - * @return integer The character position + * @return integer|false The character position * @api */ public static function strpos(string $haystack, string $needle, int $offset = 0) @@ -154,16 +154,19 @@ public static function strpos(string $haystack, string $needle, int $offset = 0) * @see http://www.php.net/manual/en/function.pathinfo.php * * @param string $path - * @param integer $options Optional, one of PATHINFO_DIRNAME, PATHINFO_BASENAME, PATHINFO_EXTENSION or PATHINFO_FILENAME. - * @return string|array + * @param integer|null $options Optional, one of PATHINFO_DIRNAME, PATHINFO_BASENAME, PATHINFO_EXTENSION or PATHINFO_FILENAME. + * @return string|array{dirname: string, basename: string, extension: string, filename: string} * @api */ - public static function pathinfo(string $path, ?int $options = null) + public static function pathinfo(string $path, ?int $options = null): string|array { + /** @var string $currentLocale we assume the current locale to be properly set */ + /** @phpstan-ignore argument.type (int is allowed for locales) */ $currentLocale = setlocale(LC_CTYPE, 0); // Before we have a setting for setlocale, his should suffice for pathinfo // to work correctly on Unicode strings setlocale(LC_CTYPE, 'en_US.UTF-8'); + /** @var string|array{dirname: string, basename: string, extension: string, filename: string} $pathinfo */ $pathinfo = $options == null ? pathinfo($path) : pathinfo($path, $options); setlocale(LC_CTYPE, $currentLocale); return $pathinfo; @@ -188,8 +191,11 @@ public static function parse_url(string $url, int $component = -1) $encodedUrl = preg_replace_callback('%[^:@/?#&=\.]+%usD', function ($matches) { return urlencode($matches[0]); }, $url); - $components = parse_url($encodedUrl); + if ($encodedUrl === null) { + return false; + } + $components = parse_url($encodedUrl); if ($components === false) { return false; } diff --git a/Neos.Utility.Unicode/Classes/TextIterator.php b/Neos.Utility.Unicode/Classes/TextIterator.php index 862a05c204..2af09dd48d 100644 --- a/Neos.Utility.Unicode/Classes/TextIterator.php +++ b/Neos.Utility.Unicode/Classes/TextIterator.php @@ -19,6 +19,7 @@ /** * A UTF8-aware TextIterator * + * @implements \Iterator */ class TextIterator implements \Iterator { @@ -68,12 +69,12 @@ class TextIterator implements \Iterator protected $currentPosition; /** - * @var \ArrayObject + * @var \ArrayObject */ protected $iteratorCache; /** - * @var \ArrayIterator + * @var \ArrayIterator */ protected $iteratorCacheIterator; @@ -109,11 +110,11 @@ public function __construct(string $subject, int $iteratorType = self::CHARACTER /** * Returns the current element * - * @return string The value of the current element + * @return string|null The value of the current element */ - public function current(): string + public function current(): ?string { - return $this->getCurrentElement()->getValue(); + return $this->getCurrentElement()?->getValue(); } /** @@ -123,7 +124,7 @@ public function current(): string */ public function next(): void { - $this->previousElement = $this->getCurrentElement(); + $this->previousElement = $this->getCurrentElement() ?: $this->previousElement; $this->iteratorCacheIterator->next(); } @@ -164,11 +165,11 @@ public function rewind(): void /** * Returns the offset in the original given string of the current element * - * @return integer The offset of the current element + * @return int|null The offset of the current element, if any */ - public function offset(): int + public function offset(): ?int { - return $this->getCurrentElement()->getOffset(); + return $this->getCurrentElement()?->getOffset(); } /** @@ -194,7 +195,8 @@ public function last(): string $previousElement = $this->getCurrentElement(); $this->next(); } - return $previousElement->getValue(); + // can never be null because the iterator cannot be empty + return $previousElement?->getValue() ?: ''; } /** @@ -202,15 +204,15 @@ public function last(): string * given by its offset * * @param integer $offset The offset of the character - * @return int The offset of the element following this character + * @return int|null The offset of the element following this character or null if the offset is out of bounds */ - public function following(int $offset): int + public function following(int $offset): ?int { $this->rewind(); while ($this->valid()) { $this->next(); $nextElement = $this->getCurrentElement(); - if ($nextElement->getOffset() >= $offset) { + if ($nextElement && $nextElement->getOffset() >= $offset) { return $nextElement->getOffset(); } } @@ -231,7 +233,7 @@ public function preceding(int $offset): int $previousElement = $this->getCurrentElement(); $this->next(); $currentElement = $this->getCurrentElement(); - if (($currentElement->getOffset() + $currentElement->getLength()) >= $offset) { + if ($previousElement && $currentElement && ($currentElement->getOffset() + $currentElement->getLength()) >= $offset) { return $previousElement->getOffset() + $previousElement->getLength(); } } @@ -254,20 +256,21 @@ public function preceding(int $offset): int */ public function isBoundary(): bool { - return $this->getCurrentElement()->isBoundary(); + return $this->getCurrentElement()?->isBoundary() ?: false; } /** * Returns all elements of the iterator in an array * - * @return array All elements of the iterator + * @return array All elements of the iterator */ public function getAll(): array { $this->rewind(); $allValues = []; while ($this->valid()) { - $allValues[] = $this->getCurrentElement()->getValue(); + // will never be null while valid + $allValues[] = $this->getCurrentElement()?->getValue() ?: ''; $this->next(); } return $allValues; @@ -276,7 +279,7 @@ public function getAll(): array /** * @throws UnsupportedFeatureException */ - public function getRuleStatus() + public function getRuleStatus(): never { throw new UnsupportedFeatureException('getRuleStatus() is not supported.', 1210849057); } @@ -284,7 +287,7 @@ public function getRuleStatus() /** * @throws UnsupportedFeatureException */ - public function getRuleStatusArray() + public function getRuleStatusArray(): never { throw new UnsupportedFeatureException('getRuleStatusArray() is not supported.', 1210849076); } @@ -292,7 +295,7 @@ public function getRuleStatusArray() /** * @throws UnsupportedFeatureException */ - public function getAvailableLocales() + public function getAvailableLocales(): never { throw new UnsupportedFeatureException('getAvailableLocales() is not supported.', 1210849105); } @@ -305,7 +308,8 @@ public function getAvailableLocales() public function first(): string { $this->rewind(); - return $this->getCurrentElement()->getValue(); + // can never be empty, will at least contain empty string + return $this->getCurrentElement()?->getValue() ?: ''; } /** @@ -346,7 +350,7 @@ private function generateIteratorElements() private function parseSubjectByCharacter(): void { $i = 0; - foreach (preg_split('//u', $this->subject) as $currentCharacter) { + foreach (preg_split('//u', $this->subject) ?: [] as $currentCharacter) { if ($currentCharacter === '') { continue; } @@ -373,7 +377,7 @@ private function parseSubjectByWord() $this->iteratorCache->append(new TextIteratorElement(' ', $i, 1, true)); $j = 0; - $splittedWord = preg_split('/' . self::REGEXP_SENTENCE_DELIMITERS . '/', $currentWord); + $splittedWord = preg_split('/' . self::REGEXP_SENTENCE_DELIMITERS . '/', $currentWord) ?: []; foreach ($splittedWord as $currentPart) { if ($currentPart !== '') { $this->iteratorCache->append(new TextIteratorElement($currentPart, $i, Unicode\Functions::strlen($currentPart), false)); @@ -442,7 +446,7 @@ private function parseSubjectBySentence() $count = 0; $delimitersMatches = []; preg_match_all('/' . self::REGEXP_SENTENCE_DELIMITERS . '/', $this->subject, $delimitersMatches); - $splittedSentence = preg_split('/' . self::REGEXP_SENTENCE_DELIMITERS . '/', $this->subject); + $splittedSentence = preg_split('/' . self::REGEXP_SENTENCE_DELIMITERS . '/', $this->subject) ?: []; if (count($splittedSentence) == 1) { $this->iteratorCache->append(new TextIteratorElement($splittedSentence[0], 0, Unicode\Functions::strlen($splittedSentence[0]), false)); @@ -480,6 +484,7 @@ private function parseSubjectBySentence() * Helper function to get the current element from the cache. * * @return TextIteratorElement|null The current element of the cache + * @phpstan-ignore return.unusedType (can be null if next() leaves the valid range of the iterator) */ private function getCurrentElement() { diff --git a/composer.json b/composer.json index 2da6973341..ddc2981598 100644 --- a/composer.json +++ b/composer.json @@ -10,9 +10,11 @@ "../../flow doctrine:migrate --quiet", "../../bin/behat -f progress -c Neos.Flow/Tests/Behavior/behat.yml" ], - "lint:phpstan": "../../bin/phpstan analyse", + "lint:phpstan-legacy": "../../bin/phpstan analyse -c phpstan-legacy.neon.dist", + "lint:phpstan": "../../bin/phpstan analyse -c phpstan.neon.dist", "lint": [ - "@lint:phpstan" + "@lint:phpstan", + "@lint:phpstan-legacy" ] }, "require": { diff --git a/phpstan-legacy.neon.dist b/phpstan-legacy.neon.dist new file mode 100644 index 0000000000..168406b3ec --- /dev/null +++ b/phpstan-legacy.neon.dist @@ -0,0 +1,20 @@ +# packages we yet only lint with lvl 3 - thus _legacy_ configuration :) +parameters: + level: 3 + paths: + - Neos.Cache/Classes + - Neos.Eel/Classes + - Neos.Error.Messages/Classes + - Neos.Flow/Classes + bootstrapFiles: + - bootstrap-phpstan.php + excludePaths: + analyse: + - Neos.Flow/.phpstorm.meta.php + # The parsers are autogenerated / extending autogenerated code and not analysable + - Neos.Eel/Classes/FlowQuery/FizzleParser.php + - Neos.Eel/Classes/AbstractParser.php + - Neos.Eel/Classes/EelParser.php + - Neos.Eel/Classes/InterpretedEelParser.php + - Neos.Eel/Classes/CompilingEelParser.php + - Neos.Flow/Classes/Security/Authorization/Privilege/Entity/Doctrine/EntityPrivilegeExpressionEvaluator.php diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 9b730bf93b..e568d138a5 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,10 +1,6 @@ parameters: - level: 3 + level: 8 paths: - - Neos.Cache/Classes - - Neos.Eel/Classes - - Neos.Error.Messages/Classes - - Neos.Flow/Classes - Neos.Flow.Log/Classes - Neos.FluidAdaptor/Classes - Neos.Http.Factories/Classes @@ -29,3 +25,6 @@ parameters: - Neos.Eel/Classes/InterpretedEelParser.php - Neos.Eel/Classes/CompilingEelParser.php - Neos.Flow/Classes/Security/Authorization/Privilege/Entity/Doctrine/EntityPrivilegeExpressionEvaluator.php + scanDirectories: + - Neos.Flow/Tests + - Neos.Flow/Classes/Error