Validate nested DTOs #282
-
Hey there! I'm working with a huge DTO with serveral layers of nested DTOs and many of them need individual validation that cannot be specified solely by attributes. For that, I use the static I want to keep the validation login contained within their respective DTOs to avoid code duplication. How would you go about this? What's the best practice for this case? Does this package maybe even natively support my use case and I've just overlooked it in its docs? Stripped down example of my use case: use Illuminate\Validation\ValidationException;
use Illuminate\Validation\Validator;
use Spatie\LaravelData\Data;
class ParentData extends Data
{
public ChildData $child;
public int $value;
public static function withValidator(Validator $validator): void
{
$validator->after(function (Validator $validator) {
$data = ParentData::from($validator->getData());
if ($data->value > 10) {
$validator->errors()->add(key: 'value', message: 'Value must not be greater than 10.');
}
});
}
}
class ChildData extends Data
{
public string $otherValue;
public static function withValidator(Validator $validator): void
{
$validator->after(function (Validator $validator) {
$data = ChildData::from($validator->getData());
if ($data->otherValue === 'not allowed') {
$validator->errors()->add(key: 'otherValue', message: 'Value must not be equal to "not allowed".');
}
});
}
}
try {
$data = ParentData::validateAndCreate([
'value' => 12,
'child' => [
'otherValue' => 'not allowed',
],
]);
} catch (ValidationException $exception) {
// only the "value" key has been validated
// "child.otherValue" is missing entirely.
} |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
Hi @derheyne maybe using the rules function could be the solution for the issue? Rules defined within the rules method will always overwrite automatically generated rules.
You can even add dependencies to be automatically injected:
...
Additionally, if you need to access the data payload, you can use $payload parameter: class SongData extends Data
{
public function __construct(
public string $title,
public string $artist,
) {
}
public static function rules(array $payload): array
{
return [
'title' => ['required'],
'artist' => Rule::requiredIf($payload['title'] !== 'Rick Astley'),
];
}
} |
Beta Was this translation helpful? Give feedback.
-
Hmm I don't think we can support your use case. This is a simple example with a single nested data object, but for example Adding this functionality to collections is whole new can of worms I don't think we want to open. You're always welcome to PR such a thing but it would create a lot of edge cases I think. Other solution is to implement custom rules and use these with attributes or the rules method. |
Beta Was this translation helpful? Give feedback.
Hmm I don't think we can support your use case. This is a simple example with a single nested data object, but for example
$data = ChildData::from($validator->getData());
will already not work since the data received will be the parent data and not the child data. We're currently working on better support for relative rules using the rules method.Adding this functionality to collections is whole new can of worms I don't think we want to open.
You're always welcome to PR such a thing but it would create a lot of edge cases I think. Other solution is to implement custom rules and use these with attributes or the rules method.