Fellow Neosians,
I think it’s time for a new RFC regarding the integration of value objects into Flow and Neos in particular. As a first step, I’d like to talk about type conversion because it’s at the heart of everything.
Motivation
I found Mathias’ workshop in Hamburg earlier this year rather inspiring. In the past months I have increased using value objects a lot and am extremely happy having them in my code base.
##Status quo
Type conversion currently relies on implementations of Neos\Flow\Property\TypeConverterInterface
which in convertFrom
returns either the target object, null or an error message if anything went wrong. These error messages then are used to populate validation results etc.
##Considerations
###Conversion
The most simple conversion is that of value objects with only one constructor parameter. This already works just fine. It gets more interesting though for value objects with multiple properties, which will require a new property mapping mode from e.g. array to value object.
###Validation
Value objects usually validate themselves upon construction. The way to go there is to throw something if the validation fails. The thing to throw would be a ValidationError / a ValidationException which then could be caught by the validation framework to populate the validation result
##Example
Consider the following alternatives for defining a form field in a form factory:
$emailElement = $registrationPage->createElement('email', 'Neos.Form:SingleLineText');
$emailElement->addValidator(new EmailAddressValidator());
$emailElement = $registrationPage->createElement('email', 'Neos.Form:SingleLineText');
$emailElement->setDataType(EmailAddress::class);
The latter implementation, which imho is much more desirable, currently works only partially until you add the following ScalarTypeToValueObjectConverter
:
public function convertFrom($source, $targetType, array $convertedChildProperties = [], PropertyMappingConfigurationInterface $configuration = null)
{
try {
return new $targetType($source);
} catch (\Exception $exception) {
return new Error($exception->getMessage(), $exception->getCode());
}
}
```
which I'd like to get rid of.
##Proposal
As a first step, let's
* Use validation exceptions everywhere instead of returning Errors on type conversion
* Introduce value objects where they can replace validators (EmailAddress etc)
* Deprecated all those validators and use value objects in there for now
I'm not sure wheter this is breaking. The validator deprecation/fallback should make the transition quite smooth, I don't know how much of our validation framework is public API though.
Target versions would be 4.3 or 5.0 respectively.