this is part drölf of the never ending series: "Value object support".
We had introduced value object support natively to Neos 8.3 node properties via JsonSerializable and fromArray via neos/flow-development-collection#2762. It was required that the object implements JsonSerializable and contains one of the from* deserialisation methods.
Now over time support for these kind of objects also landed in the Neos Ui - but in an intermediate time the PropertyMapper was used to transform objects to an array ignoring JsonSerializable - see #4638.
So one might think everything is okay now? It was until Neos 9 :D
With Neos 9 we no longer use flow_json_array (obviously) and our node property serialisation was fully rewritten to be a combination of symphony serialiser and our own from flow copied serialisers.
That results in a quirky state as we use different encoding and decoding techniques mixed together.
In short: The Neos Ui - for the inspector - requires \JsonSerializable to be implemented, and uses fromArray , fromString via Flows DenormalizingObjectConverter to upcast new values send from the frontend. (Aligns to Neos 8.3 behaviour)
Now the new 9.0 cr uses Symfony's AbstractObjectNormalizer to get ahold of all object properties which it intends to map back to the constructor on decoding, but for decoding we use our own fromArray and fromString methods via our new ValueObjectArrayDenormalizer which are modelled like the DenormalizingObjectConverter and friends.
The problem is that these two approaches collapse when we intend to have a value object encapsulating a single value and json-serializable to that:
final readonly class SomeId implements \JsonSerializable
{
public function __construct(
public string $id
) {
}
public static function fromString(string $value): self
{
return new self(
id: $value
);
}
/** @return array<int|string,mixed> */
public function jsonSerialize(): mixed
{
return $this->id;
}
}
The Neos Ui will correctly use jsonSerialize while the CR reads the properties and fails to construct it as its an array.
Note i tested this when this SomeId object was nested in another object - if SomeId is used as value object directly it might even work.
Its hard to support both flavours at the same time, so i started to add a special normalizer for the content repository to use JsonSerializable.
I like to discuss and establish a unified standard for how we in Neos write value objects and how they are expected to be serialised and unserialised. The use of manual fromArray methods for example is not optional as there is no error handling usually implemented by the developer and thus type errors and array offset errors are to be expected. Also there is a lot of redundant code.
this is part drölf of the never ending series: "Value object support".
We had introduced value object support natively to Neos 8.3 node properties via
JsonSerializableandfromArrayvia neos/flow-development-collection#2762. It was required that the object implementsJsonSerializableand contains one of thefrom*deserialisation methods.Now over time support for these kind of objects also landed in the Neos Ui - but in an intermediate time the PropertyMapper was used to transform objects to an array ignoring
JsonSerializable- see #4638.So one might think everything is okay now? It was until Neos 9 :D
With Neos 9 we no longer use
flow_json_array(obviously) and our node property serialisation was fully rewritten to be a combination of symphony serialiser and our own from flow copied serialisers.That results in a quirky state as we use different encoding and decoding techniques mixed together.
In short: The Neos Ui - for the inspector - requires
\JsonSerializableto be implemented, and usesfromArray,fromStringvia FlowsDenormalizingObjectConverterto upcast new values send from the frontend. (Aligns to Neos 8.3 behaviour)Now the new 9.0 cr uses Symfony's
AbstractObjectNormalizerto get ahold of all object properties which it intends to map back to the constructor on decoding, but for decoding we use our ownfromArrayandfromStringmethods via our newValueObjectArrayDenormalizerwhich are modelled like theDenormalizingObjectConverterand friends.The problem is that these two approaches collapse when we intend to have a value object encapsulating a single value and json-serializable to that:
The Neos Ui will correctly use
jsonSerializewhile the CR reads the properties and fails to construct it as its an array.Note i tested this when this
SomeIdobject was nested in another object - ifSomeIdis used as value object directly it might even work.Its hard to support both flavours at the same time, so i started to add a special normalizer for the content repository to use
JsonSerializable.I like to discuss and establish a unified standard for how we in Neos write value objects and how they are expected to be serialised and unserialised. The use of manual
fromArraymethods for example is not optional as there is no error handling usually implemented by the developer and thus type errors and array offset errors are to be expected. Also there is a lot of redundant code.