4.1 KiB
Field Writability
By default, fields are read-only. You can allow a field to be written to in PATCH and POST requests using the writable and readonly methods.
You can optionally supply a closure to these methods which will receive the model instance, and should return a boolean value.
For example, the following schema will make an email attribute that is only writable by the self:
$type->attribute('email')
->writable(function ($model, Context $context) {
return $model->id === $context->getRequest()->getAttribute('userId');
});
Writable Once
You may want a field to only be writable when creating a new resource, but not when an existing resource is being updated. This can be achieved by calling the once method:
$type->hasOne('author')
->writable()->once();
Default Values
You can provide a default value to be used when creating a new resource if there is no value provided by the consumer. Pass a value or a closure to the default method:
$type->attribute('joinedAt')
->default(new DateTime);
$type->attribute('ipAddress')
->default(function (Context $context) {
return $context->getRequest()->getServerParams()['REMOTE_ADDR'] ?? null;
});
::: tip If you're using Eloquent, you could also define default attribute values to achieve a similar thing. However, the Request instance will not be available in this context. :::
Validation
You can ensure that data provided for a field is valid before the resource is saved. Provide a closure to the validate method, and call the first argument if validation fails:
$type->attribute('email')
->validate(function (callable $fail, $value, $model, Context $context) {
if (! filter_var($value, FILTER_VALIDATE_EMAIL)) {
$fail('Invalid email');
}
});
::: tip
You can easily use Laravel's Validation component for field validation with the rules helper function.
:::
This works for relationships, too. The related models will be retrieved via your adapter and passed into your validation function.
$type->hasMany('groups')
->validate(function (callable $fail, array $groups, $model, Context $context) {
foreach ($groups as $group) {
if ($group->id === 1) {
$fail('You cannot assign this group');
}
}
});
Transformers
Use the transform method on an attribute to mutate any incoming value before it is saved to the model.
$type->attribute('firstName')
->transform(function ($value, Context $context) {
return ucfirst($value);
});
::: tip If you're using Eloquent, you could also define attribute casts or mutators on your model to achieve a similar thing. :::
Setters
Use the set method to define custom mutation logic for your field, instead of just setting the value straight on the model property.
$type->attribute('firstName')
->set(function ($value, $model, Context $context) {
$model->first_name = ucfirst($value);
if ($model->first_name === 'Toby') {
$model->last_name = 'Zerner';
}
});
Savers
If your field corresponds to some other form of data storage rather than a simple property on your model, you can use the save method to provide a closure that will be run after your model has been successfully saved. If specified, the adapter will NOT be used to set the field on the model.
$type->attribute('locale')
->save(function ($value, $model, Context $context) {
$model->preferences()
->where('key', 'locale')
->update(['value' => $value]);
});
Events
saved
Run after a field has been successfully saved.
$type->attribute('email')
->saved(function ($value, $model, Context $context) {
event(new EmailWasChanged($model));
});