Laravel is an amazing framework. You can build almost any powerful applications with it. I have personally built amazing applications using Laravel. But, I am quite embarrassed to admit that some of my early projects lacked both the form validation and the SQL transaction statements. Luckily, I understood my mistakes in time and quickly patched the controllers with new and improved updates. In this post, I would explore both form validation and SQL transaction and at the end of the tutorial, I would share the link to relevant source files in my Github Account.
Whenever a user submits some data from the blade file, it is always recommended that the input gets checked before storing into the database. Let us take an example.
Example 1: Say we have a table called item_cost. It has three columns named id, name and cost. The id column is the primary key and is auto-incremented by the system. The name column is always of varchar value of 30 characters and only alphabets and space is allowed. Finally, the cost column stores value as a non-negative integer only.
Step 1: Now, let us create a simple blade file to take the input. We won’t be doing any validation in the blade file for the sake of simplicity. Here is the HTML form.
<form action="{{route('itemcosts.store')}}" method="post">
@csrf
<div class="form-group">
<label for="fname">Name</label>
<input type="text" class="form-control" id="fname" name="fname" placeholder="Item Name">
</div>
<div class="form-group">
<label for="cost">Cost</label>
<input type="text" class="form-control" id="cost" name="cost" placeholder="Item Cost">
</div>
<button style="float:right;" type="submit" class="btn btn-primary">Submit</button>
</form>
Step 2: Write the validation part in inside the function store(Request $request) within the Controller
$validator = \Validator::make($request->all(), [
'cost'=>'required|Integer|min:0',
'fname'=>'required|regex:/^(?![\s.]+$)[a-zA-Z\s.]*$/',
]);
Step 3: Check if the validation was successful or send back necessary error message to the blade file
if ($validator->fails()) {
Log::error(__CLASS__."::".__FUNCTION__." Validation Failed");
return redirect()
->back()
->withErrors($validator)
->withInput();
}
Step 4: In order to view the error message copy paste this code inside the blade file
@if (session()->has('message') || session()->has('status'))
<div class="alert alert-success"><a href="#" class="close" data-dismiss="alert" aria-label="close">×</a>{{ session()->get('message') }}</div>
@endif
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div><br />
@endif
Step 5: Store the data in item_cost table
$item_cost = new item_cost([
'name' => $request->get('fname'),
'cost' => $request->get('cost'),
]);
$item_cost->save();
Till now, we have interacted with one table so risk of failure is low. Now let us take another example.
Example 2: Now let us consider everything from Example 1 and feed in some new conditions. Consider another table total_item_cost. This table has one row with one of its column i.e, total initialised to zero. The id of this row is 1. Every time an item is inserted into the item_cost table the total value from total_item_cost is retrieved and added with the new entry cost. Finally, this new total is updated into the total field of total_item_cost.
What if during this process somehow we fail to update either one of the two tables? If such a situation occurs the entire integrity of the system might be jeopardized. Therefore to be safe, its always a good practice to include SQL transaction whenever we need to interact with two or more tables.
A transaction is a logical unit of work that contains one or more SQL statements. A transaction is an atomic unit. The effects of all the SQL statements in a transaction can be either all committed (applied to the database) or all rolled back (undone from the database).
Source
Step 6 : To use SQL transaction in Laravel you need to first add this line on the top part of your controller
<?php
.
.
.
.
.
use DB; //For SQL Transaction
Note: The basic template of SQL transaction is quite simple and looks like this
DB::transaction(function () use ($request){
});
/*Values are passed in comma separated form like $request*/
But, in order to catch errors and show better error messages its better to put it within try-catch statements like shown below
try{
DB::transaction(function () use ($request){
});
}catch(\Exception $e){
return redirect()
->back()
->withErrors($e->getMessage());
}
Step 6: Let us now put our logic inside the store function
try{
DB::transaction(function () use ($request){
$item_cost = new item_cost([
'name' => $request->get('fname'),
'cost' => $request->get('cost'),
]);
$item_cost->save();
$total_item_cost = total_item_cost::find(1);
$total_item_cost->total = $total_item_cost->total + $request->get('cost');
$total_item_cost->save();
});
Log::info(__CLASS__."::".__FUNCTION__." Saved");
return redirect()->back()->with('message', 'New Entry Added!');
}catch(\Exception $e){
return redirect()
->back()
->withErrors($e->getMessage());
}
Finally, the store function will look like this
public function store(Request $request)
{
Log::debug(__CLASS__."::".__FUNCTION__." Called");
$validator = \Validator::make($request->all(), [
'cost'=>'required|Integer|min:0',
'fname'=>'required|regex:/^(?![\s.]+$)[a-zA-Z\s.]*$/',
]);
if ($validator->fails()) {
Log::error(__CLASS__."::".__FUNCTION__." Validation Failed");
return redirect()
->back()
->withErrors($validator)
->withInput();
}
try{
DB::transaction(function () use ($request){
$item_cost = new item_cost([
'name' => $request->get('fname'),
'cost' => $request->get('cost'),
]);
$item_cost->save();
$total_item_cost = total_item_cost::find(1);
$total_item_cost->total = $total_item_cost->total + $request->get('cost');
$total_item_cost->save();
});
Log::info(__CLASS__."::".__FUNCTION__." Saved");
return redirect()->back()->with('message', 'New Entry Added!');
}catch(\Exception $e){
return redirect()
->back()
->withErrors($e->getMessage());
}
}
Note: The error message is sent from catch and the code to send the error is given below
return redirect()
->back()
->withErrors($e->getMessage());
The source files used in this tutorial can be found below
With over 3 years of versatile experience in IT Specialist, Project Manager, CTO, and Coding Instructor roles, I bring a comprehensive skill set to my current position as a Senior IT Support Analyst at RBC Capital Markets. I am proficient in stakeholder management, envisioning, producing, and delivering well-tested software products, and optimizing business processes. My passion lies in two key areas: technical writing and cloud engineering.
My expertise in technical writing is evidenced by published works on esteemed platforms like Techflow360, FreeCodeCamp, and Elsevier. In the realm of cloud engineering, I am further bolstered by my Google Cloud Associate Cloud Engineer certification.
At She Thinks Code, I actively contribute to offering computer science education to women from Least Developed Countries, harnessing technology to empower individuals. I am eager to explore collaborations and initiatives that capitalize on my expertise in diverse technical environments, including leveraging my cloud engineering skills.
App Engine is a robust platform within Google Cloud that empowers developers to create and…
Django is an open-source web framework that helps developers to create and maintain high-quality, secure…
The problem of converting a string in a zigzag pattern is a classic problem in…
When Neeraj Chopra bagged India's only gold medal in Tokyo 2020 Olympics, the whole nation…
Htmx is short for high power tools for HTML. It simplifies tedious work for developers.…
What is Biomechanics? We know, mechanics is the branch of physics dealing with the motion…