Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

TASK: Cosmetic followup for #3443 #3447

Merged
merged 4 commits into from
Feb 18, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 37 additions & 80 deletions Neos.Flow/Classes/Reflection/ReflectionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,15 @@
* service also builds up class schema information which is used by the Flow's
* persistence layer.
*
* Reflection of classes of all active packages is triggered through the bootstrap's
* initializeReflectionService() method. In a development context, single classes
* may be re-reflected once files are modified whereas in a production context
* reflection is done once and successive requests read from the frozen caches for
* performance reasons.
* The list of available classes from flow packages is determined during initialisation of the
* CompileTimeObjectManager which also triggers the initial build of reflection data.
*
* The list of available classes is determined by the CompiletimeObjectManager which
* also triggers the initial build of reflection data in this service.
* During shutdown any reflection changes that occurred are saved to the cache.
*
* The invalidation of reflection cache entries is done by the CacheManager which
* in turn is triggered by signals sent by the file monitor.
* The invalidation of reflection cache entries is done by the CacheManager during development
* via flushClassCachesByChangedFiles by removing the reflected data from the cache.
*
* The internal representation of cache data is optimized for memory consumption and
* speed by using constants which have an integer value.
* The internal representation of cache data is optimized for memory consumption.
*
* @api
* @Flow\Scope("singleton")
Expand Down Expand Up @@ -284,7 +279,7 @@ public function getDefaultImplementationClassNameForInterface(string $interfaceN
}
$interfaceName = $this->prepareClassReflectionForUsage($interfaceName);

$classNamesFound = isset($this->classReflectionData[$interfaceName][self::DATA_INTERFACE_IMPLEMENTATIONS]) ? array_keys($this->classReflectionData[$interfaceName][self::DATA_INTERFACE_IMPLEMENTATIONS]) : [];
$classNamesFound = array_keys($this->classReflectionData[$interfaceName][self::DATA_INTERFACE_IMPLEMENTATIONS] ?? []);
if (count($classNamesFound) === 1) {
return $classNamesFound[0];
}
Expand Down Expand Up @@ -320,7 +315,7 @@ public function getAllImplementationClassNamesForInterface(string $interfaceName
}
$interfaceName = $this->prepareClassReflectionForUsage($interfaceName);

return (isset($this->classReflectionData[$interfaceName][self::DATA_INTERFACE_IMPLEMENTATIONS])) ? array_keys($this->classReflectionData[$interfaceName][self::DATA_INTERFACE_IMPLEMENTATIONS]) : [];
return array_keys($this->classReflectionData[$interfaceName][self::DATA_INTERFACE_IMPLEMENTATIONS] ?? []);
}

