Skip to content
Open
Show file tree
Hide file tree
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
4 changes: 4 additions & 0 deletions Neos.Flow/Classes/Aop/Builder/ProxyClassBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,10 @@ public function buildProxyClass(string $targetClassName, array $aspectContainers
$propertyName = $propertyIntroduction->getPropertyName();
$declaringAspectClassName = $propertyIntroduction->getDeclaringAspectClassName();
$possiblePropertyTypes = $this->reflectionService->getPropertyTagValues($declaringAspectClassName, $propertyName, 'var');
if (count($possiblePropertyTypes) === 0) {
$typeHint = $this->reflectionService->getPropertyType($declaringAspectClassName, $propertyName);
$possiblePropertyTypes = $typeHint !== null ? [$typeHint] : [];
}
if (count($possiblePropertyTypes) > 0 && !$this->reflectionService->isPropertyAnnotatedWith($declaringAspectClassName, $propertyName, Flow\Transient::class)) {
$classSchema = $this->reflectionService->getClassSchema($targetClassName);
$classSchema?->addProperty($propertyName, $possiblePropertyTypes[0]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,20 +339,8 @@ protected static function parseAutowiring($value)
protected function parsePropertyOfTypeObject($propertyName, $objectNameOrConfiguration, Configuration $parentObjectConfiguration)
{
if (is_array($objectNameOrConfiguration)) {
if (isset($objectNameOrConfiguration['name'])) {
$objectName = $objectNameOrConfiguration['name'];
unset($objectNameOrConfiguration['name']);
} else {
if (isset($objectNameOrConfiguration['factoryObjectName']) || isset($objectNameOrConfiguration['factoryMethodName'])) {
$objectName = null;
} else {
$annotations = $this->reflectionService->getPropertyTagValues($parentObjectConfiguration->getClassName(), $propertyName, 'var');
if (count($annotations) !== 1) {
throw new InvalidObjectConfigurationException(sprintf('Object %s (%s), for property "%s", contains neither object name, nor factory object name, and nor is the property properly @var - annotated.', $parentObjectConfiguration->getClassName(), $parentObjectConfiguration->getConfigurationSourceHint(), $propertyName), 1297097815);
}
$objectName = $annotations[0];
}
}
$objectName = $this->determineObjectNameOfProperty($objectNameOrConfiguration, $parentObjectConfiguration->getClassName(), $propertyName, $parentObjectConfiguration->getConfigurationSourceHint());
unset($objectNameOrConfiguration['name']);
$objectConfiguration = $this->parseConfigurationArray($objectName, $objectNameOrConfiguration, $parentObjectConfiguration->getConfigurationSourceHint() . ', property "' . $propertyName . '"');
$property = new ConfigurationProperty($propertyName, $objectConfiguration, ConfigurationProperty::PROPERTY_TYPES_OBJECT);
} else {
Expand All @@ -361,6 +349,42 @@ protected function parsePropertyOfTypeObject($propertyName, $objectNameOrConfigu
return $property;
}

/**
* @param $objectNameOrConfiguration
* @param $parentClassName
* @param $propertyName
* @param string $configurationSourceHint
* @return string
* @throws InvalidObjectConfigurationException
* @throws \Neos\Flow\Reflection\Exception\ClassLoadingForReflectionFailedException
* @throws \Neos\Flow\Reflection\Exception\InvalidClassException
* @throws \ReflectionException
*/
protected function determineObjectNameOfProperty($objectNameOrConfiguration, $parentClassName, $propertyName, string $configurationSourceHint): string
{
if (isset($objectNameOrConfiguration['name'])) {
return $objectNameOrConfiguration['name'];
}

if (isset($objectNameOrConfiguration['factoryObjectName']) || isset($objectNameOrConfiguration['factoryMethodName'])) {
return '';
}

$varTags = $this->reflectionService->getPropertyTagValues($parentClassName, $propertyName, 'var');
if (count($varTags) > 1) {
throw new InvalidObjectConfigurationException(sprintf('Object %s (%s), for property "%s", contains neither object name, nor factory object name, and nor is the property properly @var - annotated.', $parentClassName, $configurationSourceHint, $propertyName), 1297097815);
}
if (count($varTags) === 1) {
return $varTags[0];
}
$typeHint = $this->reflectionService->getPropertyType($parentClassName, $propertyName);
if ($typeHint === null) {
throw new InvalidObjectConfigurationException(sprintf('Object %s (%s), for property "%s", contains neither object name, nor factory object name, and neither is the property properly type hinted or @var - tagged.', $parentClassName, $configurationSourceHint, $propertyName), 1779793488);
}

return $typeHint;
}

/**
* Parses the configuration for arguments of type OBJECT
*
Expand Down Expand Up @@ -590,6 +614,7 @@ protected function autowireProperties(array &$objectConfigurations)
$enableLazyInjection = false; # See: https://github.com/neos/flow-development-collection/issues/2114
}
}
// This is already a fallback, getPropertyType is used first.
if ($objectName === null) {
$objectName = trim(implode('', $this->reflectionService->getPropertyTagValues($className, $propertyName, 'var')), ' \\');
}
Expand Down
7 changes: 6 additions & 1 deletion Neos.Flow/Classes/Property/TypeConverter/ObjectConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,13 @@ public function getTypeOfChildProperty($targetType, $propertyName, PropertyMappi
}
return $parsedType['type'] . ($parsedType['elementType'] !== null ? '<' . $parsedType['elementType'] . '>' : '');
}
$typeHint = $this->reflectionService->getPropertyType($targetType, $propertyName);
if ($typeHint !== null) {
$parsedType = TypeHandling::parseType($typeHint);
return $parsedType['type'];
}

throw new InvalidTargetException(sprintf('Public property "%s" had no proper type annotation (i.e. "@var") in target object of type "%s".', $propertyName, $targetType), 1406821818);
throw new InvalidTargetException(sprintf('Public property "%s" had no type hints or proper type tag (i.e. "@var") in target object of type "%s".', $propertyName, $targetType), 1406821818);
}
}

Expand Down
17 changes: 16 additions & 1 deletion Neos.Flow/Classes/Reflection/ReflectionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,22 @@ public function getPropertyTagsValues(string $className, string $propertyName):
public function getPropertyTagValues(string $className, string $propertyName, string $tag): array
{
$className = $this->prepareClassReflectionForUsage($className);
return $this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_TAGS_VALUES][$tag] ?? [];
$tagValues = $this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_TAGS_VALUES][$tag] ?? [];
if ($tag !== 'var') {
return $tagValues;
}

if ($tagValues !== []) {
return $tagValues;
}

// Upgrade behavior for "var" tag requests also considering the type hints as fallback.
$propertyType = $this->getPropertyType($className, $propertyName);
if ($propertyType !== null) {
return [$propertyType];
}

return [];
}

/**
Expand Down
20 changes: 7 additions & 13 deletions Neos.Flow/Classes/Validation/ValidatorResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -296,30 +296,24 @@ protected function buildBaseValidatorConjunction($indexKey, $targetClassName, ar
}
$conjunctionValidator->addValidator($objectValidator);
foreach ($this->reflectionService->getClassPropertyNames($targetClassName) as $classPropertyName) {
if ($this->reflectionService->isPropertyAnnotatedWith($targetClassName, $classPropertyName, Flow\IgnoreValidation::class)) {
continue;
}

$classPropertyTagsValues = $this->reflectionService->getPropertyTagsValues($targetClassName, $classPropertyName);
if (!isset($classPropertyTagsValues['var'])) {
try {
$propertyReflection = new PropertyReflection($targetClassName, $classPropertyName);
} catch (\ReflectionException $e) {
throw new \RuntimeException(sprintf('Failed reflecting property %s from class %s while building base a validator conjunction: %s', $classPropertyName, $targetClassName, $e->getMessage()), 1651570561);
}

if (!$propertyReflection->hasType()) {
$type = $this->reflectionService->getPropertyType($targetClassName, $classPropertyName);
if ($type === null) {
throw new \InvalidArgumentException(sprintf('Failed building base validator conjunction for property %s in class %s because there is no @var annotation and no type declaration.', $classPropertyName, $targetClassName), 1363778104);
}
/** @var \ReflectionNamedType $type */
$type = $propertyReflection->getType();
$classPropertyTagsValues['var'][] = $type->getName();
$classPropertyTagsValues['var'][] = $this->reflectionService->getPropertyType($targetClassName, $classPropertyName);
}
try {
$parsedType = TypeHandling::parseType(trim(implode('', $classPropertyTagsValues['var']), ' \\'));
} catch (InvalidTypeException $exception) {
throw new \InvalidArgumentException(sprintf(' @var annotation of ' . $exception->getMessage(), 'class "' . $targetClassName . '", property "' . $classPropertyName . '"'), 1315564744, $exception);
}

if ($this->reflectionService->isPropertyAnnotatedWith($targetClassName, $classPropertyName, Flow\IgnoreValidation::class)) {
continue;
}
if ($classSchema !== null
&& $classSchema->hasProperty($classPropertyName)
&& $classSchema->isPropertyTransient($classPropertyName)
Expand Down
Loading