Laravel Volt realtime live stats
Hey! So Livewire 3 and Volt are out. I’ve been playing around with them and they’re pretty cool. My favorite part? Definitely the long …
ReadIn Laravel, validating forms is key to maintaining the safety and accuracy of user data. The FormRequest component simplifies this by keeping the validation rules in a dedicated class, rather than in the controller. This also makes the code neater and allows for special functions related to the request, like fetching a model or changing a data type of a field.
To set up a FormRequest for our login page, execute:
1php artisan make:request LoginRequest
Next, update the generated class as follows:
1class LoginRequest extends FormRequest
2{
3 public function rules()
4 {
5 return [
6 'email' => 'required|string',
7 'password' => 'required|string',
8 ];
9 }
10}
To use it, just add it to the appropriate method in your controller:
1class LoginController extends Controller
2{
3 public function store(LoginRequest $request)
4 {
5 // Your code here
6 }
7}
It’s as straightforward as that!
Next, we’ll explore some of its additional features.
If you want to access all the keys and values set in the rules
method, there’s an easy way to do it.
Instead of individually retrieving them like this:
1Post::create([
2 'title' => $request->title,
3 'body' => $request->body,
4 'published_at' => $request->published_at,
5]);
You can simply use the validated()
method:
1Post::create($request->validated());
The FormRequest class allows for adjustments on-the-fly, helping maintain the cleanliness of other classes. Consider handling an array of tags:
In the rules:
1public function rules()
2{
3 return [
4 'title' => 'required|string',
5 'body' => 'required|string',
6 'published_at' => 'datetime',
7 ];
8}
Syncing tags with our post traditionally looks like this:
1public function store(StorePostRequest $request) {
2 $post = Post::create($request->only('title', 'body','published_at'));
3
4 if($request->has('tags')) {
5 $post->tags()->attach(explode(',', $request->tags));
6 }
7}
Notice how we split the tags to attach each one to the post? We can handle this directly within the FormRequest using the afterValidation
method:
1class StorePostRequest extends FormRequest
2{
3 public function rules(): array
4 {
5 return [
6 'title' => 'required|string',
7 'body' => 'required|string',
8 'published_at' => 'datetime',
9 ];
10 }
11
12 protected function passedValidation() {
13 $this->merge([
14 'tags' => $this->tags ? explode(',', $this->tags) : []
15 ]);
16 }
17}
With this adjustment, the tags will already be in an array format after validation. This simplifies the controller code:
1public function store(StorePostRequest $request) {
2 $post = Post::create($request->only('title', 'body','published_at'));
3
4 $post->tags()->attach($request->tags);
5}
Using the prepareForValidation
method, we can adjust our input just before the FormRequest begins its validation process. For our tags, we want to ensure they are integers.
First, let’s tweak the tags input:
1protected function prepareForValidation() {
2 $this->merge([
3 'tags' => $this->tags ? explode(',', $this->tags) : []
4 ]);
5}
Now, the updated FormRequest class should be:
1class StorePostRequest extends FormRequest
2{
3 public function rules(): array
4 {
5 return [
6 'title' => 'required|string',
7 'body' => 'required|string',
8 'published_at' => 'datetime',
9 'tags' => 'array',
10 'tags.*' => 'integer',
11 ];
12 }
13
14 protected function prepareForValidation() {
15 $this->merge([
16 'tags' => $this->tags ? explode(',', $this->tags) : []
17 ]);
18 }
19}
The controller, despite these changes, will still treat the tags as an array:
1public function store(StorePostRequest $request) {
2 $post = Post::create($request->only('title', 'body','published_at'));
3
4 $post->tags()->attach($request->tags);
5}
You can directly access the authenticated user from the request class:
1public function store(StorePostRequest $request) {
2 $post = $request->user()->posts()->create(
3 $request->only('title', 'body','published_at')
4 );
5}
This method retrieves the currently authenticated user, making it easier to associate new posts with the user.
When you use a FormRequest in the method signature, Laravel automatically handles the validation for you. That means you don’t need to manually call $request->validate()
in the controller. Let’s understand how this magic happens.
To dissect the validation component, a good starting point is to search for instances where the rules
method from our StorePostRequest
class is used.
You might be surprised to find that PHPStorm’s “find usages” feature doesn’t detect any use of this method directly in our custom FormRequest class. But, if you search within its parent class, FormRequest
, you’ll discover it’s utilized in the createDefaultValidator
method.
1protected function createDefaultValidator(ValidationFactory $factory)
2{
3 $rules = method_exists($this, 'rules') ? $this->container->call([$this, 'rules']) : [];
4
5 $validator = $factory->make(
6 $this->validationData(), $rules,
7 $this->messages(), $this->attributes()
8 )->stopOnFirstFailure($this->stopOnFirstFailure);
9
10 if ($this->isPrecognitive()) {
11 $validator->setRules(
12 $this->filterPrecognitiveRules($validator->getRulesWithoutPlaceholders())
13 );
14 }
15
16 return $validator;
17}
The FormRequest
class utilizes Laravel’s service container when invoking the rules method. This approach is beneficial as it allows for dependency injection directly into the rules method, meaning any service or class you need can be automatically resolved and injected.
Now Let’s see the usage of createDefaultValidator
1protected function getValidatorInstance()
2{
3 if ($this->validator) {
4 return $this->validator;
5 }
6
7 $factory = $this->container->make(ValidationFactory::class);
8
9 if (method_exists($this, 'validator')) {
10 $validator = $this->container->call([$this, 'validator'], compact('factory'));
11 } else {
12 $validator = $this->createDefaultValidator($factory);
13 }
14
15 if (method_exists($this, 'withValidator')) {
16 $this->withValidator($validator);
17 }
18
19 if (method_exists($this, 'after')) {
20 $validator->after($this->container->call(
21 $this->after(...),
22 ['validator' => $validator]
23 ));
24 }
25
26 $this->setValidator($validator);
27
28 return $this->validator;
29}
Laravel follows a series of steps when validating using the FormRequest. Initially, Laravel checks if your FormRequest has its own Validator class; if not, it uses the createDefaultValidator
. Then, Laravel examines if there are any after
hooks to run.
Continuing our exploration, we see that getValidatorInstance
is invoked.
Next, we have the ValidatesWhenResolvedTrait
. This trait is applied to all FormRequests and houses methods for validating input data when the FormRequest class is determined.
1public function validateResolved()
2{
3 $this->prepareForValidation();
4
5 if (! $this->passesAuthorization()) {
6 $this->failedAuthorization();
7 }
8
9 $instance = $this->getValidatorInstance();
10
11 if ($this->isPrecognitive()) {
12 $instance->after(Precognition::afterValidationHook($this));
13 }
14
15 if ($instance->fails()) {
16 $this->failedValidation($instance);
17 }
18
19 $this->passedValidation();
20}
Here, we encounter the prepareForValidation
and passedValidation
methods we discussed earlier.
Moving on, let’s dive into how the validateResolved()
method is used.
1namespace Illuminate\Foundation\Providers;
2
3class FormRequestServiceProvider extends ServiceProvider
4{
5 public function boot()
6 {
7 $this->app->afterResolving(ValidatesWhenResolved::class, function ($resolved) {
8 $resolved->validateResolved();
9 });
10
11 $this->app->resolving(FormRequest::class, function ($request, $app) {
12 $request = FormRequest::createFrom($app['request'], $request);
13
14 $request->setContainer($app)->setRedirector($app->make(Redirector::class));
15 });
16 }
17}
Indeed, in the FormRequestServiceProvider
, Laravel sets up an afterResolving
hook that triggers the ValidatesWhenResolved
trait to invoke the validateResolved
method, which effectively performs the validation.
And that’s the fundamental process of how FormRequest validation is executed when it’s incorporated into your controller’s method.
Happy Coding!
Hey! So Livewire 3 and Volt are out. I’ve been playing around with them and they’re pretty cool. My favorite part? Definitely the long …
ReadIn your Laravel projects, how do you go about setting up routes for a particular resource? Do you do it in the following manner? …
Read