Forms#
Waterhole allows you to easily add fields, validation, and persistence logic to forms throughout the application.
In Waterhole, a form is made up of an ordered list of fields. Each field is a Blade component with a render
method, but it may also have additional methods which allow it to specify validation logic, and run code upon form submission, before and after a model is saved.
Defining a Field#
To define a new field, extend the Waterhole\Forms\Field
class. The constructor will receive an instance of the model that is the subject of the form. A field is a Blade component, so you will need to define a render
method that returns the field's view. Feel free to use the <x-waterhole::field>
component to take care of the boilerplate:
namespace App\Fields;
use Waterhole\Forms\Field;
class FullNameField extends Field
{
public function __construct(public ?User $user)
{
}
public function render(): string
{
return <<<'blade'
<x-waterhole::field name="full_name" label="Full Name">
<input
type="text"
name="full_name"
value="{{ old('full_name', $user->full_name ?? '') }}"
class="input"
>
</x-waterhole::field>
blade;
}
}
Validation#
If your field's input will need to be validated, add a validating
method. This method receives an instance of the Validator, to which you can add validation rules:
use Illuminate\Validation\Validator;
public function validating(Validator $validator): void
{
$validator->addRules([
'full_name' => ['required', 'string', 'max:255'],
]);
}
If you need to specify custom validation logic, make sure you do so using the after
method on the validator, which will allow you to add additional error messages to the message collection:
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add(
'full_name', 'Something is wrong with the full name!'
);
}
});
Saving#
After the form has passed validation, the subject model will be saved. By implementing the saving
method, fields are able to run code before the model is saved in order to assign validated data to the model:
use Illuminate\Foundation\Http\FormRequest;
public function saving(FormRequest $request)
{
$this->user->full_name = $request->validated('full_name');
}
Likewise, by implementing the saved
method, fields can run code after the model has been saved:
public function saved(FormRequest $request)
{
logger("User {$this->user->id} was saved with a full name!");
}
Form Structure#
Adding a Field to a Form#
Most of the forms throughout Waterhole have a corresponding extender to which you can add fields. For example, to add a field to the registration form, we would use the RegistrationForm
extender:
use App\Fields\FullNameField;
use Waterhole\Extend;
Extend\RegistrationForm::add(FullNameField::class);
Adding a Field to a Form Section#
Some forms are more complex and group fields into distinct sections. One example is the form for editing channels, which divides fields into various collapsible sections.
Like their parent forms, most of the distinct form sections throughout Waterhole have a corresponding extender to which you can add fields. For example, to add a field to the "Details" section of the channel editing form, we would use the ChannelFormDetails
extender:
Extend\ChannelFormDetails::add(ChannelColorField::class);
Adding a Form Section#
You can add a new section to a form using the FormSection
component, which can be constructed with a title and an array of field component instances. In the following example, we add a new "Membership" section to the channel editing form. Note how the $channel
model is forwarded onto the field instances:
use Waterhole\Forms\FormSection;
use Waterhole\Models\Channel;
Extend\ChannelForm::add(
'membership',
fn(Channel $channel) => new FormSection('Membership', [
new MembershipEnabledField($channel),
new MembershipPriceField($channel),
])
);
No Results Found