/**
Expand All @@ -340,7 +335,7 @@ public function getAllSubClassNamesForClass(string $className): array
throw new \InvalidArgumentException('"' . $className . '" does not exist or is not the name of a class.', 1257168042);
}
$className = $this->prepareClassReflectionForUsage($className);
return (isset($this->classReflectionData[$className][self::DATA_CLASS_SUBCLASSES])) ? array_keys($this->classReflectionData[$className][self::DATA_CLASS_SUBCLASSES]) : [];
return array_keys($this->classReflectionData[$className][self::DATA_CLASS_SUBCLASSES] ?? []);
}

/**
Expand All @@ -354,7 +349,7 @@ public function getClassNamesByAnnotation(string $annotationClassName): array
}
$annotationClassName = $this->cleanClassName($annotationClassName);

return (isset($this->annotatedClasses[$annotationClassName]) ? array_keys($this->annotatedClasses[$annotationClassName]) : []);
return array_keys($this->annotatedClasses[$annotationClassName] ?? []);
}

/**
Expand All @@ -371,7 +366,7 @@ public function isClassAnnotatedWith(string $className, string $annotationClassN

$annotationClassName = $this->cleanClassName($annotationClassName);

return (isset($this->annotatedClasses[$annotationClassName][$className]));
return isset($this->annotatedClasses[$annotationClassName][$className]);
}

/**
Expand Down Expand Up @@ -440,11 +435,9 @@ public function getClassAnnotation(string $className, string $annotationClassNam
public function isClassImplementationOf(string $className, string $interfaceName): bool
{
$className = $this->prepareClassReflectionForUsage($className);
$this->prepareClassReflectionForUsage($interfaceName);

$interfaceName = $this->cleanClassName($interfaceName);
$this->loadOrReflectClassIfNecessary($interfaceName);

return (isset($this->classReflectionData[$interfaceName][self::DATA_INTERFACE_IMPLEMENTATIONS][$className]));
return isset($this->classReflectionData[$interfaceName][self::DATA_INTERFACE_IMPLEMENTATIONS][$className]);
}

/**
Expand Down Expand Up @@ -517,7 +510,7 @@ public function getClassesContainingMethodsAnnotatedWith(string $annotationClass
$this->initialize();
}

return isset($this->classesByMethodAnnotations[$annotationClassName]) ? array_keys($this->classesByMethodAnnotations[$annotationClassName]) : [];
return array_keys($this->classesByMethodAnnotations[$annotationClassName] ?? []);
}

/**
Expand Down Expand Up @@ -575,7 +568,7 @@ public function isMethodStatic(string $className, string $methodName): bool
public function isMethodPublic(string $className, string $methodName): bool
{
$className = $this->prepareClassReflectionForUsage($className);
return (isset($this->classReflectionData[$className][self::DATA_CLASS_METHODS][$methodName][self::DATA_METHOD_VISIBILITY]) && $this->classReflectionData[$className][self::DATA_CLASS_METHODS][$methodName][self::DATA_METHOD_VISIBILITY] === self::VISIBILITY_PUBLIC);
return ($this->classReflectionData[$className][self::DATA_CLASS_METHODS][$methodName][self::DATA_METHOD_VISIBILITY] ?? null) === self::VISIBILITY_PUBLIC;
}

/**
Expand All @@ -588,7 +581,7 @@ public function isMethodPublic(string $className, string $methodName): bool
public function isMethodProtected(string $className, string $methodName): bool
{
$className = $this->prepareClassReflectionForUsage($className);
return (isset($this->classReflectionData[$className][self::DATA_CLASS_METHODS][$methodName][self::DATA_METHOD_VISIBILITY]) && $this->classReflectionData[$className][self::DATA_CLASS_METHODS][$methodName][self::DATA_METHOD_VISIBILITY] === self::VISIBILITY_PROTECTED);
return ($this->classReflectionData[$className][self::DATA_CLASS_METHODS][$methodName][self::DATA_METHOD_VISIBILITY] ?? null) === self::VISIBILITY_PROTECTED;
}

/**
Expand All @@ -601,7 +594,7 @@ public function isMethodProtected(string $className, string $methodName): bool
public function isMethodPrivate(string $className, string $methodName): bool
{
$className = $this->prepareClassReflectionForUsage($className);
return (isset($this->classReflectionData[$className][self::DATA_CLASS_METHODS][$methodName][self::DATA_METHOD_VISIBILITY]) && $this->classReflectionData[$className][self::DATA_CLASS_METHODS][$methodName][self::DATA_METHOD_VISIBILITY] === self::VISIBILITY_PRIVATE);
return ($this->classReflectionData[$className][self::DATA_CLASS_METHODS][$methodName][self::DATA_METHOD_VISIBILITY] ?? null) === self::VISIBILITY_PRIVATE;
}

/**
Expand Down Expand Up @@ -723,7 +716,7 @@ public function getMethodAnnotation(string $className, string $methodName, strin
public function getClassPropertyNames(string $className): array
{
$className = $this->prepareClassReflectionForUsage($className);
return isset($this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES]) ? array_keys($this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES]) : [];
return array_keys($this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES] ?? []);
}

/**
Expand Down Expand Up @@ -808,12 +801,10 @@ public function getMethodDeclaredReturnType(string $className, string $methodNam
public function getPropertyNamesByTag(string $className, string $tag): array
{
$className = $this->prepareClassReflectionForUsage($className);
if (!isset($this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES])) {
return [];
}

$propertyNames = [];
foreach ($this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES] as $propertyName => $propertyData) {
$classProperties = $this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES] ?? [];
foreach ($classProperties as $propertyName => $propertyData) {
if (isset($propertyData[self::DATA_PROPERTY_TAGS_VALUES][$tag])) {
$propertyNames[$propertyName] = true;
}
Expand All @@ -836,10 +827,6 @@ public function getPropertyNamesByTag(string $className, string $tag): array
public function getPropertyTagsValues(string $className, string $propertyName): array
{
$className = $this->prepareClassReflectionForUsage($className);
if (!isset($this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName])) {
return [];
}

return $this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_TAGS_VALUES] ?? [];
}

Expand All @@ -859,10 +846,6 @@ public function getPropertyTagsValues(string $className, string $propertyName):
public function getPropertyTagValues(string $className, string $propertyName, string $tag): array
{
$className = $this->prepareClassReflectionForUsage($className);
if (!isset($this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName])) {
return [];
}

return $this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_TAGS_VALUES][$tag] ?? [];
}

Expand Down Expand Up @@ -894,8 +877,7 @@ public function getPropertyType(string $className, string $propertyName): ?strin
public function isPropertyPrivate(string $className, string $propertyName): bool
{
$className = $this->prepareClassReflectionForUsage($className);
return (isset($this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_VISIBILITY])
&& $this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_VISIBILITY] === self::VISIBILITY_PRIVATE);
return ($this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_VISIBILITY] ?? null) === self::VISIBILITY_PRIVATE;
}

/**
Expand Down Expand Up @@ -949,12 +931,10 @@ public function isPropertyAnnotatedWith(string $className, string $propertyName,
public function getPropertyNamesByAnnotation(string $className, string $annotationClassName): array
{
$className = $this->prepareClassReflectionForUsage($className);
if (!isset($this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES])) {
return [];
}

$propertyNames = [];
foreach ($this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES] as $propertyName => $propertyData) {
$classProperties = $this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES] ?? [];
foreach ($classProperties as $propertyName => $propertyData) {
if (isset($propertyData[self::DATA_PROPERTY_ANNOTATIONS][$annotationClassName])) {
$propertyNames[$propertyName] = true;
}
Expand Down Expand Up @@ -1073,11 +1053,8 @@ protected function prepareClassReflectionForUsage(string $className): string
*/
protected function reflectEmergedClasses(): void
{
$availableClassnames = [];
foreach ($this->availableClassNames as $classNamesInPackage) {
$availableClassnames[] = $classNamesInPackage;
}
$classNamesToReflect = array_merge([], ...$availableClassnames);
// flatten nested array structure to a list of classes
$classNamesToReflect = array_merge(...array_values($this->availableClassNames));
$reflectedClassNames = array_keys($this->classReflectionData);
sort($classNamesToReflect);
sort($reflectedClassNames);
Expand All @@ -1087,33 +1064,31 @@ protected function reflectEmergedClasses(): void
}

