Description
Currently, the best you can do when defining an update #[Input(update: true)]
is to define regular properties without readonly
:
#[Input(default: true, update: true)]
class UpdateDTO
{
#[Field] public Layout $layout;
}
Then, if you try to
- mark the class/property as
readonly
, it fails trying to set it:Cannot initialize readonly property UpdateDTO::$layout from scope TheCodingMachine\\GraphQLite\\Utils\\PropertyAccessor
. This can be fixed by using reflection to set the value instead of setting it directly using$object->$field = $value;
- mark the property as private (in case you instead want to provide a getter for it), it fails again with a similar error
- lastly, use promoted properties (constructor hydration) - it fails again with
Parameter 'layout' is missing for class 'UpdateDTO' constructor. It should be mapped as required field.
.
Modern deserialization (Java - Moshi, GSON) libraries default to creating an instance without constructor and then hydrating the properties rather than calling the constructor, even if it exists. This makes sense because deserialization usually requires more complex logic than just create an instance, as is the case with #[Input(update: true)]
.
The reason I want to use promoted properties is because those inputs classes are used as value objects throughout the project, so it makes perfect sense for them to have a regular constructor. One more thing is unit testing - with a constructor I can do this:
$service->doSomething(new UpdateDTO(layout: Layout::BASIC))
So what would sound better to me is always using field-based hydration:
#[Input(default: true, update: true)]
readonly class UpdateDTO
{
public function __construct() {
#[Field] public Layout $layout,
}
}
If constructor hydration is deemed important (at the very least for compatibility with older code that could break), we can instead make it opt-in:
#[Input(default: true, update: true)]
class UpdateDTO
{
#[Hydrate]
public function __construct() {
#[Field] public Layout $layout,
}
}
Thoughts on using reflection to set the property? And the hydration?