From 0326ac66a63d3bd6042c25a36400ba6516d5e40d Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Sat, 28 Nov 2020 21:46:04 +0100 Subject: [PATCH 01/32] TASK: Allow doctrine/orm 2.8.x-dev to test PHP 8 compatibility --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 30988591ac..2d16648be8 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "psr/http-server-middleware": "^1.0", "psr/http-server-handler": "^1.0", "ramsey/uuid": "^3.0 || ^4.0", - "doctrine/orm": "^2.7", + "doctrine/orm": "^2.7 || 2.8.x-dev", "doctrine/migrations": "^3.0", "doctrine/dbal": "^2.12", "doctrine/common": "^2.13.1 || ^3.0", From 7093af56c98cd0ade1920477d5b67fde0cb062c6 Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Sun, 3 Jan 2021 16:55:50 +0100 Subject: [PATCH 02/32] TASK: Conditionally invoke libxml_disable_entity_loader See https://www.php.net/manual/de/migration80.deprecated.php#migration80.deprecated.libxml --- .../Property/TypeConverter/MediaTypeConverter.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Neos.Flow/Classes/Property/TypeConverter/MediaTypeConverter.php b/Neos.Flow/Classes/Property/TypeConverter/MediaTypeConverter.php index c88575101e..ba341ee2b1 100644 --- a/Neos.Flow/Classes/Property/TypeConverter/MediaTypeConverter.php +++ b/Neos.Flow/Classes/Property/TypeConverter/MediaTypeConverter.php @@ -92,12 +92,19 @@ protected function convertMediaType($requestBody, $mediaType) } break; case 'xml': - $entityLoaderValue = libxml_disable_entity_loader(true); + // TODO: Remove those lines once the minimum PHP version is 8.0 + if (PHP_MAJOR_VERSION < 8) { + $entityLoaderValue = libxml_disable_entity_loader(true); + } try { $xmlElement = new \SimpleXMLElement(urldecode($requestBody), LIBXML_NOERROR); - libxml_disable_entity_loader($entityLoaderValue); + if (PHP_MAJOR_VERSION < 8) { + libxml_disable_entity_loader($entityLoaderValue); + } } catch (\Exception $exception) { - libxml_disable_entity_loader($entityLoaderValue); + if (PHP_MAJOR_VERSION < 8) { + libxml_disable_entity_loader($entityLoaderValue); + } return []; } $result = Arrays::convertObjectToArray($xmlElement); From 5169338bccbd288a6ea4a8ac829f739cef060abf Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Sun, 3 Jan 2021 18:18:41 +0100 Subject: [PATCH 03/32] TASK: Remove usage of ReflectionParamater::isArray and ReflectionParameter::getClass This method is deprecated in favor of getType(). See https://www.php.net/manual/de/migration80.deprecated.php#migration80.deprecated.reflection --- .../Classes/Reflection/ReflectionService.php | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Neos.Flow/Classes/Reflection/ReflectionService.php b/Neos.Flow/Classes/Reflection/ReflectionService.php index a713acf471..66d539d753 100644 --- a/Neos.Flow/Classes/Reflection/ReflectionService.php +++ b/Neos.Flow/Classes/Reflection/ReflectionService.php @@ -1788,9 +1788,6 @@ protected function convertParameterReflectionToArray(ParameterReflection $parame if ($parameter->isPassedByReference()) { $parameterInformation[self::DATA_PARAMETER_BY_REFERENCE] = true; } - if ($parameter->isArray()) { - $parameterInformation[self::DATA_PARAMETER_ARRAY] = true; - } if ($parameter->isOptional()) { $parameterInformation[self::DATA_PARAMETER_OPTIONAL] = true; } @@ -1800,11 +1797,20 @@ protected function convertParameterReflectionToArray(ParameterReflection $parame $parameterType = $parameter->getType(); if ($parameterType !== null) { + // TODO: This needs to handle ReflectionUnionType $parameterType = ($parameterType instanceof \ReflectionNamedType) ? $parameterType->getName() : $parameterType->__toString(); } - if ($parameter->getClass() !== null) { + if ($parameterType !== null && !TypeHandling::isSimpleType($parameterType)) { // We use parameter type here to make class_alias usage work and return the hinted class name instead of the alias $parameterInformation[self::DATA_PARAMETER_CLASS] = $parameterType; + } elseif ($parameterType === 'array') { + $parameterInformation[self::DATA_PARAMETER_ARRAY] = true; + } else { + $builtinType = $parameter->getBuiltinType(); + if ($builtinType !== null) { + $parameterInformation[self::DATA_PARAMETER_TYPE] = $builtinType; + $parameterInformation[self::DATA_PARAMETER_SCALAR_DECLARATION] = true; + } } if ($parameter->isOptional() && $parameter->isDefaultValueAvailable()) { $parameterInformation[self::DATA_PARAMETER_DEFAULT_VALUE] = $parameter->getDefaultValue(); @@ -1816,17 +1822,10 @@ protected function convertParameterReflectionToArray(ParameterReflection $parame $parameterType = $this->expandType($method->getDeclaringClass(), $explodedParameters[0]); } } - if (!$parameter->isArray()) { - $builtinType = $parameter->getBuiltinType(); - if ($builtinType !== null) { - $parameterInformation[self::DATA_PARAMETER_TYPE] = $builtinType; - $parameterInformation[self::DATA_PARAMETER_SCALAR_DECLARATION] = true; - } - } if (!isset($parameterInformation[self::DATA_PARAMETER_TYPE]) && $parameterType !== null) { $parameterInformation[self::DATA_PARAMETER_TYPE] = $this->cleanClassName($parameterType); } elseif (!isset($parameterInformation[self::DATA_PARAMETER_TYPE])) { - $parameterInformation[self::DATA_PARAMETER_TYPE] = $parameter->isArray() ? 'array' : 'mixed'; + $parameterInformation[self::DATA_PARAMETER_TYPE] = 'mixed'; } return $parameterInformation; From 9077b6f7feda5933acb2cb144315893f90d45ea3 Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Sun, 3 Jan 2021 19:08:42 +0100 Subject: [PATCH 04/32] TASK: Avoid named parameter passing in Signal DispatcherTest --- Neos.Flow/Tests/Unit/SignalSlot/DispatcherTest.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Neos.Flow/Tests/Unit/SignalSlot/DispatcherTest.php b/Neos.Flow/Tests/Unit/SignalSlot/DispatcherTest.php index c7228a9103..6fa074ce2c 100644 --- a/Neos.Flow/Tests/Unit/SignalSlot/DispatcherTest.php +++ b/Neos.Flow/Tests/Unit/SignalSlot/DispatcherTest.php @@ -144,7 +144,7 @@ public function dispatchPassesTheSignalArgumentsToTheSlotMethod(): void $dispatcher->connect('Foo', 'bar', $mockSlot, '', false); $dispatcher->injectObjectManager($mockObjectManager); - $dispatcher->dispatch('Foo', 'bar', ['foo' => 'bar', 'baz' => 'quux']); + $dispatcher->dispatch('Foo', 'bar', ['bar', 'quux']); self::assertSame(['bar', 'quux'], $arguments); } @@ -160,7 +160,7 @@ public function dispatchPassesTheSignalArgumentsToTheStaticSlotMethod(): void $dispatcher->connect('Foo', 'bar', get_class($this), '::staticSlot', false); $dispatcher->injectObjectManager($mockObjectManager); - $dispatcher->dispatch('Foo', 'bar', ['foo' => 'bar', 'baz' => 'quux']); + $dispatcher->dispatch('Foo', 'bar', ['bar', 'quux']); self::assertSame(['bar', 'quux'], self::$arguments); } @@ -172,8 +172,8 @@ public function dispatchPassesTheSignalArgumentsToTheStaticSlotMethodIfNoObjectm $dispatcher = new Dispatcher(); $dispatcher->connect('Foo', 'bar', get_class($this), '::staticSlot', false); - $dispatcher->dispatch('Foo', 'bar', ['no' => 'object', 'manager' => 'exists']); - self::assertSame(['object', 'exists'], self::$arguments); + $dispatcher->dispatch('Foo', 'bar', ['no', 'object', 'manager', 'exists']); + self::assertSame(['no', 'object', 'manager', 'exists'], self::$arguments); } /** @@ -210,7 +210,7 @@ public function dispatchRetrievesSlotInstanceFromTheObjectManagerIfOnlyAClassNam $dispatcher->injectObjectManager($mockObjectManager); $dispatcher->connect('Foo', 'bar', $slotClassName, 'slot', false); - $dispatcher->dispatch('Foo', 'bar', ['foo' => 'bar', 'baz' => 'quux']); + $dispatcher->dispatch('Foo', 'bar', ['bar', 'quux']); self::assertSame($mockSlot->arguments, ['bar', 'quux']); } @@ -247,7 +247,7 @@ public function dispatchThrowsAnExceptionIfTheSpecifiedSlotMethodDoesNotExist(): $dispatcher->injectObjectManager($mockObjectManager); $dispatcher->connect('Foo', 'bar', $slotClassName, 'unknownMethodName', true); - $dispatcher->dispatch('Foo', 'bar', ['foo' => 'bar', 'baz' => 'quux']); + $dispatcher->dispatch('Foo', 'bar', ['bar', 'quux']); } /** @@ -266,7 +266,7 @@ public function dispatchPassesArgumentContainingSlotInformationLastIfTheConnecti $dispatcher->connect('SignalClassName', 'methodName', $mockSlot, '', true); $dispatcher->injectObjectManager($mockObjectManager); - $dispatcher->dispatch('SignalClassName', 'methodName', ['foo' => 'bar', 'baz' => 'quux']); + $dispatcher->dispatch('SignalClassName', 'methodName', ['bar', 'quux']); self::assertSame(['bar', 'quux', 'SignalClassName::methodName'], $arguments); } From 75616133a78e30fdad28c34b4d801dc30ed938e7 Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Sun, 3 Jan 2021 20:02:20 +0100 Subject: [PATCH 05/32] TASK: Fix PhpAnalyzer for PHP8 See https://www.php.net/manual/en/migration80.incompatible.php#migration80.incompatible.tokenizer --- Neos.Flow/Classes/Utility/PhpAnalyzer.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Neos.Flow/Classes/Utility/PhpAnalyzer.php b/Neos.Flow/Classes/Utility/PhpAnalyzer.php index 2914e5a26e..8af705c423 100644 --- a/Neos.Flow/Classes/Utility/PhpAnalyzer.php +++ b/Neos.Flow/Classes/Utility/PhpAnalyzer.php @@ -82,6 +82,9 @@ public function extractNamespace(): ?string break; } list($type, $value) = $token; + if (defined('T_NAME_QUALIFIED') && $type === T_NAME_QUALIFIED) { + return $value; + } if ($type === T_STRING) { $namespaceParts[] = $value; continue; From 3cfe0c9d2d1476c272cf3f654bc5c452fa3c82e2 Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Sun, 3 Jan 2021 20:57:48 +0100 Subject: [PATCH 06/32] TASK: Fix PhpAnalyzer for PHP8 Fully qualified namespaces emit a `T_NAME_FULLY_QUALIFIED` token in PHP8. --- Neos.Flow/Classes/Utility/PhpAnalyzer.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Neos.Flow/Classes/Utility/PhpAnalyzer.php b/Neos.Flow/Classes/Utility/PhpAnalyzer.php index 8af705c423..ef04a58904 100644 --- a/Neos.Flow/Classes/Utility/PhpAnalyzer.php +++ b/Neos.Flow/Classes/Utility/PhpAnalyzer.php @@ -85,6 +85,9 @@ public function extractNamespace(): ?string if (defined('T_NAME_QUALIFIED') && $type === T_NAME_QUALIFIED) { return $value; } + if (defined('T_NAME_FULLY_QUALIFIED') && $type === T_NAME_FULLY_QUALIFIED) { + return ltrim($value, '\\'); + } if ($type === T_STRING) { $namespaceParts[] = $value; continue; From e083f680dd49bd38f65bb7848b972657c9b5184e Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Wed, 24 Feb 2021 22:11:23 +0100 Subject: [PATCH 07/32] TASK: Enable PHP 8.0 build --- .github/workflows/build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 007262dc78..84e1df6abb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,11 +28,11 @@ jobs: dependencies: 'highest' # Experimental build for PHP 8 - #- php-versions: '8.0' - # composer-arguments: '--ignore-platform-reqs' - # static-analysis: 'no' - # experimental: true - # dependencies: 'highest' + - php-versions: '8.0' + #composer-arguments: '--ignore-platform-reqs' + static-analysis: 'no' + experimental: true + dependencies: 'highest' # Build for minimum dependencies. Fails right now, hence deactivated. #- php-versions: '7.3' From d84c96b0993590cc440474bbc39c122be5d33afd Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Wed, 24 Feb 2021 23:22:45 +0100 Subject: [PATCH 08/32] BUGFIX: Fix signal named arguments --- Neos.Flow/Classes/SignalSlot/Dispatcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Neos.Flow/Classes/SignalSlot/Dispatcher.php b/Neos.Flow/Classes/SignalSlot/Dispatcher.php index 5f212184ad..e3dae7f6ff 100644 --- a/Neos.Flow/Classes/SignalSlot/Dispatcher.php +++ b/Neos.Flow/Classes/SignalSlot/Dispatcher.php @@ -183,7 +183,7 @@ public function dispatch(string $signalClassName, string $signalName, array $sig $finalSignalArguments[] = $signalClassName . '::' . $signalName; } // Need to use call_user_func_array here, because $object may be the class name when the slot is a static method - call_user_func_array([$object, $slotInformation['method']], $finalSignalArguments); + call_user_func_array([$object, $slotInformation['method']], array_values($finalSignalArguments)); } } } From 0da755f2144cde306a2b8f04803a51378f486d8c Mon Sep 17 00:00:00 2001 From: bwaidelich Date: Wed, 27 Jan 2021 13:19:38 +0100 Subject: [PATCH 09/32] FEATURE: Increase PHP 8 compatibility Related: #2233 --- Neos.Flow/Classes/Core/LockManager.php | 4 +++- Neos.Flow/Classes/Reflection/ParameterReflection.php | 4 ++-- Neos.Flow/Classes/SignalSlot/Dispatcher.php | 2 +- Neos.Flow/Classes/Utility/PhpAnalyzer.php | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Neos.Flow/Classes/Core/LockManager.php b/Neos.Flow/Classes/Core/LockManager.php index 818883900a..1a858a112f 100644 --- a/Neos.Flow/Classes/Core/LockManager.php +++ b/Neos.Flow/Classes/Core/LockManager.php @@ -135,7 +135,9 @@ public function unlockSite() fclose($this->lockResource); unlink($this->lockPathAndFilename); } - @unlink($this->lockFlagPathAndFilename); + if (file_exists($this->lockFlagPathAndFilename)) { + @unlink($this->lockFlagPathAndFilename); + } } /** diff --git a/Neos.Flow/Classes/Reflection/ParameterReflection.php b/Neos.Flow/Classes/Reflection/ParameterReflection.php index 130faac76d..86db6a3b35 100644 --- a/Neos.Flow/Classes/Reflection/ParameterReflection.php +++ b/Neos.Flow/Classes/Reflection/ParameterReflection.php @@ -57,9 +57,9 @@ public function getClass() public function getBuiltinType() { $type = $this->getType(); - if ($type === null || !$type->isBuiltin()) { + if (!$type instanceof \ReflectionNamedType) { return null; } - return $type instanceof \ReflectionNamedType ? $type->getName() : (string)$type; + return $type->isBuiltin() ? $type->getName() : null; } } diff --git a/Neos.Flow/Classes/SignalSlot/Dispatcher.php b/Neos.Flow/Classes/SignalSlot/Dispatcher.php index e3dae7f6ff..4ff4f5c05e 100644 --- a/Neos.Flow/Classes/SignalSlot/Dispatcher.php +++ b/Neos.Flow/Classes/SignalSlot/Dispatcher.php @@ -149,7 +149,7 @@ public function dispatch(string $signalClassName, string $signalName, array $sig } foreach ($this->slots[$signalClassName][$signalName] as $slotInformation) { - $finalSignalArguments = $signalArguments; + $finalSignalArguments = array_values($signalArguments); if (isset($slotInformation['object'])) { $object = $slotInformation['object']; } elseif (strpos($slotInformation['method'], '::') === 0) { diff --git a/Neos.Flow/Classes/Utility/PhpAnalyzer.php b/Neos.Flow/Classes/Utility/PhpAnalyzer.php index ef04a58904..7e9cbebdd0 100644 --- a/Neos.Flow/Classes/Utility/PhpAnalyzer.php +++ b/Neos.Flow/Classes/Utility/PhpAnalyzer.php @@ -89,7 +89,7 @@ public function extractNamespace(): ?string return ltrim($value, '\\'); } if ($type === T_STRING) { - $namespaceParts[] = $value; + $namespaceParts[] = ltrim($value, '\\'); continue; } if ($type !== T_NS_SEPARATOR && $type !== T_WHITESPACE) { From c6eae5025c244ecf8df16a55b7dffb1b62b2490a Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Thu, 25 Feb 2021 08:59:52 +0100 Subject: [PATCH 10/32] TASK: Handle potential exceptions in unlink PHP8 will ignore some shutup operators and still raise errors, which will be converted to an Exception by our ErrorHandler. --- Neos.Cache/Classes/Backend/FileBackend.php | 4 +++- Neos.Flow/Classes/Core/LockManager.php | 12 ++++++++---- Neos.Flow/Classes/Package/PackageManager.php | 4 +++- Neos.Utility.Files/Classes/Files.php | 4 +++- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Neos.Cache/Classes/Backend/FileBackend.php b/Neos.Cache/Classes/Backend/FileBackend.php index 2ed3c9b9ac..ff3e220774 100644 --- a/Neos.Cache/Classes/Backend/FileBackend.php +++ b/Neos.Cache/Classes/Backend/FileBackend.php @@ -281,7 +281,9 @@ public function flush(): void { Files::emptyDirectoryRecursively($this->cacheDirectory); if ($this->frozen === true) { - @unlink($this->cacheDirectory . 'FrozenCache.data'); + try { + @unlink($this->cacheDirectory . 'FrozenCache.data'); + } catch (\Throwable $e) {} $this->frozen = false; } } diff --git a/Neos.Flow/Classes/Core/LockManager.php b/Neos.Flow/Classes/Core/LockManager.php index 1a858a112f..217c2990bd 100644 --- a/Neos.Flow/Classes/Core/LockManager.php +++ b/Neos.Flow/Classes/Core/LockManager.php @@ -79,8 +79,10 @@ protected function removeExpiredLock() if (filemtime($this->lockFlagPathAndFilename) >= (time() - self::LOCKFILE_MAXIMUM_AGE)) { return; } - @unlink($this->lockFlagPathAndFilename); - @unlink($this->lockPathAndFilename); + try { + @unlink($this->lockFlagPathAndFilename); + @unlink($this->lockPathAndFilename); + } catch (\Throwable $e) {} } /** @@ -135,8 +137,10 @@ public function unlockSite() fclose($this->lockResource); unlink($this->lockPathAndFilename); } - if (file_exists($this->lockFlagPathAndFilename)) { - @unlink($this->lockFlagPathAndFilename); + if ($this->isSiteLocked()) { + try { + @unlink($this->lockFlagPathAndFilename); + } catch (\Throwable $e) {} } } diff --git a/Neos.Flow/Classes/Package/PackageManager.php b/Neos.Flow/Classes/Package/PackageManager.php index 41ecbf6377..62f51913a1 100644 --- a/Neos.Flow/Classes/Package/PackageManager.php +++ b/Neos.Flow/Classes/Package/PackageManager.php @@ -764,7 +764,9 @@ protected function savePackageStates(array $orderedPackageStates): void // Clean legacy file TODO: Remove at some point $legacyPackageStatesPath = FLOW_PATH_CONFIGURATION . 'PackageStates.php'; if (is_file($legacyPackageStatesPath)) { - @unlink($legacyPackageStatesPath); + try { + @unlink($legacyPackageStatesPath); + } catch (\Throwable $e) {} } OpcodeCacheHelper::clearAllActive($this->packageInformationCacheFilePath); diff --git a/Neos.Utility.Files/Classes/Files.php b/Neos.Utility.Files/Classes/Files.php index 19ff177e16..8ee49224df 100644 --- a/Neos.Utility.Files/Classes/Files.php +++ b/Neos.Utility.Files/Classes/Files.php @@ -190,7 +190,9 @@ public static function removeEmptyDirectoriesOnPath(string $path, string $basePa break; } if (file_exists($path . '/.DS_Store')) { - @unlink($path . '/.DS_Store'); + try { + @unlink($path . '/.DS_Store'); + } catch (\Throwable $e) {} } if (@rmdir($path) === false) { break; From d39a5c3cc4874773f72ec1c0ec996273d4048ccb Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Thu, 25 Feb 2021 09:05:44 +0100 Subject: [PATCH 11/32] TASK: Fix code style --- Neos.Cache/Classes/Backend/FileBackend.php | 4 +++- Neos.Flow/Classes/Core/LockManager.php | 8 ++++++-- Neos.Flow/Classes/Package/PackageManager.php | 4 +++- Neos.Utility.Files/Classes/Files.php | 4 +++- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Neos.Cache/Classes/Backend/FileBackend.php b/Neos.Cache/Classes/Backend/FileBackend.php index ff3e220774..f01bb61779 100644 --- a/Neos.Cache/Classes/Backend/FileBackend.php +++ b/Neos.Cache/Classes/Backend/FileBackend.php @@ -283,7 +283,9 @@ public function flush(): void if ($this->frozen === true) { try { @unlink($this->cacheDirectory . 'FrozenCache.data'); - } catch (\Throwable $e) {} + } catch (\Throwable $e) { + // Double-shrug catching + } $this->frozen = false; } } diff --git a/Neos.Flow/Classes/Core/LockManager.php b/Neos.Flow/Classes/Core/LockManager.php index 217c2990bd..b9a0d79992 100644 --- a/Neos.Flow/Classes/Core/LockManager.php +++ b/Neos.Flow/Classes/Core/LockManager.php @@ -82,7 +82,9 @@ protected function removeExpiredLock() try { @unlink($this->lockFlagPathAndFilename); @unlink($this->lockPathAndFilename); - } catch (\Throwable $e) {} + } catch (\Throwable $e) { + // Double-shrug catching + } } /** @@ -140,7 +142,9 @@ public function unlockSite() if ($this->isSiteLocked()) { try { @unlink($this->lockFlagPathAndFilename); - } catch (\Throwable $e) {} + } catch (\Throwable $e) { + // Double-shrug catching + } } } diff --git a/Neos.Flow/Classes/Package/PackageManager.php b/Neos.Flow/Classes/Package/PackageManager.php index 62f51913a1..c88feeb2f4 100644 --- a/Neos.Flow/Classes/Package/PackageManager.php +++ b/Neos.Flow/Classes/Package/PackageManager.php @@ -766,7 +766,9 @@ protected function savePackageStates(array $orderedPackageStates): void if (is_file($legacyPackageStatesPath)) { try { @unlink($legacyPackageStatesPath); - } catch (\Throwable $e) {} + } catch (\Throwable $e) { + // Double-shrug catching + } } OpcodeCacheHelper::clearAllActive($this->packageInformationCacheFilePath); diff --git a/Neos.Utility.Files/Classes/Files.php b/Neos.Utility.Files/Classes/Files.php index 8ee49224df..0a6334df17 100644 --- a/Neos.Utility.Files/Classes/Files.php +++ b/Neos.Utility.Files/Classes/Files.php @@ -192,7 +192,9 @@ public static function removeEmptyDirectoriesOnPath(string $path, string $basePa if (file_exists($path . '/.DS_Store')) { try { @unlink($path . '/.DS_Store'); - } catch (\Throwable $e) {} + } catch (\Throwable $e) { + // Double-shrug catching + } } if (@rmdir($path) === false) { break; From fb76c960274ca906963463bbfb3b2bcc6acde439 Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Thu, 25 Feb 2021 10:58:32 +0100 Subject: [PATCH 12/32] TASK: Fix trigger_error levels in tests --- Neos.Cache/Tests/Unit/Backend/FileBackendTest.php | 2 +- Neos.Cache/Tests/Unit/Backend/SimpleFileBackendTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Neos.Cache/Tests/Unit/Backend/FileBackendTest.php b/Neos.Cache/Tests/Unit/Backend/FileBackendTest.php index 64b531ebaf..0e7aa883ff 100644 --- a/Neos.Cache/Tests/Unit/Backend/FileBackendTest.php +++ b/Neos.Cache/Tests/Unit/Backend/FileBackendTest.php @@ -572,7 +572,7 @@ public function requireOnceDoesNotSwallowPhpWarningsOfTheIncludedFile() $backend->setCache($mockCache); $entryIdentifier = 'SomePhpEntryWithPhpWarning'; - $backend->set($entryIdentifier, ''); + $backend->set($entryIdentifier, ''); $backend->requireOnce($entryIdentifier); } diff --git a/Neos.Cache/Tests/Unit/Backend/SimpleFileBackendTest.php b/Neos.Cache/Tests/Unit/Backend/SimpleFileBackendTest.php index 840a1fc81a..071f42e3fd 100644 --- a/Neos.Cache/Tests/Unit/Backend/SimpleFileBackendTest.php +++ b/Neos.Cache/Tests/Unit/Backend/SimpleFileBackendTest.php @@ -405,7 +405,7 @@ public function requireOnceDoesNotSwallowPhpWarningsOfTheIncludedFile() $entryIdentifier = 'SomePhpEntryWithPhpWarning'; $simpleFileBackend = $this->getSimpleFileBackend(); - $simpleFileBackend->set($entryIdentifier, ''); + $simpleFileBackend->set($entryIdentifier, ''); $simpleFileBackend->requireOnce($entryIdentifier); } From dc19a84dc4f12d9dae29dffa2c6527ae5c4db53a Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Thu, 25 Feb 2021 11:02:25 +0100 Subject: [PATCH 13/32] TASK: Fix expectation for PHP 8 --- Neos.Cache/Tests/Unit/Backend/SimpleFileBackendTest.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Neos.Cache/Tests/Unit/Backend/SimpleFileBackendTest.php b/Neos.Cache/Tests/Unit/Backend/SimpleFileBackendTest.php index 071f42e3fd..605f829f8a 100644 --- a/Neos.Cache/Tests/Unit/Backend/SimpleFileBackendTest.php +++ b/Neos.Cache/Tests/Unit/Backend/SimpleFileBackendTest.php @@ -414,7 +414,11 @@ public function requireOnceDoesNotSwallowPhpWarningsOfTheIncludedFile() */ public function requireOnceDoesNotSwallowPhpNoticesOfTheIncludedFile() { - $this->expectNotice(); + if (PHP_MAJOR_VERSION >= 8) { + $this->expectWarning(); + } else { + $this->expectNotice(); + } $entryIdentifier = 'SomePhpEntryWithPhpNotice'; $simpleFileBackend = $this->getSimpleFileBackend(); From b050c365464b80f587711900d8c2b35a1b2f5668 Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Thu, 25 Feb 2021 17:03:07 +0100 Subject: [PATCH 14/32] BUGFIX: Fix Math.sign EEL Helper for PHP 8 --- Neos.Eel/Classes/Helper/MathHelper.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Neos.Eel/Classes/Helper/MathHelper.php b/Neos.Eel/Classes/Helper/MathHelper.php index 2f349f14bf..af266a4541 100644 --- a/Neos.Eel/Classes/Helper/MathHelper.php +++ b/Neos.Eel/Classes/Helper/MathHelper.php @@ -422,14 +422,14 @@ public function round($subject, $precision = 0) */ public function sign($x) { - if ($x < 0) { + if (!is_numeric($x)) { + return NAN; + } elseif ($x < 0) { return -1; } elseif ($x > 0) { return 1; - } elseif ($x === 0 || $x === 0.0) { - return 0; } else { - return NAN; + return 0; } } From 754379fc90efae39e2ddef39245cc9ddd32bcc85 Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Thu, 25 Feb 2021 17:06:51 +0100 Subject: [PATCH 15/32] BUGFIX: Correctly check for notice errors in required backed --- Neos.Cache/Tests/Unit/Backend/FileBackendTest.php | 2 +- Neos.Cache/Tests/Unit/Backend/SimpleFileBackendTest.php | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Neos.Cache/Tests/Unit/Backend/FileBackendTest.php b/Neos.Cache/Tests/Unit/Backend/FileBackendTest.php index 0e7aa883ff..79fc3df010 100644 --- a/Neos.Cache/Tests/Unit/Backend/FileBackendTest.php +++ b/Neos.Cache/Tests/Unit/Backend/FileBackendTest.php @@ -589,7 +589,7 @@ public function requireOnceDoesNotSwallowPhpNoticesOfTheIncludedFile() $backend->setCache($mockCache); $entryIdentifier = 'SomePhpEntryWithPhpNotice'; - $backend->set($entryIdentifier, ''); + $backend->set($entryIdentifier, ''); $backend->requireOnce($entryIdentifier); } diff --git a/Neos.Cache/Tests/Unit/Backend/SimpleFileBackendTest.php b/Neos.Cache/Tests/Unit/Backend/SimpleFileBackendTest.php index 605f829f8a..e42231f533 100644 --- a/Neos.Cache/Tests/Unit/Backend/SimpleFileBackendTest.php +++ b/Neos.Cache/Tests/Unit/Backend/SimpleFileBackendTest.php @@ -414,15 +414,11 @@ public function requireOnceDoesNotSwallowPhpWarningsOfTheIncludedFile() */ public function requireOnceDoesNotSwallowPhpNoticesOfTheIncludedFile() { - if (PHP_MAJOR_VERSION >= 8) { - $this->expectWarning(); - } else { - $this->expectNotice(); - } + $this->expectNotice(); $entryIdentifier = 'SomePhpEntryWithPhpNotice'; $simpleFileBackend = $this->getSimpleFileBackend(); - $simpleFileBackend->set($entryIdentifier, ''); + $simpleFileBackend->set($entryIdentifier, ''); $simpleFileBackend->requireOnce($entryIdentifier); } From 1aaa37bbd09dedba4c24e3f588320911241658c5 Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Thu, 25 Feb 2021 17:13:53 +0100 Subject: [PATCH 16/32] BUGFIX: Cast math function arguments to float --- Neos.Eel/Classes/Helper/MathHelper.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Neos.Eel/Classes/Helper/MathHelper.php b/Neos.Eel/Classes/Helper/MathHelper.php index af266a4541..19309d3b63 100644 --- a/Neos.Eel/Classes/Helper/MathHelper.php +++ b/Neos.Eel/Classes/Helper/MathHelper.php @@ -407,7 +407,7 @@ public function round($subject, $precision = 0) if (!is_numeric($subject)) { return NAN; } - $subject = floatval($subject); + $subject = (float)$subject; if ($precision != null && !is_int($precision)) { return NAN; } @@ -492,9 +492,9 @@ public function trunc($x) $sign = $this->sign($x); switch ($sign) { case -1: - return (int)ceil($x); + return (int)ceil((float)$x); case 1: - return (int)floor($x); + return (int)floor((float)$x); default: return $sign; } From d70ba6352232557772151ec3d7660c6e5a1f1d1f Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Thu, 25 Feb 2021 17:28:04 +0100 Subject: [PATCH 17/32] BUGFIX: Handle PHP8 TypeError in get_class_methods --- .../ObjectManagement/Configuration/ConfigurationBuilder.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Neos.Flow/Classes/ObjectManagement/Configuration/ConfigurationBuilder.php b/Neos.Flow/Classes/ObjectManagement/Configuration/ConfigurationBuilder.php index 16217de34d..66c48b1750 100644 --- a/Neos.Flow/Classes/ObjectManagement/Configuration/ConfigurationBuilder.php +++ b/Neos.Flow/Classes/ObjectManagement/Configuration/ConfigurationBuilder.php @@ -507,7 +507,11 @@ protected function autowireProperties(array &$objectConfigurations) continue; } - $classMethodNames = get_class_methods($className); + try { + $classMethodNames = get_class_methods($className); + } catch (\TypeError $error) { + throw new UnknownClassException(sprintf('The class "%s" defined in the object configuration for object "%s", defined in package: %s, does not exist.', $className, $objectConfiguration->getObjectName(), $objectConfiguration->getPackageKey()), 1352371371); + } if (!is_array($classMethodNames)) { if (!class_exists($className)) { throw new UnknownClassException(sprintf('The class "%s" defined in the object configuration for object "%s", defined in package: %s, does not exist.', $className, $objectConfiguration->getObjectName(), $objectConfiguration->getPackageKey()), 1352371371); From 310b5c0a02bc9f384cfd154b1f6d52db1991b06d Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Thu, 25 Feb 2021 17:45:52 +0100 Subject: [PATCH 18/32] TASK: Revert array_values duplicate change --- Neos.Flow/Classes/SignalSlot/Dispatcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Neos.Flow/Classes/SignalSlot/Dispatcher.php b/Neos.Flow/Classes/SignalSlot/Dispatcher.php index 4ff4f5c05e..b802e14517 100644 --- a/Neos.Flow/Classes/SignalSlot/Dispatcher.php +++ b/Neos.Flow/Classes/SignalSlot/Dispatcher.php @@ -183,7 +183,7 @@ public function dispatch(string $signalClassName, string $signalName, array $sig $finalSignalArguments[] = $signalClassName . '::' . $signalName; } // Need to use call_user_func_array here, because $object may be the class name when the slot is a static method - call_user_func_array([$object, $slotInformation['method']], array_values($finalSignalArguments)); + call_user_func_array([$object, $slotInformation['method']], $finalSignalArguments); } } } From 094d3257f1823f729849e6f8c8606aaabe3094b2 Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Thu, 25 Feb 2021 17:50:24 +0100 Subject: [PATCH 19/32] TASK: Fix return typehint for getBuiltinType --- Neos.Flow/Classes/Reflection/ParameterReflection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Neos.Flow/Classes/Reflection/ParameterReflection.php b/Neos.Flow/Classes/Reflection/ParameterReflection.php index 86db6a3b35..7fb273652e 100644 --- a/Neos.Flow/Classes/Reflection/ParameterReflection.php +++ b/Neos.Flow/Classes/Reflection/ParameterReflection.php @@ -52,7 +52,7 @@ public function getClass() } /** - * @return string The name of a builtin type (e.g. string, int) if it was declared for the parameter (scalar type declaration), null otherwise + * @return string|null The name of a builtin type (e.g. string, int) if it was declared for the parameter (scalar type declaration), null otherwise */ public function getBuiltinType() { From 9bc27006b28a3903a07670cd93a3cbe3dc1c89a1 Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Thu, 25 Feb 2021 17:50:36 +0100 Subject: [PATCH 20/32] TASK: Update psalm baseline --- psalm-baseline.xml | 111 +++------------------------------------------ 1 file changed, 7 insertions(+), 104 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index f81cb6c32c..c75aa1a523 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -21,72 +21,11 @@ \APCUIterator - - - \Memcached - \Memcached - - - $this->memcache - $this->memcache - $this->memcache - $this->memcache - $this->memcache - $this->memcache - $this->memcache - $this->memcache - $this->memcache - $this->memcache - $this->memcache - \Memcache|\Memcached - - null - - - \Redis - \Redis - \Redis - - - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - $this->redis - \Redis - - string|bool @@ -1212,15 +1151,6 @@ $dotPosition - - - string - - - null - null - - LOG_DEBUG @@ -1443,10 +1373,6 @@ - - ObjectPathMapping - ObjectPathMapping - flush logicalAnd @@ -1816,12 +1742,6 @@ $primaryTable['name'] - - - $this->entityManager->find($objectType, $identifier) - $this->entityManager->getReference($objectType, $identifier) - - Comparison|string @@ -1847,11 +1767,6 @@ Constraint - - - (isset($rows[0])) ? $rows[0] : null - - $classMetadata @@ -1859,12 +1774,6 @@ QueryResultInterface - - object - - - $this->entityManager->find($this->objectType, $identifier) - $query->equals($propertyName, $arguments[0], $caseSensitive) $query->equals($propertyName, $arguments[0], $caseSensitive) @@ -1961,6 +1870,10 @@ $source + + $entityLoaderValue + $entityLoaderValue + @@ -1975,9 +1888,6 @@ - - object - self::CONFIGURATION_CREATION_ALLOWED self::CONFIGURATION_CREATION_ALLOWED @@ -1985,8 +1895,7 @@ self::CONFIGURATION_MODIFICATION_ALLOWED self::CONFIGURATION_TARGET_TYPE - - null + null @@ -2070,14 +1979,12 @@ - + ClassReflection - string - + is_object($class) ? new ClassReflection($class->getName()) : null null - null getName @@ -2318,10 +2225,6 @@ $object - - Account - Account - logicalAnd logicalAnd From e85f76b95de3a4dea42aa1829874969efe7f69f3 Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Thu, 25 Feb 2021 17:56:49 +0100 Subject: [PATCH 21/32] TASK: Adjust doctrine dependency version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 2d16648be8..30988591ac 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "psr/http-server-middleware": "^1.0", "psr/http-server-handler": "^1.0", "ramsey/uuid": "^3.0 || ^4.0", - "doctrine/orm": "^2.7 || 2.8.x-dev", + "doctrine/orm": "^2.7", "doctrine/migrations": "^3.0", "doctrine/dbal": "^2.12", "doctrine/common": "^2.13.1 || ^3.0", From be4725e588e2487f062e986370c0c4de47be59f9 Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Thu, 25 Feb 2021 20:03:07 +0100 Subject: [PATCH 22/32] BUGFIX: Fix method return types in proxies --- Neos.Flow/Classes/Reflection/ReflectionService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Neos.Flow/Classes/Reflection/ReflectionService.php b/Neos.Flow/Classes/Reflection/ReflectionService.php index 66d539d753..7d451d00c8 100644 --- a/Neos.Flow/Classes/Reflection/ReflectionService.php +++ b/Neos.Flow/Classes/Reflection/ReflectionService.php @@ -1380,7 +1380,7 @@ protected function reflectClassMethod($className, MethodReflection $method) $this->classesByMethodAnnotations[$annotationClassName][$className][] = $methodName; } - $returnType = $method->getDeclaredReturnType(); + $returnType = ltrim($method->getDeclaredReturnType(), '?\\'); if ($returnType !== null && !in_array($returnType, ['self', 'null', 'callable', 'void']) && !TypeHandling::isSimpleType($returnType)) { $returnType = '\\' . $returnType; } From 9c843811bc07aafaa4e660769e2d687b7b937725 Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Thu, 25 Feb 2021 20:39:06 +0100 Subject: [PATCH 23/32] BUGFIX: Fix method return types in PHP8 --- Neos.Flow/Classes/Reflection/MethodReflection.php | 2 +- Neos.Flow/Classes/Reflection/ReflectionService.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Neos.Flow/Classes/Reflection/MethodReflection.php b/Neos.Flow/Classes/Reflection/MethodReflection.php index 01d5942377..c6577dbef1 100644 --- a/Neos.Flow/Classes/Reflection/MethodReflection.php +++ b/Neos.Flow/Classes/Reflection/MethodReflection.php @@ -103,7 +103,7 @@ public function getDeclaredReturnType() return null; } $type = $this->getReturnType(); - return $type !== null ? (string)$type : null; + return $type !== null ? ltrim((string)$type, '?') : null; } /** diff --git a/Neos.Flow/Classes/Reflection/ReflectionService.php b/Neos.Flow/Classes/Reflection/ReflectionService.php index 7d451d00c8..66d539d753 100644 --- a/Neos.Flow/Classes/Reflection/ReflectionService.php +++ b/Neos.Flow/Classes/Reflection/ReflectionService.php @@ -1380,7 +1380,7 @@ protected function reflectClassMethod($className, MethodReflection $method) $this->classesByMethodAnnotations[$annotationClassName][$className][] = $methodName; } - $returnType = ltrim($method->getDeclaredReturnType(), '?\\'); + $returnType = $method->getDeclaredReturnType(); if ($returnType !== null && !in_array($returnType, ['self', 'null', 'callable', 'void']) && !TypeHandling::isSimpleType($returnType)) { $returnType = '\\' . $returnType; } From 3ac08f0aa4371b45df63bb86f790f8e2670402cf Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Thu, 25 Feb 2021 21:19:13 +0100 Subject: [PATCH 24/32] TASK: Adapt required argument test for PHP8 --- .../Functional/Mvc/ActionControllerTest.php | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Neos.Flow/Tests/Functional/Mvc/ActionControllerTest.php b/Neos.Flow/Tests/Functional/Mvc/ActionControllerTest.php index b87affa7a0..3142b1c28f 100644 --- a/Neos.Flow/Tests/Functional/Mvc/ActionControllerTest.php +++ b/Neos.Flow/Tests/Functional/Mvc/ActionControllerTest.php @@ -429,7 +429,6 @@ public function argumentTestsDataProvider() 'required date string' => ['requiredDate', '1980-12-13T14:22:12+02:00', '1980-12-13'], 'required date - missing value' => ['requiredDate', null, $requiredArgumentExceptionText], 'required date - mapping error' => ['requiredDate', 'no date', 'Validation failed while trying to call Neos\Flow\Tests\Functional\Mvc\Fixtures\Controller\ActionControllerTestBController->requiredDateAction().'], - 'required date - empty value' => ['requiredDate', '', 'Uncaught Exception in Flow Argument 1 passed to Neos\Flow\Tests\Functional\Mvc\Fixtures\Controller\ActionControllerTestBController_Original::requiredDateAction() must be an instance of DateTime, null given'], 'optional date string' => ['optionalDate', '1980-12-13T14:22:12+02:00', '1980-12-13'], 'optional date - default value' => ['optionalDate', null, 'null'], 'optional date - mapping error' => ['optionalDate', 'no date', 'Validation failed while trying to call Neos\Flow\Tests\Functional\Mvc\Fixtures\Controller\ActionControllerTestBController->optionalDateAction().'], @@ -460,6 +459,25 @@ public function argumentTests($action, $argument, $expectedResult) self::assertTrue(strpos(trim($response->getBody()->getContents()), (string)$expectedResult) === 0, sprintf('The resulting string did not start with the expected string. Expected: "%s", Actual: "%s"', $expectedResult, $response->getBody()->getContents())); } + /** + * @test + */ + public function requiredDateNullArgumentTest() + { + $arguments = [ + 'argument' => '', + ]; + + $uri = str_replace('{@action}', 'requireddate', 'http://localhost/test/mvc/actioncontrollertestb/{@action}'); + $response = $this->browser->request($uri, 'POST', $arguments); + if (PHP_MAJOR_VERSION < 8) { + $expectedResult = 'Uncaught Exception in Flow Argument 1 passed to Neos\Flow\Tests\Functional\Mvc\Fixtures\Controller\ActionControllerTestBController_Original::requiredDateAction() must be an instance of DateTime, null given'; + } else { + $expectedResult = 'Uncaught Exception in Flow Neos\Flow\Tests\Functional\Mvc\Fixtures\Controller\ActionControllerTestBController_Original::requiredDateAction(): Argument #1 ($argument) must be of type DateTime, null given'; + } + self::assertTrue(strpos(trim($response->getBody()->getContents()), (string)$expectedResult) === 0, sprintf('The resulting string did not start with the expected string. Expected: "%s", Actual: "%s"', $expectedResult, $response->getBody()->getContents())); + } + /** * @test */ From d31db0288bd851f94eff7f913d272f1211cc5a3c Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Thu, 25 Feb 2021 21:25:49 +0100 Subject: [PATCH 25/32] TASK: Add null to method return type --- Neos.Flow/Classes/Reflection/MethodReflection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Neos.Flow/Classes/Reflection/MethodReflection.php b/Neos.Flow/Classes/Reflection/MethodReflection.php index c6577dbef1..b7d907f73e 100644 --- a/Neos.Flow/Classes/Reflection/MethodReflection.php +++ b/Neos.Flow/Classes/Reflection/MethodReflection.php @@ -95,7 +95,7 @@ public function getDescription() } /** - * @return string The name of a type (e.g. string, \stdClass) if it was declared as a return type, null otherwise + * @return string|null The name of a type (e.g. string, \stdClass) if it was declared as a return type, null otherwise */ public function getDeclaredReturnType() { From b985f3721b7b71ff43c420a86bb15ff812b38a8a Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Fri, 26 Feb 2021 14:24:17 +0100 Subject: [PATCH 26/32] TASK: Add PHP 8.0 to test matrix instead of experimental step --- .github/workflows/build.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 84e1df6abb..570e595553 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['7.3', '7.4'] + php-versions: ['7.3', '7.4', '8.0'] dependencies: ['highest'] composer-arguments: [''] # to run --ignore-platform-reqs in experimental builds static-analysis: ['no'] @@ -27,12 +27,12 @@ jobs: experimental: false dependencies: 'highest' - # Experimental build for PHP 8 - - php-versions: '8.0' - #composer-arguments: '--ignore-platform-reqs' - static-analysis: 'no' - experimental: true - dependencies: 'highest' + # Experimental build for PHP nightly + #- php-versions: 'nightly' + # composer-arguments: '--ignore-platform-reqs' + # static-analysis: 'no' + # experimental: true + # dependencies: 'highest' # Build for minimum dependencies. Fails right now, hence deactivated. #- php-versions: '7.3' From b2c60da475670c36a4b22f5a42b205f8bd2db758 Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Mon, 15 Mar 2021 11:48:09 +0100 Subject: [PATCH 27/32] TASK: Improve double-shrug catching comment --- Neos.Cache/Classes/Backend/FileBackend.php | 2 +- Neos.Flow/Classes/Core/LockManager.php | 4 ++-- Neos.Flow/Classes/Package/PackageManager.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Neos.Cache/Classes/Backend/FileBackend.php b/Neos.Cache/Classes/Backend/FileBackend.php index f01bb61779..b07a17b196 100644 --- a/Neos.Cache/Classes/Backend/FileBackend.php +++ b/Neos.Cache/Classes/Backend/FileBackend.php @@ -284,7 +284,7 @@ public function flush(): void try { @unlink($this->cacheDirectory . 'FrozenCache.data'); } catch (\Throwable $e) { - // Double-shrug catching + // PHP 8 apparently throws for unlink even with shutup operator, but we really don't care at this place. It's also the only way to handle this race-condition free. } $this->frozen = false; } diff --git a/Neos.Flow/Classes/Core/LockManager.php b/Neos.Flow/Classes/Core/LockManager.php index b9a0d79992..788a730378 100644 --- a/Neos.Flow/Classes/Core/LockManager.php +++ b/Neos.Flow/Classes/Core/LockManager.php @@ -83,7 +83,7 @@ protected function removeExpiredLock() @unlink($this->lockFlagPathAndFilename); @unlink($this->lockPathAndFilename); } catch (\Throwable $e) { - // Double-shrug catching + // PHP 8 apparently throws for unlink even with shutup operator, but we really don't care at this place. It's also the only way to handle this race-condition free. } } @@ -143,7 +143,7 @@ public function unlockSite() try { @unlink($this->lockFlagPathAndFilename); } catch (\Throwable $e) { - // Double-shrug catching + // PHP 8 apparently throws for unlink even with shutup operator, but we really don't care at this place. It's also the only way to handle this race-condition free. } } } diff --git a/Neos.Flow/Classes/Package/PackageManager.php b/Neos.Flow/Classes/Package/PackageManager.php index c88feeb2f4..50333d6008 100644 --- a/Neos.Flow/Classes/Package/PackageManager.php +++ b/Neos.Flow/Classes/Package/PackageManager.php @@ -767,7 +767,7 @@ protected function savePackageStates(array $orderedPackageStates): void try { @unlink($legacyPackageStatesPath); } catch (\Throwable $e) { - // Double-shrug catching + // PHP 8 apparently throws for unlink even with shutup operator, but we really don't care at this place. It's also the only way to handle this race-condition free. } } OpcodeCacheHelper::clearAllActive($this->packageInformationCacheFilePath); From a417883d6db6acf40efc09dd3778d23d7105461d Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Mon, 15 Mar 2021 11:50:54 +0100 Subject: [PATCH 28/32] TASK: Try/catch every single unlink instead of multiple --- Neos.Flow/Classes/Core/LockManager.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Neos.Flow/Classes/Core/LockManager.php b/Neos.Flow/Classes/Core/LockManager.php index 788a730378..4dfa1a82b7 100644 --- a/Neos.Flow/Classes/Core/LockManager.php +++ b/Neos.Flow/Classes/Core/LockManager.php @@ -81,10 +81,13 @@ protected function removeExpiredLock() } try { @unlink($this->lockFlagPathAndFilename); - @unlink($this->lockPathAndFilename); } catch (\Throwable $e) { // PHP 8 apparently throws for unlink even with shutup operator, but we really don't care at this place. It's also the only way to handle this race-condition free. } + try { + @unlink($this->lockPathAndFilename); + } catch (\Throwable $e) { + } } /** From b61942bc4b7f8116d1041e8d5fb1d79a4826a365 Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Mon, 15 Mar 2021 19:32:27 +0100 Subject: [PATCH 29/32] TASK: Replace missing double-shrug catching comment --- Neos.Utility.Files/Classes/Files.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Neos.Utility.Files/Classes/Files.php b/Neos.Utility.Files/Classes/Files.php index 0a6334df17..fac66763eb 100644 --- a/Neos.Utility.Files/Classes/Files.php +++ b/Neos.Utility.Files/Classes/Files.php @@ -193,7 +193,7 @@ public static function removeEmptyDirectoriesOnPath(string $path, string $basePa try { @unlink($path . '/.DS_Store'); } catch (\Throwable $e) { - // Double-shrug catching + // PHP 8 apparently throws for unlink even with shutup operator, but we really don't care at this place. It's also the only way to handle this race-condition free. } } if (@rmdir($path) === false) { From 23f4bc33802b55dd84461eff4b36afe414ed1e87 Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Mon, 22 Mar 2021 09:22:10 +0100 Subject: [PATCH 30/32] TASK: Apply suggestions from code review --- .../Configuration/ConfigurationBuilder.php | 2 +- Neos.Flow/Classes/Reflection/ReflectionService.php | 1 + Neos.Flow/Tests/Unit/SignalSlot/DispatcherTest.php | 14 +++++++------- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Neos.Flow/Classes/ObjectManagement/Configuration/ConfigurationBuilder.php b/Neos.Flow/Classes/ObjectManagement/Configuration/ConfigurationBuilder.php index 66c48b1750..bd934530e1 100644 --- a/Neos.Flow/Classes/ObjectManagement/Configuration/ConfigurationBuilder.php +++ b/Neos.Flow/Classes/ObjectManagement/Configuration/ConfigurationBuilder.php @@ -510,7 +510,7 @@ protected function autowireProperties(array &$objectConfigurations) try { $classMethodNames = get_class_methods($className); } catch (\TypeError $error) { - throw new UnknownClassException(sprintf('The class "%s" defined in the object configuration for object "%s", defined in package: %s, does not exist.', $className, $objectConfiguration->getObjectName(), $objectConfiguration->getPackageKey()), 1352371371); + throw new UnknownClassException(sprintf('The class "%s" defined in the object configuration for object "%s", defined in package: %s, does not exist.', $className, $objectConfiguration->getObjectName(), $objectConfiguration->getPackageKey()), 1352371372); } if (!is_array($classMethodNames)) { if (!class_exists($className)) { diff --git a/Neos.Flow/Classes/Reflection/ReflectionService.php b/Neos.Flow/Classes/Reflection/ReflectionService.php index 66d539d753..597c6877e0 100644 --- a/Neos.Flow/Classes/Reflection/ReflectionService.php +++ b/Neos.Flow/Classes/Reflection/ReflectionService.php @@ -1805,6 +1805,7 @@ protected function convertParameterReflectionToArray(ParameterReflection $parame $parameterInformation[self::DATA_PARAMETER_CLASS] = $parameterType; } elseif ($parameterType === 'array') { $parameterInformation[self::DATA_PARAMETER_ARRAY] = true; + $parameterInformation[self::DATA_PARAMETER_TYPE] = $parameterType; } else { $builtinType = $parameter->getBuiltinType(); if ($builtinType !== null) { diff --git a/Neos.Flow/Tests/Unit/SignalSlot/DispatcherTest.php b/Neos.Flow/Tests/Unit/SignalSlot/DispatcherTest.php index 6fa074ce2c..c7228a9103 100644 --- a/Neos.Flow/Tests/Unit/SignalSlot/DispatcherTest.php +++ b/Neos.Flow/Tests/Unit/SignalSlot/DispatcherTest.php @@ -144,7 +144,7 @@ public function dispatchPassesTheSignalArgumentsToTheSlotMethod(): void $dispatcher->connect('Foo', 'bar', $mockSlot, '', false); $dispatcher->injectObjectManager($mockObjectManager); - $dispatcher->dispatch('Foo', 'bar', ['bar', 'quux']); + $dispatcher->dispatch('Foo', 'bar', ['foo' => 'bar', 'baz' => 'quux']); self::assertSame(['bar', 'quux'], $arguments); } @@ -160,7 +160,7 @@ public function dispatchPassesTheSignalArgumentsToTheStaticSlotMethod(): void $dispatcher->connect('Foo', 'bar', get_class($this), '::staticSlot', false); $dispatcher->injectObjectManager($mockObjectManager); - $dispatcher->dispatch('Foo', 'bar', ['bar', 'quux']); + $dispatcher->dispatch('Foo', 'bar', ['foo' => 'bar', 'baz' => 'quux']); self::assertSame(['bar', 'quux'], self::$arguments); } @@ -172,8 +172,8 @@ public function dispatchPassesTheSignalArgumentsToTheStaticSlotMethodIfNoObjectm $dispatcher = new Dispatcher(); $dispatcher->connect('Foo', 'bar', get_class($this), '::staticSlot', false); - $dispatcher->dispatch('Foo', 'bar', ['no', 'object', 'manager', 'exists']); - self::assertSame(['no', 'object', 'manager', 'exists'], self::$arguments); + $dispatcher->dispatch('Foo', 'bar', ['no' => 'object', 'manager' => 'exists']); + self::assertSame(['object', 'exists'], self::$arguments); } /** @@ -210,7 +210,7 @@ public function dispatchRetrievesSlotInstanceFromTheObjectManagerIfOnlyAClassNam $dispatcher->injectObjectManager($mockObjectManager); $dispatcher->connect('Foo', 'bar', $slotClassName, 'slot', false); - $dispatcher->dispatch('Foo', 'bar', ['bar', 'quux']); + $dispatcher->dispatch('Foo', 'bar', ['foo' => 'bar', 'baz' => 'quux']); self::assertSame($mockSlot->arguments, ['bar', 'quux']); } @@ -247,7 +247,7 @@ public function dispatchThrowsAnExceptionIfTheSpecifiedSlotMethodDoesNotExist(): $dispatcher->injectObjectManager($mockObjectManager); $dispatcher->connect('Foo', 'bar', $slotClassName, 'unknownMethodName', true); - $dispatcher->dispatch('Foo', 'bar', ['bar', 'quux']); + $dispatcher->dispatch('Foo', 'bar', ['foo' => 'bar', 'baz' => 'quux']); } /** @@ -266,7 +266,7 @@ public function dispatchPassesArgumentContainingSlotInformationLastIfTheConnecti $dispatcher->connect('SignalClassName', 'methodName', $mockSlot, '', true); $dispatcher->injectObjectManager($mockObjectManager); - $dispatcher->dispatch('SignalClassName', 'methodName', ['bar', 'quux']); + $dispatcher->dispatch('SignalClassName', 'methodName', ['foo' => 'bar', 'baz' => 'quux']); self::assertSame(['bar', 'quux', 'SignalClassName::methodName'], $arguments); } From 82d5c851d9ddc9cf6b7991844de420231b41ca34 Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Mon, 22 Mar 2021 09:24:36 +0100 Subject: [PATCH 31/32] TASK: Add test for unnamed dispatch signal arguments --- .../Tests/Unit/SignalSlot/DispatcherTest.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Neos.Flow/Tests/Unit/SignalSlot/DispatcherTest.php b/Neos.Flow/Tests/Unit/SignalSlot/DispatcherTest.php index c7228a9103..040132cf29 100644 --- a/Neos.Flow/Tests/Unit/SignalSlot/DispatcherTest.php +++ b/Neos.Flow/Tests/Unit/SignalSlot/DispatcherTest.php @@ -148,6 +148,26 @@ public function dispatchPassesTheSignalArgumentsToTheSlotMethod(): void self::assertSame(['bar', 'quux'], $arguments); } + /** + * @test + */ + public function dispatchPassesUnnamedSignalArgumentsToTheSlotMethod(): void + { + $arguments = []; + $mockSlot = function () use (&$arguments) { + $arguments = func_get_args(); + }; + + $mockObjectManager = $this->createMock(ObjectManagerInterface::class); + + $dispatcher = new Dispatcher(); + $dispatcher->connect('Foo', 'bar', $mockSlot, '', false); + $dispatcher->injectObjectManager($mockObjectManager); + + $dispatcher->dispatch('Foo', 'bar', ['bar', 'quux']); + self::assertSame(['bar', 'quux'], $arguments); + } + /** * @test */ From c5268c81eb8939758030958a2012d305c7088f9e Mon Sep 17 00:00:00 2001 From: Alexander Berl Date: Mon, 22 Mar 2021 12:09:22 +0100 Subject: [PATCH 32/32] BUGFIX: Use typehint annotations for arrays --- Neos.Flow/Classes/Reflection/ReflectionService.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Neos.Flow/Classes/Reflection/ReflectionService.php b/Neos.Flow/Classes/Reflection/ReflectionService.php index 597c6877e0..66d539d753 100644 --- a/Neos.Flow/Classes/Reflection/ReflectionService.php +++ b/Neos.Flow/Classes/Reflection/ReflectionService.php @@ -1805,7 +1805,6 @@ protected function convertParameterReflectionToArray(ParameterReflection $parame $parameterInformation[self::DATA_PARAMETER_CLASS] = $parameterType; } elseif ($parameterType === 'array') { $parameterInformation[self::DATA_PARAMETER_ARRAY] = true; - $parameterInformation[self::DATA_PARAMETER_TYPE] = $parameterType; } else { $builtinType = $parameter->getBuiltinType(); if ($builtinType !== null) {