In the previous article, we learned how to send information to the server and save tasks in a table. However, what if the user sends wrong information or leaves the tasks title field empty? I told you! In such cases, we will encounter the following page:
To solve this problem, we need to ensure that the requested data is correct before adding a new record. We can evaluate the information entered using Laravel’s validate property in the request
helper function.
Request Validation
To do this, let’s go back to the store function in the controller and define a set of rules to evaluate the entered information.
The first rule is to check if the Task title is required, so that the user cannot send an empty name.
public function store()
{
request()->validate([
'title' => 'required'
]);
$task = new Task();
$task->title = request('title');
$task->save();
return back();
}
Now, if we leave the title field empty and send a request, we will see that the previous error page is not displayed, and only the page is refreshed. However, if we want to display the error related to the user’s request and maintain the user interface of the program, we need to display the errors variable. The errors variable contains JSON data, and when our request is rejected during the evaluation stage, it will return the relevant error message for us.
To display the error message from the evaluation stage, we need to make some changes to the blade file related to our create task. By doing so, when we send a request with an empty field, we will see the following result:
Let’s add some additional rules, such as a character limit:
Or ensuring that the Task title is not repeated (although this is usually used for usernames or internal site addresses, here we are using it for educational purposes):
You can also consider other conditions for the entered information, the list of which can be found at the laravel official doc here.
Another thing you may have noticed is that when the user encounters an error in their request, the field gets cleared. To prevent this, there is a useful helper function called old that allows you to return the value previously entered by the user. Let’s add this to our form:
Now, Let’s add another attribute to our task model which is tasks description, which let users time more about a task but this attribute definitely isn’t required and we want to user add it as an optional data.
To do that first we need to add another mitigation to our project to add another column into task table!
Please remember this important tip when working on a project that is still in development and not yet released. It’s crucial to keep the migrations simple and avoid creating too many separate migration files. Having numerous migrations can make it difficult to track and understand the data model attributes. when it comes to adding changes to a live, production-ready application, it’s necessary to create a new migration. Since, it’s crucial to avoid accidentally resetting any existing data.
But here, only for learning purposes I add another migration:
php artisan make:migration add_description_to_tasks_table
As you see in following up and down function I just add one column into our tasks table:
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('tasks', function (Blueprint $table) {
$table->text('description')->after('title')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('tasks', function (Blueprint $table) {
$table->dropColumn('description');
});
}
As you noticed you can use after
method to specify the exact position where you want to add the column. Additionally, you can use the nullable
attribute to allow the column to contain null values. Although you can also set a default value by default
method for the column, but it recommended using nullable
as it’s more optimized for query speed. However, please note that there are cases, such as with boolean columns, where using nullable
may not be feasible or appropriate.
Now let’s run it and check the results:
Everything works fine but the description is not right after!
While Laravel provides convenient methods for working with databases, there are limitations with certain methods, especially when using SQLite. Unfortunately, SQLite does not support inserting a column at a specific position in a table. So, even if you use the after
method in Laravel, the column will not be placed immediately after the specified column as expected. This is a limitation of SQLite itself, and it's not something that can be directly addressed through Laravel methods.
Fortunately, this limitation only applies to SQLite databases. If you’re using PostgreSQL or MySQL, you won’t encounter this
To fix this, We can remove last migration and as just change tasks migration files. We can reset all tables with:
php artisan migrate:reset
But suppose that we have some data we won’t to reset them, so the solution here is rollback all migration files!
To rollback last migration you can use following command:
php artisan migrate:rollback
And to rollback certain amount of migrations:
php artisan migrate:rollback --step=<steps_count>
I just remove last migration file and do our changes in tasks migration file, you’ll see after running php artisan migrate
command our desired changes will be added!
I add some rule for description and as you can see in following pic everything works fine:
That was super simple? huh!
Now let’s add another field? what about due to date and time? To do that let’s add another time column called expired_at
which is also nullable
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('description')->nullable();
$table->timestamp('expired_at')->nullable();
$table->timestamps();
});
That’s it let’s migrate tasks table again:
php artisan migrate:rollback
php artisan migrate
Then We have to update store function as bellow:
public function store()
{
request()->validate([
'title' => 'required|min:3|max:120|unique:tasks,title',
'description' => 'nullable|min:3|max:255',
'expired_at' => 'nullable|date|after:now'
]);
$task = new Task();
$task->title = request('title');
$task->description = request('description');
$task->expired_at = new \DateTime(request('expired_at'));
$task->save();
return redirect("/");
}
There are a few important points to consider. Firstly, when you need to validate a date in Laravel, you can use the built-in date validation rules. Let’s review them below:
date
: This validation rule checks if a given input is a valid date:
'date_field' => 'required|date'
date_format
: This rule validates if the input matches a specific date format:
'date_field' => 'required|date_format:Y-m-d',
after:date
: This rule ensures that the input date is after a specified date:
'date_field' => 'required|date|after:2023–01–01', // or maybe tommorow
after_or_equal:date
: This rule validates if the input date is equal to or after a specified date:
'date_field' => 'required|date|after_or_equal:2023–01–01',
before:date
: This rule ensures that the input date is before a specified date:
'date_field' => 'required|date|before:2023–01–01',
before_or_equal:date
: This rule validates if the input date is equal to or before a specified date:
'date_field' => 'required|date|before_or_equal:2023–01–01',
By utilizing these date format validation rules, you can ensure that the input dates meet your specified criteria within your Laravel application.
The second point to note is casting expired_at data as the exact datetime PHP data type. Sometimes, Laravel doesn't automatically recognize the data type, even if we validate it. to resolve it we can use Datetime helper class. or casting inside the data model! How?!
When we created our Task
model, we actually created an Eloquent model, which is an amazing feature in Laravel. However, so far, we haven't made any modifications to it. By default, every Eloquent model we create is stored in the app/models
directory of our Laravel project (note that this location may vary in older versions). To cast the data in our model, we need to make some changes by adding a rule to the casts
variable, like this:
protected $casts = [
'expired_at' => 'datetime'
];
By this defining we don’t need to use Datetime
class anymore:
public function store()
{
request()->validate([
'title' => 'required|min:3|max:120|unique:tasks,title',
'description' => 'nullable|min:3|max:255',
'expired_at' => 'nullable|date|after:now'
]);
$task = new Task();
$task->title = request('title');
$task->description = request('description');
$task->expired_at = request('expired_at');
$task->save();
return redirect("/");
}
Please note that you don’t need to casting for the created_at
and updated_at
columns, as Laravel handles them by default. However, in general, it's considered a best practice to explicitly define all the data model's fields and cast them accordingly:
protected $casts = [
'title' => 'string',
'description' => 'string',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'expired_at' => 'datetime'
];
This approach ensures that you have a clear understanding of each model's attributes and their respective data types. Just keep in mind that in real-world projects, it can sometimes be challenging to determine all the fields of a data model by solely relying on migrations.
Here is the result:
Again every time you need to walk through project you can find out here!
That’ it! I hope you found this tutorial enjoyable!
Top comments (0)