From 10b5103ab04d1da1ff712ca68a08a6b8ee7e0152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Mu=CC=88ller?= Date: Thu, 6 Feb 2025 17:00:15 +0100 Subject: [PATCH] !!!TASK: Reduce complexity of ReflectionService This change tackles some problems within the reflection service that stem from historically increasing complexity due to various caching mechanisms depending on application context and compile time status. The aim was to cut down on this complexity, while ensuring that all existing use-cases continue working as intended. This ultimately also fixes issue #3402 by providing the same reflection data across all possible contexts. A few features and caches got deprecated with this change and could be breaking in the rare case you used the freeze package api in your code: The entire concept of freezing a package is deprecated What remains are the commands in the package controller, which are now all no-ops and deprecated to be removed with 9.0. This is to ensure deployment pipelines possibly calling freeze commands do not break with the 8.4 update. Additionally the single method `PackageManager::isPackageFrozen` remains, while the rest was removed. None of the methods was ever api and it seems unlikely that someone used them in user-land code. `isPackageFrozen` however is at the very least used in Framework and Neos code and therefore remains until 9.0, but will now return false for every package. Caches deprecated and unused With the simplification two caches are no longer needed, both are still declared so that possibly existing cache configuration in user projects doesn't error, but both `Flow_Reflection_Status` and `Flow_Reflection_CompiletimeData` will no longer be used and any content can be removed. The only reflection cache is now `Flow_Reflection_RuntimeData`, which makes the name somewhat deceptive as it is also used in compile time. To avoid backwards compatibility issues however it makes sense to keep the name for the foreseeable future. Quick performance comparisons suggest that especially the initial compile from empty cache benefits from this change. Reflection updates in Development context afterwards seem to be on par with the existing code base. --- .../Classes/Aop/Builder/ProxyClassBuilder.php | 4 +- Neos.Flow/Classes/Cache/CacheManager.php | 5 +- .../Command/CacheCommandController.php | 20 - .../Command/PackageCommandController.php | 164 +------ Neos.Flow/Classes/Core/Booting/Scripts.php | 6 +- Neos.Flow/Classes/Package.php | 6 +- Neos.Flow/Classes/Package/PackageManager.php | 85 +--- .../Classes/Reflection/ReflectionService.php | 419 +++--------------- .../Reflection/ReflectionServiceFactory.php | 4 - Neos.Flow/Configuration/Caches.yaml | 13 +- .../Reflection/ReflectionServiceTest.php | 1 + .../Tests/Unit/Cache/CacheManagerTest.php | 4 +- .../Tests/Unit/Package/PackageManagerTest.php | 32 -- Neos.FluidAdaptor/Classes/Package.php | 4 - 14 files changed, 103 insertions(+), 664 deletions(-) diff --git a/Neos.Flow/Classes/Aop/Builder/ProxyClassBuilder.php b/Neos.Flow/Classes/Aop/Builder/ProxyClassBuilder.php index b1052792f7..a175e0cf8d 100644 --- a/Neos.Flow/Classes/Aop/Builder/ProxyClassBuilder.php +++ b/Neos.Flow/Classes/Aop/Builder/ProxyClassBuilder.php @@ -441,10 +441,8 @@ public function buildProxyClass(string $targetClassName, array $aspectContainers * @param ClassNameIndex $targetClassNameCandidates target class names for advices * @param ClassNameIndex $treatedSubClasses Already treated (sub) classes to avoid duplication * @return ClassNameIndex The new collection of already treated classes - * @throws ClassLoadingForReflectionFailedException - * @throws \ReflectionException - * @throws InvalidClassException * @throws CannotBuildObjectException + * @throws \ReflectionException */ protected function proxySubClassesOfClassToEnsureAdvices(string $className, ClassNameIndex $targetClassNameCandidates, ClassNameIndex $treatedSubClasses): ClassNameIndex { diff --git a/Neos.Flow/Classes/Cache/CacheManager.php b/Neos.Flow/Classes/Cache/CacheManager.php index ede879875d..a1108b1353 100644 --- a/Neos.Flow/Classes/Cache/CacheManager.php +++ b/Neos.Flow/Classes/Cache/CacheManager.php @@ -374,9 +374,10 @@ protected function flushClassCachesByChangedFiles(array $changedFiles): void $flushDoctrineProxyCache = false; $flushPolicyCache = false; if (count($modifiedClassNamesWithUnderscores) > 0) { - $reflectionStatusCache = $this->getCache('Flow_Reflection_Status'); + $reflectionDataRuntimeCache = $this->getCache('Flow_Reflection_RuntimeData'); foreach (array_keys($modifiedClassNamesWithUnderscores) as $classNameWithUnderscores) { - $reflectionStatusCache->remove($classNameWithUnderscores); + $this->logger->debug('File change detected, removing reflection for ' . $classNameWithUnderscores); + $reflectionDataRuntimeCache->remove($classNameWithUnderscores); if ($flushDoctrineProxyCache === false && preg_match('/_Domain_Model_(.+)/', $classNameWithUnderscores) === 1) { $flushDoctrineProxyCache = true; } diff --git a/Neos.Flow/Classes/Command/CacheCommandController.php b/Neos.Flow/Classes/Command/CacheCommandController.php index 9782466b81..b04fb1b520 100644 --- a/Neos.Flow/Classes/Command/CacheCommandController.php +++ b/Neos.Flow/Classes/Command/CacheCommandController.php @@ -135,9 +135,6 @@ public function injectEnvironment(Environment $environment) * from running, the removal of any temporary data can be forced by specifying * the option --force. * - * This command does not remove the precompiled data provided by frozen - * packages unless the --force option is used. - * * @param boolean $force Force flushing of any temporary data * @return void * @see neos.flow:cache:warmup @@ -157,23 +154,6 @@ public function flushCommand(bool $force = false) $this->lockManager->unlockSite(); } - $frozenPackages = []; - foreach (array_keys($this->packageManager->getAvailablePackages()) as $packageKey) { - if ($this->packageManager->isPackageFrozen($packageKey)) { - $frozenPackages[] = $packageKey; - } - } - if ($frozenPackages !== []) { - $this->outputFormatted(PHP_EOL . 'Please note that the following package' . (count($frozenPackages) === 1 ? ' is' : 's are') . ' currently frozen: ' . PHP_EOL); - $this->outputFormatted(implode(PHP_EOL, $frozenPackages) . PHP_EOL, [], 2); - - $message = 'As code and configuration changes in these packages are not detected, the application may respond '; - $message .= 'unexpectedly if modifications were done anyway or the remaining code relies on these changes.' . PHP_EOL . PHP_EOL; - $message .= 'You may call package:refreeze all in order to refresh frozen packages or use the --force '; - $message .= 'option of this cache:flush command to flush caches if Flow becomes unresponsive.' . PHP_EOL; - $this->outputFormatted($message, [$frozenPackages]); - } - $this->sendAndExit(0); } diff --git a/Neos.Flow/Classes/Command/PackageCommandController.php b/Neos.Flow/Classes/Command/PackageCommandController.php index 25e6616f5a..e005fba02c 100644 --- a/Neos.Flow/Classes/Command/PackageCommandController.php +++ b/Neos.Flow/Classes/Command/PackageCommandController.php @@ -32,25 +32,6 @@ class PackageCommandController extends CommandController */ protected $packageManager; - /** - * @var array - */ - protected $settings; - - /** - * @var Bootstrap - */ - protected $bootstrap; - - /** - * @param array $settings The Flow settings - * @return void - */ - public function injectSettings(array $settings) - { - $this->settings = $settings; - } - /** * @param PackageManager $packageManager * @return void @@ -60,15 +41,6 @@ public function injectPackageManager(PackageManager $packageManager) $this->packageManager = $packageManager; } - /** - * @param Bootstrap $bootstrap - * @return void - */ - public function injectBootstrap(Bootstrap $bootstrap) - { - $this->bootstrap = $bootstrap; - } - /** * Create a new package * @@ -112,9 +84,7 @@ public function createCommand(string $packageKey, string $packageType = PackageI public function listCommand(bool $loadingOrder = false) { $availablePackages = []; - $frozenPackages = []; $longestPackageKey = 0; - $freezeSupported = $this->bootstrap->getContext()->isDevelopment(); foreach ($this->packageManager->getAvailablePackages() as $packageKey => $package) { if (strlen($packageKey) > $longestPackageKey) { @@ -123,9 +93,6 @@ public function listCommand(bool $loadingOrder = false) $availablePackages[$packageKey] = $package; - if ($this->packageManager->isPackageFrozen($packageKey)) { - $frozenPackages[$packageKey] = $package; - } } if ($loadingOrder === false) { @@ -135,13 +102,7 @@ public function listCommand(bool $loadingOrder = false) $this->outputLine('PACKAGES:'); /** @var PackageInterface|PackageKeyAwareInterface $package */ foreach ($availablePackages as $package) { - $frozenState = ($freezeSupported && isset($frozenPackages[$package->getPackageKey()]) ? '* ' : ' '); - $this->outputLine(' ' . str_pad($package->getPackageKey(), $longestPackageKey + 3) . $frozenState . str_pad($package->getInstalledVersion(), 15)); - } - - if (count($frozenPackages) > 0 && $freezeSupported) { - $this->outputLine(); - $this->outputLine(' * frozen package'); + $this->outputLine(' ' . str_pad($package->getPackageKey(), $longestPackageKey + 3) . str_pad($package->getInstalledVersion(), 15)); } } @@ -165,47 +126,11 @@ public function listCommand(bool $loadingOrder = false) * @return void * @see neos.flow:package:unfreeze * @see neos.flow:package:refreeze + * @deprecated since 8.4 */ public function freezeCommand(string $packageKey = 'all') { - if (!$this->bootstrap->getContext()->isDevelopment()) { - $this->outputLine('Package freezing is only supported in Development context.'); - $this->quit(3); - } - - $packagesToFreeze = []; - - if ($packageKey === 'all') { - foreach (array_keys($this->packageManager->getAvailablePackages()) as $packageKey) { - if (!$this->packageManager->isPackageFrozen($packageKey)) { - $packagesToFreeze[] = $packageKey; - } - } - if ($packagesToFreeze === []) { - $this->outputLine('Nothing to do, all packages were already frozen.'); - $this->quit(0); - } - } elseif ($packageKey === 'blackberry') { - $this->outputLine('http://bit.ly/freeze-blackberry'); - $this->quit(42); - } else { - if (!$this->packageManager->isPackageAvailable($packageKey)) { - $this->outputLine('Package "%s" is not available.', [$packageKey]); - $this->quit(2); - } - - if ($this->packageManager->isPackageFrozen($packageKey)) { - $this->outputLine('Package "%s" was already frozen.', [$packageKey]); - $this->quit(0); - } - - $packagesToFreeze = [$packageKey]; - } - - foreach ($packagesToFreeze as $packageKey) { - $this->packageManager->freezePackage($packageKey); - $this->outputLine('Froze package "%s".', [$packageKey]); - } + $this->outputLine('Package freezing is no longer supported, this command is deprecated and will be removed with 9.0.'); } /** @@ -222,47 +147,11 @@ public function freezeCommand(string $packageKey = 'all') * @return void * @see neos.flow:package:freeze * @see neos.flow:cache:flush + * @deprecated since 8.4 */ public function unfreezeCommand(string $packageKey = 'all') { - if (!$this->bootstrap->getContext()->isDevelopment()) { - $this->outputLine('Package freezing is only supported in Development context.'); - $this->quit(3); - } - - $packagesToUnfreeze = []; - - if ($packageKey === 'all') { - foreach (array_keys($this->packageManager->getAvailablePackages()) as $packageKey) { - if ($this->packageManager->isPackageFrozen($packageKey)) { - $packagesToUnfreeze[] = $packageKey; - } - } - if ($packagesToUnfreeze === []) { - $this->outputLine('Nothing to do, no packages were frozen.'); - $this->quit(0); - } - } else { - if ($packageKey === null) { - $this->outputLine('You must specify a package to unfreeze.'); - $this->quit(1); - } - - if (!$this->packageManager->isPackageAvailable($packageKey)) { - $this->outputLine('Package "%s" is not available.', [$packageKey]); - $this->quit(2); - } - if (!$this->packageManager->isPackageFrozen($packageKey)) { - $this->outputLine('Package "%s" was not frozen.', [$packageKey]); - $this->quit(0); - } - $packagesToUnfreeze = [$packageKey]; - } - - foreach ($packagesToUnfreeze as $packageKey) { - $this->packageManager->unfreezePackage($packageKey); - $this->outputLine('Unfroze package "%s".', [$packageKey]); - } + $this->outputLine('Package freezing is no longer supported, this command is deprecated and will be removed with 9.0.'); } /** @@ -280,50 +169,11 @@ public function unfreezeCommand(string $packageKey = 'all') * @return void * @see neos.flow:package:freeze * @see neos.flow:cache:flush + * @deprecated since 8.4 */ public function refreezeCommand(string $packageKey = 'all') { - if (!$this->bootstrap->getContext()->isDevelopment()) { - $this->outputLine('Package freezing is only supported in Development context.'); - $this->quit(3); - } - - $packagesToRefreeze = []; - - if ($packageKey === 'all') { - foreach (array_keys($this->packageManager->getAvailablePackages()) as $packageKey) { - if ($this->packageManager->isPackageFrozen($packageKey)) { - $packagesToRefreeze[] = $packageKey; - } - } - if ($packagesToRefreeze === []) { - $this->outputLine('Nothing to do, no packages were frozen.'); - $this->quit(0); - } - } else { - if ($packageKey === null) { - $this->outputLine('You must specify a package to refreeze.'); - $this->quit(1); - } - - if (!$this->packageManager->isPackageAvailable($packageKey)) { - $this->outputLine('Package "%s" is not available.', [$packageKey]); - $this->quit(2); - } - if (!$this->packageManager->isPackageFrozen($packageKey)) { - $this->outputLine('Package "%s" was not frozen.', [$packageKey]); - $this->quit(0); - } - $packagesToRefreeze = [$packageKey]; - } - - foreach ($packagesToRefreeze as $packageKey) { - $this->packageManager->refreezePackage($packageKey); - $this->outputLine('Refroze package "%s".', [$packageKey]); - } - - Scripts::executeCommand('neos.flow:cache:flush', $this->settings, false); - $this->sendAndExit(0); + $this->outputLine('Package freezing is no longer supported, this command is deprecated and will be removed with 9.0.'); } /** diff --git a/Neos.Flow/Classes/Core/Booting/Scripts.php b/Neos.Flow/Classes/Core/Booting/Scripts.php index 7614aedf75..74edfed2e0 100644 --- a/Neos.Flow/Classes/Core/Booting/Scripts.php +++ b/Neos.Flow/Classes/Core/Booting/Scripts.php @@ -247,7 +247,7 @@ public static function initializeSystemLogger(Bootstrap $bootstrap): void $throwableStorage = self::initializeExceptionStorage($bootstrap, $settings); $bootstrap->setEarlyInstance(ThrowableStorageInterface::class, $throwableStorage); - /** @var PsrLoggerFactoryInterface $psrLoggerFactoryName */ + /** @var class-string $psrLoggerFactoryName */ $psrLoggerFactoryName = $settings['log']['psr3']['loggerFactory']; $psrLogConfigurations = $settings['log']['psr3'][$psrLoggerFactoryName] ?? []; $psrLogFactory = $psrLoggerFactoryName::create($psrLogConfigurations); @@ -578,10 +578,6 @@ public static function initializeSystemFileMonitor(Bootstrap $bootstrap) /** @var FlowPackageInterface $package */ foreach ($packageManager->getFlowPackages() as $packageKey => $package) { - if ($packageManager->isPackageFrozen($packageKey)) { - continue; - } - self::monitorDirectoryIfItExists($fileMonitors['Flow_ConfigurationFiles'], $package->getConfigurationPath(), '\.y(a)?ml$'); self::monitorDirectoryIfItExists($fileMonitors['Flow_TranslationFiles'], $package->getResourcesPath() . 'Private/Translations/', '\.xlf'); diff --git a/Neos.Flow/Classes/Package.php b/Neos.Flow/Classes/Package.php index b69f7dd552..5b37920ffe 100644 --- a/Neos.Flow/Classes/Package.php +++ b/Neos.Flow/Classes/Package.php @@ -19,6 +19,7 @@ use Neos\Flow\ObjectManagement\Proxy; use Neos\Flow\Package\Package as BasePackage; use Neos\Flow\Package\PackageManager; +use Neos\Flow\Reflection\ReflectionService; use Neos\Flow\ResourceManagement\ResourceManager; use Neos\Flow\ResourceManagement\ResourceRepository; use Neos\Flow\Security\Authentication\AuthenticationProviderManager; @@ -88,10 +89,6 @@ public function boot(Core\Bootstrap $bootstrap) /** @var PackageManager $packageManager */ $packageManager = $bootstrap->getEarlyInstance(Package\PackageManager::class); foreach ($packageManager->getFlowPackages() as $packageKey => $package) { - if ($packageManager->isPackageFrozen($packageKey)) { - continue; - } - $publicResourcesPath = $package->getResourcesPath() . 'Public/'; if (is_dir($publicResourcesPath)) { $publicResourcesFileMonitor->monitorDirectory($publicResourcesPath); @@ -122,6 +119,7 @@ public function boot(Core\Bootstrap $bootstrap) $dispatcher->connect(Core\Bootstrap::class, 'bootstrapShuttingDown', ObjectManagement\ObjectManagerInterface::class, 'shutdown'); $dispatcher->connect(Core\Bootstrap::class, 'bootstrapShuttingDown', Configuration\ConfigurationManager::class, 'shutdown'); + /** @see ReflectionService::saveToCache() */ $dispatcher->connect(Core\Bootstrap::class, 'bootstrapShuttingDown', Reflection\ReflectionService::class, 'saveToCache'); $dispatcher->connect(Command\CoreCommandController::class, 'finishedCompilationRun', Security\Authorization\Privilege\Method\MethodPrivilegePointcutFilter::class, 'savePolicyCache'); diff --git a/Neos.Flow/Classes/Package/PackageManager.php b/Neos.Flow/Classes/Package/PackageManager.php index e59f351efc..9ac23f7aa9 100644 --- a/Neos.Flow/Classes/Package/PackageManager.php +++ b/Neos.Flow/Classes/Package/PackageManager.php @@ -229,6 +229,7 @@ public function getAvailablePackages(): array * precompiled reflection data in order to improve performance. * * @return array + * @deprecated since 8.4 */ public function getFrozenPackages(): array { @@ -403,6 +404,7 @@ public function createPackage($packageKey, array $manifest = [], $packagesPath = * @param string $toAbsolutePath * @return void * @throws FilesException + * @deprecated since 8.4 */ protected function movePackage($fromAbsolutePath, $toAbsolutePath): void { @@ -411,95 +413,16 @@ protected function movePackage($fromAbsolutePath, $toAbsolutePath): void Files::removeDirectoryRecursively($fromAbsolutePath); } - /** - * Freezes a package - * - * @param string $packageKey The package to freeze - * @return void - * @throws Exception\PackageStatesFileNotWritableException - * @throws Exception\UnknownPackageException - * @throws \Neos\Flow\Exception - * @throws FilesException - */ - public function freezePackage($packageKey): void - { - if (!$this->bootstrap->getContext()->isDevelopment()) { - throw new \LogicException('Package freezing is only supported in Development context.', 1338810870); - } - - if (!$this->isPackageAvailable($packageKey)) { - throw new Exception\UnknownPackageException('Package "' . $packageKey . '" is not available.', 1331715956); - } - if ($this->isPackageFrozen($packageKey)) { - return; - } - - $package = $this->packages[$packageKey]; - $this->bootstrap->getObjectManager()->get(ReflectionService::class)->freezePackageReflection($packageKey); - - $this->packageStatesConfiguration['packages'][$package->getComposerName()]['frozen'] = true; - $this->savePackageStates($this->packageStatesConfiguration); - } - /** * Tells if a package is frozen * * @param string $packageKey The package to check * @return boolean + * @deprecated since 8.4 */ public function isPackageFrozen($packageKey): bool { - if (!isset($this->packages[$packageKey])) { - return false; - } - $composerName = $this->packages[$packageKey]->getComposerName(); - - return ( - $this->bootstrap->getContext()->isDevelopment() - && isset($this->packageStatesConfiguration['packages'][$composerName]['frozen']) - && $this->packageStatesConfiguration['packages'][$composerName]['frozen'] === true - ); - } - - /** - * Unfreezes a package - * - * @param string $packageKey The package to unfreeze - * @return void - * @throws Exception\PackageStatesFileNotWritableException - * @throws \Neos\Flow\Exception - * @throws FilesException - */ - public function unfreezePackage($packageKey): void - { - if (!$this->isPackageFrozen($packageKey)) { - return; - } - if (!isset($this->packages[$packageKey])) { - return; - } - $composerName = $this->packages[$packageKey]->getComposerName(); - - $this->bootstrap->getObjectManager()->get(ReflectionService::class)->unfreezePackageReflection($packageKey); - - unset($this->packageStatesConfiguration['packages'][$composerName]['frozen']); - $this->savePackageStates($this->packageStatesConfiguration); - } - - /** - * Refreezes a package - * - * @param string $packageKey The package to refreeze - * @return void - * @throws \Neos\Flow\Exception - */ - public function refreezePackage($packageKey): void - { - if (!$this->isPackageFrozen($packageKey)) { - return; - } - - $this->bootstrap->getObjectManager()->get(ReflectionService::class)->unfreezePackageReflection($packageKey); + return false; } /** diff --git a/Neos.Flow/Classes/Reflection/ReflectionService.php b/Neos.Flow/Classes/Reflection/ReflectionService.php index 9119bf1143..e3d88610f0 100644 --- a/Neos.Flow/Classes/Reflection/ReflectionService.php +++ b/Neos.Flow/Classes/Reflection/ReflectionService.php @@ -18,24 +18,17 @@ use Doctrine\ORM\Mapping as ORM; use Doctrine\Persistence\Proxy as DoctrineProxy; use Neos\Cache\Exception; -use Neos\Cache\Frontend\StringFrontend; use Neos\Cache\Frontend\VariableFrontend; use Neos\Flow\Annotations as Flow; -use Neos\Flow\Core\ApplicationContext; use Neos\Flow\Log\Utility\LogEnvironment; use Neos\Flow\ObjectManagement\Proxy\ProxyInterface; -use Neos\Flow\Package; -use Neos\Flow\Package\PackageManager; use Neos\Flow\Persistence\RepositoryInterface; use Neos\Flow\Reflection\Exception\ClassLoadingForReflectionFailedException; use Neos\Flow\Reflection\Exception\ClassSchemaConstraintViolationException; use Neos\Flow\Reflection\Exception\InvalidClassException; use Neos\Flow\Reflection\Exception\InvalidPropertyTypeException; use Neos\Flow\Reflection\Exception\InvalidValueObjectException; -use Neos\Flow\Utility\Environment; -use Neos\Utility\Arrays; use Neos\Utility\Exception\FilesException; -use Neos\Utility\Files; use Neos\Utility\TypeHandling; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; @@ -74,15 +67,9 @@ class ReflectionService // Implementations of an interface protected const DATA_INTERFACE_IMPLEMENTATIONS = 1; - // Implemented interfaces of a class - protected const DATA_CLASS_INTERFACES = 2; - // Subclasses of a class protected const DATA_CLASS_SUBCLASSES = 3; - // Class tag values - protected const DATA_CLASS_TAGS_VALUES = 4; - // Class annotations protected const DATA_CLASS_ANNOTATIONS = 5; protected const DATA_CLASS_ABSTRACT = 6; @@ -111,14 +98,9 @@ class ReflectionService protected Reader $annotationReader; protected array $availableClassNames = []; - protected StringFrontend $statusCache; - protected VariableFrontend $reflectionDataCompiletimeCache; protected VariableFrontend $reflectionDataRuntimeCache; protected VariableFrontend $classSchemataRuntimeCache; protected ?LoggerInterface $logger = null; - protected PackageManager $packageManager; - protected Environment $environment; - protected ApplicationContext $context; /** * The doctrine PHP parser which can parse "use" statements. Is initialized @@ -133,11 +115,6 @@ class ReflectionService */ protected array $useStatementsForClassCache; - /** - * In Production context, with frozen caches, this flag will be true - */ - protected bool $loadFromClassSchemaRuntimeCache = false; - protected array $settings = []; /** @@ -179,24 +156,6 @@ class ReflectionService */ protected array $methodAnnotationsRuntimeCache = []; - /** - * Sets the status cache - * - * The cache must be set before initializing the Reflection Service - */ - public function setStatusCache(StringFrontend $cache): void - { - $this->statusCache = $cache; - $backend = $this->statusCache->getBackend(); - if (is_callable([$backend, 'initializeObject'])) { - $backend->initializeObject(); - } - } - - public function setReflectionDataCompiletimeCache(VariableFrontend $cache): void - { - $this->reflectionDataCompiletimeCache = $cache; - } public function setReflectionDataRuntimeCache(VariableFrontend $cache): void { @@ -218,16 +177,6 @@ public function injectLogger(LoggerInterface $logger): void $this->logger = $logger; } - public function injectPackageManager(PackageManager $packageManager): void - { - $this->packageManager = $packageManager; - } - - public function injectEnvironment(Environment $environment): void - { - $this->environment = $environment; - } - protected function getDoctrinePhpParser(): PhpParser { if ($this->doctrinePhpParser === null) { @@ -241,20 +190,14 @@ protected function getDoctrinePhpParser(): PhpParser * Initialize the reflection service lazily * * This method must be run only after all dependencies have been injected. - * - * @throws FilesException - * @throws \Neos\Flow\Utility\Exception */ protected function initialize(): void { - $this->context = $this->environment->getContext(); - - if ($this->hasFrozenCacheInProduction()) { - $this->classReflectionData = $this->reflectionDataRuntimeCache->get('__classNames'); + $classNames = $this->reflectionDataRuntimeCache->get('__classNames'); + if (is_array($classNames)) { + $this->classReflectionData = $classNames; $this->annotatedClasses = $this->reflectionDataRuntimeCache->get('__annotatedClasses'); - $this->loadFromClassSchemaRuntimeCache = true; - } else { - $this->loadClassReflectionCompiletimeCache(); + $this->classesByMethodAnnotations = $this->reflectionDataRuntimeCache->get('__classesByMethodAnnotations'); } $this->annotationReader = new AnnotationReader(); @@ -273,13 +216,14 @@ protected function initialize(): void * This method is called by the Compile Time Object Manager which also determines * the list of classes to consider for reflection. * + * @param array $availableClassNames * @throws ClassLoadingForReflectionFailedException * @throws ClassSchemaConstraintViolationException * @throws Exception - * @throws FilesException * @throws InvalidClassException + * @throws InvalidPropertyTypeException + * @throws InvalidValueObjectException * @throws ReflectionException - * @throws \Neos\Flow\Utility\Exception */ public function buildReflectionData(array $availableClassNames): void { @@ -295,6 +239,8 @@ public function buildReflectionData(array $availableClassNames): void * Tells if the specified class is known to this reflection service and * reflection information is available. * + * @param class-string $className + * * @api */ public function isClassReflected(string $className): bool @@ -304,7 +250,7 @@ public function isClassReflected(string $className): bool } $className = $this->cleanClassName($className); - return isset($this->classReflectionData[$className]); + return isset($this->classReflectionData[$className]) && is_array($this->classReflectionData[$className]); } /** @@ -330,15 +276,10 @@ public function getAllClassNames(): array */ public function getDefaultImplementationClassNameForInterface(string $interfaceName): string|bool { - if (!$this->initialized) { - $this->initialize(); - } - $interfaceName = $this->cleanClassName($interfaceName); - if (interface_exists($interfaceName) === false) { throw new \InvalidArgumentException('"' . $interfaceName . '" does not exist or is not the name of an interface.', 1238769559); } - $this->loadOrReflectClassIfNecessary($interfaceName); + $interfaceName = $this->prepareClassReflectionForUsage($interfaceName); $classNamesFound = isset($this->classReflectionData[$interfaceName][self::DATA_INTERFACE_IMPLEMENTATIONS]) ? array_keys($this->classReflectionData[$interfaceName][self::DATA_INTERFACE_IMPLEMENTATIONS]) : []; if (count($classNamesFound) === 1) { @@ -362,21 +303,16 @@ public function getDefaultImplementationClassNameForInterface(string $interfaceN * Searches for and returns all class names of implementations of the given object type * (interface name). If no class implementing the interface was found, an empty array is returned. * - * @throws ClassLoadingForReflectionFailedException - * @throws InvalidClassException + * @param class-string $interfaceName + * @return array * @api */ public function getAllImplementationClassNamesForInterface(string $interfaceName): array { - if (!$this->initialized) { - $this->initialize(); - } - $interfaceName = $this->cleanClassName($interfaceName); - if (interface_exists($interfaceName) === false) { throw new \InvalidArgumentException('"' . $interfaceName . '" does not exist or is not the name of an interface.', 1238769560); } - $this->loadOrReflectClassIfNecessary($interfaceName); + $interfaceName = $this->prepareClassReflectionForUsage($interfaceName); return (isset($this->classReflectionData[$interfaceName][self::DATA_INTERFACE_IMPLEMENTATIONS])) ? array_keys($this->classReflectionData[$interfaceName][self::DATA_INTERFACE_IMPLEMENTATIONS]) : []; } @@ -387,22 +323,14 @@ public function getAllImplementationClassNamesForInterface(string $interfaceName * * @psalm-param class-string $className * @psalm-return array - * @throws ClassLoadingForReflectionFailedException - * @throws InvalidClassException * @api */ public function getAllSubClassNamesForClass(string $className): array { - if (!$this->initialized) { - $this->initialize(); - } - $className = $this->cleanClassName($className); - if (class_exists($className) === false) { throw new \InvalidArgumentException('"' . $className . '" does not exist or is not the name of a class.', 1257168042); } - $this->loadOrReflectClassIfNecessary($className); - + $className = $this->prepareClassReflectionForUsage($className); return (isset($this->classReflectionData[$className][self::DATA_CLASS_SUBCLASSES])) ? array_keys($this->classReflectionData[$className][self::DATA_CLASS_SUBCLASSES]) : []; } @@ -762,7 +690,7 @@ public function hasMethod(string $className, string $methodName): bool * Returns all tags and their values the specified method is tagged with * * @throws ReflectionException - * @api + * @deprecated since 8.4 */ public function getMethodTagsValues(string $className, string $methodName): array { @@ -866,6 +794,7 @@ public function getPropertyTagValues(string $className, string $propertyName, st */ public function getPropertyType(string $className, string $propertyName): ?string { + $className = $this->prepareClassReflectionForUsage($className); return $this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_TYPE] ?? null; } @@ -991,6 +920,12 @@ public function getClassSchema(string|object $classNameOrObject): ?ClassSchema /** * Initializes the ReflectionService, cleans the given class name and finally reflects the class if necessary. + * + * @param class-string $className + * @return string + * @throws ClassLoadingForReflectionFailedException + * @throws InvalidClassException + * @throws ReflectionException */ protected function prepareClassReflectionForUsage(string $className): string { @@ -1012,14 +947,17 @@ protected function prepareClassReflectionForUsage(string $className): string * @throws ClassSchemaConstraintViolationException * @throws Exception * @throws InvalidClassException + * @throws InvalidPropertyTypeException + * @throws InvalidValueObjectException * @throws ReflectionException */ protected function reflectEmergedClasses(): void { - $classNamesToReflect = []; - foreach ($this->availableClassNames as $classNamesInOnePackage) { - $classNamesToReflect = array_merge($classNamesToReflect, $classNamesInOnePackage); + $availableClassnames = []; + foreach ($this->availableClassNames as $classNamesInPackage) { + $availableClassnames[] = $classNamesInPackage; } + $classNamesToReflect = array_merge([], ...$availableClassnames); $reflectedClassNames = array_keys($this->classReflectionData); sort($classNamesToReflect); sort($reflectedClassNames); @@ -1032,7 +970,7 @@ protected function reflectEmergedClasses(): void $count = 0; $classNameFilterFunction = function ($className) use (&$count): bool { - $this->reflectClass($className); + $this->loadOrReflectClassIfNecessary($className); if ( !$this->isClassAnnotatedWith($className, Flow\Entity::class) && !$this->isClassAnnotatedWith($className, ORM\Entity::class) && @@ -1092,10 +1030,14 @@ protected function reflectClass(string $className): void } $class = new ClassReflection($className); - if (!isset($this->classReflectionData[$className])) { + if (!isset($this->classReflectionData[$className]) || !is_array($this->classReflectionData[$className])) { $this->classReflectionData[$className] = []; } + if (!isset($this->classReflectionData[$className][self::DATA_INTERFACE_IMPLEMENTATIONS]) && $class->isInterface()) { + $this->classReflectionData[$className][self::DATA_INTERFACE_IMPLEMENTATIONS] = []; + } + if ($class->isAbstract() || $class->isInterface()) { $this->classReflectionData[$className][self::DATA_CLASS_ABSTRACT] = true; } @@ -1140,7 +1082,6 @@ protected function reflectClass(string $className): void // important for comparisons when checking if classes have changed in a // Development context. ksort($this->classReflectionData); - $this->updatedReflectionData[$className] = true; } @@ -1159,9 +1100,10 @@ public function reflectClassProperty(string $className, PropertyReflection $prop $this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_TYPE] = trim((string)$property->getType(), '?'); } - $visibility = $property->isPublic() ? self::VISIBILITY_PUBLIC : ($property->isProtected() ? self::VISIBILITY_PROTECTED : self::VISIBILITY_PRIVATE); + $visibility = $this->extractVisibility($property); $this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_VISIBILITY] = $visibility; + foreach ($property->getTagsValues() as $tagName => $tagValues) { $tagValues = $this->reflectPropertyTag($className, $property, $tagName, $tagValues); if ($tagValues === null) { @@ -1217,8 +1159,8 @@ protected function reflectPropertyTag(string $className, PropertyReflection $pro protected function addParentClass(string $className, ClassReflection $parentClass): void { $parentClassName = $parentClass->getName(); - if (!isset($this->classReflectionData[$parentClassName])) { - $this->reflectClass($parentClassName); + if (!$this->isClassReflected($parentClassName)) { + $this->loadOrReflectClassIfNecessary($parentClassName); } $this->classReflectionData[$parentClassName][self::DATA_CLASS_SUBCLASSES][$className] = true; } @@ -1235,9 +1177,10 @@ protected function addImplementedInterface(string $className, ClassReflection $i } $interfaceName = $interface->getName(); - if (!isset($this->classReflectionData[$interfaceName])) { - $this->reflectClass($interfaceName); + if (!$this->isClassReflected($interfaceName)) { + $this->loadOrReflectClassIfNecessary($interfaceName); } + $this->classReflectionData[$interfaceName][self::DATA_INTERFACE_IMPLEMENTATIONS][$className] = true; } @@ -1255,8 +1198,7 @@ protected function reflectClassMethod(string $className, MethodReflection $metho if ($method->isStatic()) { $this->classReflectionData[$className][self::DATA_CLASS_METHODS][$methodName][self::DATA_METHOD_STATIC] = true; } - $visibility = $method->isPublic() ? self::VISIBILITY_PUBLIC : ($method->isProtected() ? self::VISIBILITY_PROTECTED : self::VISIBILITY_PRIVATE); - $this->classReflectionData[$className][self::DATA_CLASS_METHODS][$methodName][self::DATA_METHOD_VISIBILITY] = $visibility; + $this->classReflectionData[$className][self::DATA_CLASS_METHODS][$methodName][self::DATA_METHOD_VISIBILITY] = $this->extractVisibility($method); foreach ($this->getMethodAnnotations($className, $methodName) as $methodAnnotation) { $annotationClassName = get_class($methodAnnotation); @@ -1294,6 +1236,15 @@ protected function reflectClassMethod(string $className, MethodReflection $metho } } + protected function extractVisibility(MethodReflection|PropertyReflection $reflection): int + { + return match (true) { + $reflection->isPublic() => self::VISIBILITY_PUBLIC, + $reflection->isProtected() => self::VISIBILITY_PROTECTED, + default => self::VISIBILITY_PRIVATE + }; + } + /** * @param string $className * @param MethodReflection $method @@ -1369,7 +1320,7 @@ protected function expandType(ClassReflection $class, string $type): string // and then we try to find "use" statements for the class. $className = $class->getName(); if (!isset($this->useStatementsForClassCache[$className])) { - $this->useStatementsForClassCache[$className] = $this->getDoctrinePhpParser()->parseClass($class); + $this->useStatementsForClassCache[$className] = $this->getDoctrinePhpParser()->parseUseStatements($class); } $useStatementsForClass = $this->useStatementsForClassCache[$className]; @@ -1404,10 +1355,12 @@ protected function getParentClasses(ClassReflection $class, array $parentClasses /** * Builds class schemata from classes annotated as entities or value objects * + * @param array $classNames * @throws ClassLoadingForReflectionFailedException * @throws ClassSchemaConstraintViolationException * @throws Exception * @throws InvalidClassException + * @throws InvalidPropertyTypeException * @throws InvalidValueObjectException */ protected function buildClassSchemata(array $classNames): void @@ -1730,26 +1683,9 @@ protected function convertParameterReflectionToArray(ParameterReflection $parame */ protected function forgetChangedClasses(): void { - $frozenNamespaces = []; - foreach ($this->packageManager->getAvailablePackages() as $packageKey => $package) { - if ($this->packageManager->isPackageFrozen($packageKey)) { - $frozenNamespaces = array_merge($frozenNamespaces, $package->getNamespaces()); - } - } - $frozenNamespaces = array_unique($frozenNamespaces); - $classNames = array_keys($this->classReflectionData); - foreach ($frozenNamespaces as $namespace) { - $namespace .= '\\'; - foreach ($classNames as $index => $className) { - if (str_starts_with($className, $namespace)) { - unset($classNames[$index]); - } - } - } - foreach ($classNames as $className) { - if (!$this->statusCache->has($this->produceCacheIdentifierFromClassName($className))) { + if (!$this->reflectionDataRuntimeCache->has($this->produceCacheIdentifierFromClassName($className))) { $this->forgetClass($className); } } @@ -1812,57 +1748,6 @@ protected function forgetClass($className): void unset($this->classesCurrentlyBeingForgotten[$className]); } - /** - * Tries to load the reflection data from the compile time cache. - * - * The compile time cache is only supported for Development context and thus - * this function will return in any other context. - * - * If no reflection data was found, this method will at least load the precompiled - * reflection data of any possible frozen package. Even if precompiled reflection - * data could be loaded, false will be returned in order to signal that other - * packages still need to be reflected. - * - * @return bool true if reflection data could be loaded, otherwise false - * @throws FilesException - * @throws \Neos\Flow\Utility\Exception - */ - protected function loadClassReflectionCompiletimeCache(): bool - { - $data = $this->reflectionDataCompiletimeCache->get('ReflectionData'); - - if ($data !== false) { - foreach ($data as $propertyName => $propertyValue) { - $this->$propertyName = $propertyValue; - } - - return true; - } - - if (!$this->context->isDevelopment()) { - return false; - } - - $useIgBinary = extension_loaded('igbinary'); - foreach ($this->packageManager->getAvailablePackages() as $packageKey => $package) { - if (!$this->packageManager->isPackageFrozen($packageKey)) { - continue; - } - - $pathAndFilename = $this->getPrecompiledReflectionStoragePath() . $packageKey . '.dat'; - if (!file_exists($pathAndFilename)) { - continue; - } - - $data = ($useIgBinary ? igbinary_unserialize(file_get_contents($pathAndFilename)) : unserialize(file_get_contents($pathAndFilename))); - foreach ($data as $propertyName => $propertyValue) { - $this->$propertyName = Arrays::arrayMergeRecursiveOverrule($this->$propertyName, $propertyValue); - } - } - - return false; - } - /** * Loads reflection data from the cache or reflects the class if needed. * @@ -1879,155 +1764,38 @@ protected function loadClassReflectionCompiletimeCache(): bool */ protected function loadOrReflectClassIfNecessary(string $className): void { - if (!isset($this->classReflectionData[$className]) || is_array($this->classReflectionData[$className])) { + if ($this->isClassReflected($className)) { return; } - if ($this->loadFromClassSchemaRuntimeCache === true) { - $this->classReflectionData[$className] = $this->reflectionDataRuntimeCache->get($this->produceCacheIdentifierFromClassName($className)); + $this->classReflectionData[$className] = $this->reflectionDataRuntimeCache->get($this->produceCacheIdentifierFromClassName($className)); + if ($this->isClassReflected($className)) { return; } $this->reflectClass($className); } - /** - * Stores the current reflection data related to classes of the specified package - * in the PrecompiledReflectionData directory for the current context. - * - * This method is used by the package manager. - * - * @param (int|string) $packageKey - * - * @psalm-param array-key $packageKey - */ - public function freezePackageReflection($packageKey): void - { - if (!$this->initialized) { - $this->initialize(); - } - if (empty($this->availableClassNames)) { - $this->availableClassNames = $this->reflectionDataRuntimeCache->get('__availableClassNames'); - } - - $reflectionData = [ - 'classReflectionData' => $this->classReflectionData, - 'classSchemata' => $this->classSchemata, - 'annotatedClasses' => $this->annotatedClasses, - 'classesByMethodAnnotations' => $this->classesByMethodAnnotations - ]; - - $reflectionData['classReflectionData'] = $this->filterArrayByClassesInPackageNamespace($reflectionData['classReflectionData'], $packageKey); - $reflectionData['classSchemata'] = $this->filterArrayByClassesInPackageNamespace($reflectionData['classSchemata'], $packageKey); - $reflectionData['annotatedClasses'] = $this->filterArrayByClassesInPackageNamespace($reflectionData['annotatedClasses'], $packageKey); - - $methodAnnotationsFilters = function ($className) use ($packageKey): bool { - return (isset($this->availableClassNames[$packageKey]) && in_array($className, $this->availableClassNames[$packageKey], true)); - }; - - foreach ($reflectionData['classesByMethodAnnotations'] as $annotationClassName => $classNames) { - $reflectionData['classesByMethodAnnotations'][$annotationClassName] = array_filter($classNames, $methodAnnotationsFilters); - } - - $precompiledReflectionStoragePath = $this->getPrecompiledReflectionStoragePath(); - if (!is_dir($precompiledReflectionStoragePath)) { - Files::createDirectoryRecursively($precompiledReflectionStoragePath); - } - $pathAndFilename = $precompiledReflectionStoragePath . $packageKey . '.dat'; - file_put_contents($pathAndFilename, extension_loaded('igbinary') ? igbinary_serialize($reflectionData) : serialize($reflectionData)); - } - - /** - * Filter an array of entries where keys are class names by being in the given package namespace. - * - * @param int|string $packageKey - * - * @psalm-param array-key $packageKey - */ - protected function filterArrayByClassesInPackageNamespace(array $array, $packageKey): array - { - return array_filter($array, function ($className) use ($packageKey) { - return (isset($this->availableClassNames[$packageKey]) && in_array($className, $this->availableClassNames[$packageKey], true)); - }, ARRAY_FILTER_USE_KEY); - } - - /** - * Removes the precompiled reflection data of a frozen package - * - * This method is used by the package manager. - * - * @throws FilesException - * @throws \Neos\Flow\Utility\Exception - */ - public function unfreezePackageReflection(string $packageKey): void - { - if (!$this->initialized) { - $this->initialize(); - } - $pathAndFilename = $this->getPrecompiledReflectionStoragePath() . $packageKey . '.dat'; - if (file_exists($pathAndFilename)) { - unlink($pathAndFilename); - } - } - /** * Exports the internal reflection data into the ReflectionData cache * * This method is triggered by a signal which is connected to the bootstrap's * shutdown sequence. * - * If the reflection data has previously been loaded from the runtime cache, - * saving it is omitted as changes are not expected. - * - * In Production context the whole cache is written at once and then frozen in - * order to be consistent. Frozen cache data in Development is only produced for - * classes contained in frozen packages. * @throws Exception */ public function saveToCache(): void { - if ($this->hasFrozenCacheInProduction()) { - return; - } if (!$this->initialized) { $this->initialize(); } - if ($this->loadFromClassSchemaRuntimeCache === true) { - return; - } - if (!empty($this->availableClassNames)) { - $this->reflectionDataRuntimeCache->set('__availableClassNames', $this->availableClassNames); - } - - if ($this->updatedReflectionData !== []) { - $this->updateReflectionData(); - } - - if ($this->context->isProduction()) { - $this->saveProductionData(); + if (empty($this->updatedReflectionData)) { return; } - $this->saveDevelopmentData(); - } - - /** - * Save reflection data to cache in Development context. - * - * @throws FilesException - * @throws \Neos\Flow\Utility\Exception - */ - protected function saveDevelopmentData(): void - { - foreach (array_keys($this->packageManager->getFrozenPackages()) as $packageKey) { - $pathAndFilename = $this->getPrecompiledReflectionStoragePath() . $packageKey . '.dat'; - if (!file_exists($pathAndFilename)) { - $this->log(sprintf('Rebuilding precompiled reflection data for frozen package %s.', $packageKey), LogLevel::DEBUG); - $this->freezePackageReflection($packageKey); - } - } + $this->saveProductionData(); } /** @@ -2037,55 +1805,27 @@ protected function saveDevelopmentData(): void */ protected function saveProductionData(): void { - $this->reflectionDataRuntimeCache->flush(); - $this->classSchemataRuntimeCache->flush(); - $classNames = []; foreach ($this->classReflectionData as $className => $reflectionData) { - $classNames[$className] = true; + if ($this->isClassReflected($className)) { + $classNames[$className] = true; + } + } + + foreach (array_keys($this->updatedReflectionData) as $className) { + $reflectionData = $this->classReflectionData[$className]; $cacheIdentifier = $this->produceCacheIdentifierFromClassName($className); $this->reflectionDataRuntimeCache->set($cacheIdentifier, $reflectionData); if (isset($this->classSchemata[$className])) { $this->classSchemataRuntimeCache->set($cacheIdentifier, $this->classSchemata[$className]); } } + $this->reflectionDataRuntimeCache->set('__classNames', $classNames); $this->reflectionDataRuntimeCache->set('__annotatedClasses', $this->annotatedClasses); + $this->reflectionDataRuntimeCache->set('__classesByMethodAnnotations', $this->classesByMethodAnnotations); - /** @phpstan-ignore-next-line will be refactored with neos 9 */ - $this->reflectionDataRuntimeCache->getBackend()->freeze(); - /** @phpstan-ignore-next-line will be refactored with neos 9 */ - $this->classSchemataRuntimeCache->getBackend()->freeze(); - - $this->log(sprintf('Built and froze reflection runtime caches (%s classes).', count($this->classReflectionData)), LogLevel::INFO); - } - - /** - * Set updated reflection data to caches. - * - * @throws Exception - */ - protected function updateReflectionData(): void - { - $this->log(sprintf('Found %s classes whose reflection data was not cached previously.', count($this->updatedReflectionData)), LogLevel::DEBUG); - - foreach (array_keys($this->updatedReflectionData) as $className) { - $this->statusCache->set($this->produceCacheIdentifierFromClassName($className), ''); - } - - $data = []; - $propertyNames = [ - 'classReflectionData', - 'classSchemata', - 'annotatedClasses', - 'classesByMethodAnnotations' - ]; - - foreach ($propertyNames as $propertyName) { - $data[$propertyName] = $this->$propertyName; - } - - $this->reflectionDataCompiletimeCache->set('ReflectionData', $data); + $this->log(sprintf('Updated reflection caches (%s classes).', count($this->updatedReflectionData)), LogLevel::INFO); } /** @@ -2112,22 +1852,7 @@ protected function log(string $message, string $severity = LogLevel::INFO, array $this->logger?->log($severity, $message, $additionalData); } - /** - * @throws \Neos\Flow\Utility\Exception - * @throws FilesException - */ - protected function getPrecompiledReflectionStoragePath(): string - { - return Files::concatenatePaths([$this->environment->getPathToTemporaryDirectory(), 'PrecompiledReflectionData/']) . '/'; - } - - protected function hasFrozenCacheInProduction(): bool - { - /** @phpstan-ignore-next-line will be refactored with neos 9 */ - return $this->environment->getContext()->isProduction() && $this->reflectionDataRuntimeCache->getBackend()->isFrozen(); - } - - private function renderParameterType(?\ReflectionType $parameterType): ?string + private function renderParameterType(?\ReflectionType $parameterType = null): string|null { $that = $this; return match (true) { diff --git a/Neos.Flow/Classes/Reflection/ReflectionServiceFactory.php b/Neos.Flow/Classes/Reflection/ReflectionServiceFactory.php index c86ead9de3..a0673a2269 100644 --- a/Neos.Flow/Classes/Reflection/ReflectionServiceFactory.php +++ b/Neos.Flow/Classes/Reflection/ReflectionServiceFactory.php @@ -64,12 +64,8 @@ public function create(): ReflectionService $reflectionService = new ReflectionService(); $reflectionService->injectLogger($this->bootstrap->getEarlyInstance(PsrLoggerFactoryInterface::class)->get('systemLogger')); $reflectionService->injectSettings($settings); - $reflectionService->injectPackageManager($this->bootstrap->getEarlyInstance(PackageManager::class)); - $reflectionService->setStatusCache($cacheManager->getCache('Flow_Reflection_Status')); - $reflectionService->setReflectionDataCompiletimeCache($cacheManager->getCache('Flow_Reflection_CompiletimeData')); $reflectionService->setReflectionDataRuntimeCache($cacheManager->getCache('Flow_Reflection_RuntimeData')); $reflectionService->setClassSchemataRuntimeCache($cacheManager->getCache('Flow_Reflection_RuntimeClassSchemata')); - $reflectionService->injectEnvironment($this->bootstrap->getEarlyInstance(Environment::class)); $this->reflectionService = $reflectionService; return $reflectionService; diff --git a/Neos.Flow/Configuration/Caches.yaml b/Neos.Flow/Configuration/Caches.yaml index b7238738c1..e9ea1501f1 100644 --- a/Neos.Flow/Configuration/Caches.yaml +++ b/Neos.Flow/Configuration/Caches.yaml @@ -93,16 +93,23 @@ Flow_Persistence_Doctrine_Results: Flow_Persistence_Doctrine_SecondLevel: backend: Neos\Cache\Backend\SimpleFileBackend -# Flow_Reflection* # +# DEPRECATED since 8.4 +# These caches will be removed in 9.0, they are unused so you can safely remove any configuration for them. # Flow_Reflection_Status: frontend: Neos\Cache\Frontend\StringFrontend backend: Neos\Cache\Backend\SimpleFileBackend Flow_Reflection_CompiletimeData: backend: Neos\Cache\Backend\SimpleFileBackend -Flow_Reflection_RuntimeData: [] -Flow_Reflection_RuntimeClassSchemata: [] + +# Flow_Reflection +# +# +Flow_Reflection_RuntimeData: + backend: Neos\Cache\Backend\SimpleFileBackend +Flow_Reflection_RuntimeClassSchemata: + backend: Neos\Cache\Backend\SimpleFileBackend # Flow_Resource_Status # diff --git a/Neos.Flow/Tests/Functional/Reflection/ReflectionServiceTest.php b/Neos.Flow/Tests/Functional/Reflection/ReflectionServiceTest.php index ac8807d3fe..a306e8ab96 100644 --- a/Neos.Flow/Tests/Functional/Reflection/ReflectionServiceTest.php +++ b/Neos.Flow/Tests/Functional/Reflection/ReflectionServiceTest.php @@ -57,6 +57,7 @@ public function classSchemaCanBeBuiltForAggregateRootsWithPlainOldPhpBaseClasses /** * @test * @throws + * @deprecated */ public function theReflectionServiceCorrectlyBuildsMethodTagsValues(): void { diff --git a/Neos.Flow/Tests/Unit/Cache/CacheManagerTest.php b/Neos.Flow/Tests/Unit/Cache/CacheManagerTest.php index 232e8e577a..5401b60a91 100644 --- a/Neos.Flow/Tests/Unit/Cache/CacheManagerTest.php +++ b/Neos.Flow/Tests/Unit/Cache/CacheManagerTest.php @@ -277,7 +277,7 @@ public function flushSystemCachesByChangedFilesWithChangedClassFileRemovesCacheE { $objectClassCache = $this->registerCache('Flow_Object_Classes'); $objectConfigurationCache = $this->registerCache('Flow_Object_Configuration'); - $this->registerCache('Flow_Reflection_Status'); + $this->registerCache('Flow_Reflection_RuntimeData'); $objectClassCache->expects(self::once())->method('remove')->with('Neos_Flow_Cache_CacheManager'); $objectConfigurationCache->expects(self::once())->method('remove')->with('allCompiledCodeUpToDate'); @@ -294,7 +294,7 @@ public function flushSystemCachesByChangedFilesWithChangedTestFileRemovesCacheEn { $objectClassCache = $this->registerCache('Flow_Object_Classes'); $objectConfigurationCache = $this->registerCache('Flow_Object_Configuration'); - $this->registerCache('Flow_Reflection_Status'); + $this->registerCache('Flow_Reflection_RuntimeData'); $objectClassCache->expects(self::once())->method('remove')->with('Neos_Flow_Tests_Unit_Cache_CacheManagerTest'); $objectConfigurationCache->expects(self::once())->method('remove')->with('allCompiledCodeUpToDate'); diff --git a/Neos.Flow/Tests/Unit/Package/PackageManagerTest.php b/Neos.Flow/Tests/Unit/Package/PackageManagerTest.php index ab32cb06e3..72bb58373c 100644 --- a/Neos.Flow/Tests/Unit/Package/PackageManagerTest.php +++ b/Neos.Flow/Tests/Unit/Package/PackageManagerTest.php @@ -470,36 +470,4 @@ public function createPackageEmitsPackageStatesUpdatedSignal() $this->mockDispatcher->expects(self::once())->method('dispatch')->with(PackageManager::class, 'packageStatesUpdated'); $this->packageManager->createPackage('Some.Package', [], 'vfs://Test/Packages/Application'); } - - /** - * @test - */ - public function freezePackageEmitsPackageStatesUpdatedSignal() - { - $this->mockApplicationContext->expects(self::atLeastOnce())->method('isDevelopment')->will(self::returnValue(true)); - - $this->packageManager->createPackage('Some.Package', [ - 'name' => 'some/package' - ], 'vfs://Test/Packages/Application'); - - $this->mockDispatcher->expects(self::once())->method('dispatch')->with(PackageManager::class, 'packageStatesUpdated'); - $this->packageManager->freezePackage('Some.Package'); - } - - /** - * @test - */ - public function unfreezePackageEmitsPackageStatesUpdatedSignal() - { - $this->mockApplicationContext->expects(self::atLeastOnce())->method('isDevelopment')->will(self::returnValue(true)); - - $this->packageManager->createPackage('Some.Package', [ - 'name' => 'some/package', - 'type' => 'neos-package' - ], 'vfs://Test/Packages/Application'); - $this->packageManager->freezePackage('Some.Package'); - - $this->mockDispatcher->expects(self::once())->method('dispatch')->with(PackageManager::class, 'packageStatesUpdated'); - $this->packageManager->unfreezePackage('Some.Package'); - } } diff --git a/Neos.FluidAdaptor/Classes/Package.php b/Neos.FluidAdaptor/Classes/Package.php index 9f6a9cd540..84a32d31ed 100644 --- a/Neos.FluidAdaptor/Classes/Package.php +++ b/Neos.FluidAdaptor/Classes/Package.php @@ -48,10 +48,6 @@ public function boot(Bootstrap $bootstrap) $packageManager = $bootstrap->getEarlyInstance(PackageManager::class); /** @var FlowPackageInterface $package */ foreach ($packageManager->getFlowPackages() as $packageKey => $package) { - if ($packageManager->isPackageFrozen($packageKey)) { - continue; - } - foreach (['Templates', 'Partials', 'Layouts'] as $path) { $templatesPath = $package->getResourcesPath() . 'Private/' . $path;