Let's work on validating the form.
Currently, we don't have any validation. If you don't fill out the Create Post form, you will receive an error from the database.
You could add required
in the HTML form, and it would work. But this value can be easily removed using the browser developer tool, or the user could send the request not directly from the browser.
It could also be a mobile application with an API or someone maliciously trying to launch the request. So, we need the backend validation.
There are a few ways how to add backend validation. First, each field must have a set of validation rules. These rules can be placed in the Controller itself or a separate Form Request class.
First, let's see how we can do it in the Controller.
Validation Rules in Controller
We must validate the Request, so we need to call the validate()
method and provide fields with rules in an array.
app/Http/Controllers/PostController.php:
class PostController extends Controller{ // ... public function store(Request $request) { $request->validate([ 'title' => ['required'], 'text' => ['required'], 'category_id' => ['required'], ]); Post::create([ 'title' => $request->input('title'), 'text' => $request->input('text'), 'category_id' => $request->input('category_id'), ]); return redirect()->route('posts.index'); } // ...}
Now, you will be redirected back to the form if you try to submit an empty form.
This is the default behavior: Laravel redirects back with error messages in the session if validation fails.
Showing Validation Messages
Let's show those validation errors. To show errors, we will use a snippet from the official documentation.
@if ($errors->any()) <div class="alert alert-danger"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div>@endif
The $errors
variable is passed automatically to the Views. In the View where we have form, for example, on the create page, we can add this snippet before the form.
resources/views/posts/create.blade.php:
// ...<div class="p-6 text-gray-900"> @if ($errors->any()) <div class="alert alert-danger"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <form method="POST" action="{{ route('posts.store') }}"> // ...
After posting an empty form, we can see validation error messages.
Here's the GitHub commit for this change.
Validation in Form Requests
Next, I would like to show you how to make your Controllers shorter. For that, Laravel has a concept of Form Request class. Form Requests can also be created using an artisan command.
php artisan make:request StorePostRequest
Then, we replace the Request type in the Controllers method. And move all the fields into the StorePostRequest
class rules()
method.
app/Http/Controllers/PostController.php:
use App\Http\Requests\StorePostRequest; class PostController extends Controller{ // ... public function store(Request $request) public function store(StorePostRequest $request) { $request->validate([ 'title' => ['required'], 'text' => ['required'], 'category_id' => ['required'], ]); Post::create([ 'title' => $request->input('title'), 'text' => $request->input('text'), 'category_id' => $request->input('category_id'), ]); return redirect()->route('posts.index'); } // ...}
Inside the Form Request class, we see this structure:
app/Http/Requests/StorePostRequest.php:
class StorePostRequest extends FormRequest{ public function authorize(): bool { return false; } public function rules(): array { return [ // ]; }}
The authorize()
method indicates whether the user is authorized to make the request. It can be set to true
but could contain more checks, such as the user's role.
app/Http/Requests/StorePostRequest.php:
use Illuminate\Foundation\Http\FormRequest; class StorePostRequest extends FormRequest{ public function authorize(): bool { return false; return true; } public function rules(): array { return [ 'title' => ['required'], 'text' => ['required'], 'category_id' => ['required'], ]; }}
Also, when using Form Request, the returned result is validated data as an array. This array can be used when creating or updating records using the Request's validated()
method.
app/Http/Controllers/PostController.php:
class PostController extends Controller{ // ... public function store(StorePostRequest $request) { $request->validate([ 'title' => ['required'], 'text' => ['required'], 'category_id' => ['required'], ]); Post::create([ 'title' => $request->input('title'), 'text' => $request->input('text'), 'category_id' => $request->input('category_id'), ]); Post::create($request->validated()); return redirect()->route('posts.index'); } // ...}
Now, the create form works the same way, but the Controller is much shorter. Validating data or creating the record is achieved with just two lines in the Controller.
Here's the GitHub commit for this change.
And... that's it for this practical Laravel course for beginners! Well done if you created a similar project while reading this!
In the next and final lesson, I will give advice on what to learn next.
Hello
Iam learning Laravel and your courses are great. But, our database and all the infrastructure around it, inclusing several websties already exist, so Laravel will need to play nicely alongside them.
We have a users table and a sessions table, but with slight differences in columns. Users log in using a "username & password", stored on the users table rather than using "email".
Iam a little bit stuck in howto adapt Laravel to auth using our table structure and Postgres Crypt method, and wondered if you had a course that covered tweaking it to work against our method?
Thankyou
Hi,
We don't have a specific course that would cover your exact needs - sorry.
As for how to change
email
tousername
- this is done in theapp/Http/Requests/Auth/LoginRequest.php
file - there's:That you can override.
Hope that helps a little bit!