Learn how Laravel Data validates requests, arrays, and other data structures with automatic rule inference
Laravel Data allows you to create data objects from all sorts of data. One of the most common ways to create a data object is from a request, and the data from a request cannot always be trusted.That’s why it is possible to validate the data before creating the data object. You can validate requests but also arrays and other structures.The package will try to automatically infer validation rules from the data object, so you don’t have to write them yourself. For example, a ?string property will automatically have the nullable and string rules.
Validation is probably one of the coolest features of this package, but it is also the most complex one. We’ll try to make it as straightforward as possible to validate data, but in the end, the Laravel validator was not written to be used in this way. So there are some limitations and quirks you should be aware of.In a few cases it might be easier to just create a custom request class with validation rules and then call toArray on the request to create a data object than trying to validate the data with this package.
Validation will always happen BEFORE a data object is created. Once a data object is created, it is assumed that the data is valid.At the moment, there isn’t a way to validate data objects, so you should implement this logic yourself. We’re looking into ways to make this easier in the future.Validation runs automatically in the following cases:
When injecting a data object somewhere and the data object gets created from the request
When calling the from method on a data object with a request
On all other occasions, validation won’t run automatically. You can always validate the data manually by calling the validate method on a data object:
SongData::validate( ['title' => 'Never gonna give you up']); // ValidationException will be thrown because 'artist' is missing
When you also want to create the object after validation was successful you can use validateAndCreate:
SongData::validateAndCreate( ['title' => 'Never gonna give you up', 'artist' => 'Rick Astley']); // returns a SongData object
We’ve got a lot of documentation about validation and we suggest you read it all, but if you want to get a quick glance at the validation functionality, here’s a quick overview:
It is possible to add extra rules as attributes to properties of a data object:
use Spatie\LaravelData\Attributes\Validation\Max;class SongData extends Data{ public function __construct( public string $title, #[Max(20)] public string $artist, ) { }}
When you provide an artist with a length of more than 20 characters, the validation will fail.There’s a complete chapter dedicated to validation attributes.
Sometimes you want to add rules manually, this can be done as such:
class SongData extends Data{ public function __construct( public string $title, public string $artist, ) { } public static function rules(): array { return [ 'title' => ['required', 'string'], 'artist' => ['required', 'string'], ]; }}
We resolve a data object from the container, its properties will already be filled by the values of the request with matching key names.
If the request contains data that is not compatible with the data object, a validation exception will be thrown.
Just like with Laravel requests, it is possible to authorize an action for certain people only:
use Illuminate\Support\Facades\Auth;class SongData extends Data{ public function __construct( public string $title, public string $artist, ) { } public static function authorize(): bool { return Auth::user()->name === 'Ruben'; }}
If the method returns false, then an AuthorizationException is thrown.
Let’s say we want to create a data object like this from a request:
class AlbumData extends Data{ /** * @param array<SongData> $songs */ public function __construct( public string $title, public array $songs, ) { }}
Since the SongData has its own validation rules, the package will automatically apply them when resolving validation
rules for this object.In this case the validation rules for AlbumData would look like this:
When you’ve set some default values for a data object, the validation rules will only be generated if something else than the default is provided.For example, when we have this data object:
class SongData extends Data{ public function __construct( public string $title = 'Never Gonna Give You Up', public string $artist = 'Rick Astley', ) { }}
And we try to validate the following data:
SongData::validate( ['title' => 'Giving Up On Love']);
When mapping property names, the validation rules will be generated for the mapped property name:
use Spatie\LaravelData\Attributes\MapInputName;class SongData extends Data{ public function __construct( #[MapInputName('song_title')] public string $title, ) { }}
The validation rules for this class will be:
[ 'song_title' => ['required', 'string'],]
There’s one small catch when the validation fails; the error message will be for the original property name, not the mapped property name. This is a small quirk we hope to solve as soon as possible.
We suggest always providing a payload when generating validation rules. Because such a payload is used to determine which rules will be generated and which can be skipped.