$this->log('Reflected class names did not match class names to reflect', LogLevel::DEBUG);
$count = 0;

$classNameFilterFunction = function ($className) use (&$count): bool {
$classNamesToBuildSchemaFor = [];
foreach ($newClassNames as $className) {
$this->loadOrReflectClassIfNecessary($className);
if (
!$this->isClassAnnotatedWith($className, Flow\Entity::class) &&
!$this->isClassAnnotatedWith($className, ORM\Entity::class) &&
!$this->isClassAnnotatedWith($className, ORM\Embeddable::class) &&
!$this->isClassAnnotatedWith($className, Flow\ValueObject::class)
) {
return false;
continue;
}

$scopeAnnotation = $this->getClassAnnotation($className, Flow\Scope::class);
if ($scopeAnnotation !== null && $scopeAnnotation->value !== 'prototype') {
throw new Exception(sprintf('Classes tagged as entity or value object must be of scope prototype, however, %s is declared as %s.', $className, $scopeAnnotation->value), 1264103349);
}

$count++;
return true;
$classNamesToBuildSchemaFor[] = $className;
};

$classNamesToBuildSchemaFor = array_filter($newClassNames, $classNameFilterFunction);
$this->buildClassSchemata($classNamesToBuildSchemaFor);

if ($count > 0) {
$this->log(sprintf('Reflected %s emerged classes.', $count), LogLevel::INFO, LogEnvironment::fromMethodName(__METHOD__));
if ($classNamesToBuildSchemaFor !== []) {
$this->log(sprintf('Reflected %s emerged classes.', count($classNamesToBuildSchemaFor)), LogLevel::INFO, LogEnvironment::fromMethodName(__METHOD__));
}
}

Expand Down Expand Up @@ -1822,8 +1797,7 @@ protected function convertParameterReflectionToArray(ParameterReflection $parame
*/
protected function forgetChangedClasses(): void
{
$classNames = array_keys($this->classReflectionData);
foreach ($classNames as $className) {
foreach ($this->classReflectionData as $className => $_) {
if (is_string($className) && !$this->reflectionDataRuntimeCache->has($this->produceCacheIdentifierFromClassName($className))) {
$this->forgetClass($className);
}
Expand Down Expand Up @@ -1868,12 +1842,12 @@ private function forgetClass(string $className): void
}

if (isset($this->classReflectionData[$className][self::DATA_CLASS_SUBCLASSES])) {
foreach (array_keys($this->classReflectionData[$className][self::DATA_CLASS_SUBCLASSES]) as $subClassName) {
foreach ($this->classReflectionData[$className][self::DATA_CLASS_SUBCLASSES] as $subClassName => $_) {
$this->forgetClass((string)$subClassName);
}
}

foreach (array_keys($this->annotatedClasses) as $annotationClassName) {
foreach ($this->annotatedClasses as $annotationClassName => $_) {
if (isset($this->annotatedClasses[$annotationClassName][$className])) {
unset($this->annotatedClasses[$annotationClassName][$className]);
}
Expand All @@ -1884,7 +1858,7 @@ private function forgetClass(string $className): void
unset($this->classSchemata[$className]);
}

foreach (array_keys($this->classesByMethodAnnotations) as $annotationClassName) {
foreach ($this->classesByMethodAnnotations as $annotationClassName => $_) {
unset($this->classesByMethodAnnotations[$annotationClassName][$className]);
}

Expand All @@ -1894,13 +1868,6 @@ private function forgetClass(string $className): void
/**
* Loads reflection data from the cache or reflects the class if needed.
*
* If the class is completely unknown, this method won't try to load or reflect
* it. If it is known and reflection data has been loaded already, it won't be
* loaded again.
*
* In Production context, with frozen caches, this method will load reflection
* data for the specified class from the runtime cache.
*
* @param class-string $className
* @throws ClassLoadingForReflectionFailedException
* @throws InvalidClassException
Expand Down Expand Up @@ -1931,32 +1898,22 @@ private function loadOrReflectClassIfNecessary(string $className): void
*/
public function saveToCache(): void
{
if (empty($this->updatedReflectionData)) {
if ($this->updatedReflectionData === []) {
return;
}

if (!$this->initialized) {
$this->initialize();
}

$this->updateCacheEntries();
}

/**
* Save reflection data to cache in Production context.
*
* @throws Exception
*/
private function updateCacheEntries(): void
{
$classNames = [];
foreach ($this->classReflectionData as $className => $reflectionData) {
if ($this->isClassReflected($className)) {
$classNames[$className] = true;
}
}

foreach (array_keys($this->updatedReflectionData) as $className) {
foreach ($this->updatedReflectionData as $className => $_) {
$reflectionData = $this->classReflectionData[$className];
$cacheIdentifier = $this->produceCacheIdentifierFromClassName($className);
$this->reflectionDataRuntimeCache->set($cacheIdentifier, $reflectionData);
Expand Down