Opinionated: How to safely insert multiple records to more than one table in Laravel

WBOY
Release: 2024-07-17 19:33:34
Original
789 people have browsed it

Opinionated: How to safely insert multiple records to more than one table in Laravel

There are many ways to kill a bird. Different people have their unique ways of doing things effectively, that was why I added OPINIONATED to the topic, this is my way of inserting multiple records to more than one table and running other services effectively.

For example, let's say you want to run a service that does these under-listed tasks in a registration controller:

  • Check if the new user/potential customer exists in the database.
  • Register A User (of course we must save this record in a table).
  • Log the event/activity in a table.
  • Log the new user email/phone number in a tokens_table for account verification.
  • Dispatch Email containing a token that will expire in 10 minutes.
  • Dispatch SMS containing a token that will expire in 10 minutes.

The main gist here is that we are running multiple services in a controller and they must all run successfully so we don't have a Partial Transaction issue.

A Partial Transaction can be described as a scenario where only some parts of a transaction are completed, leading to data inconsistency.

How do we make sure we guide against this?

We use the Database Transactions facade readily available to us in the Laravel framework.

To run a database transaction, we need to let the code executor know this is a database transaction.

DB::beginTransaction();
Copy after login

Then we create a try-catch block so we can catch errors easily and do the needful. The try block will be inserting into the database while the catch block will catch any errors encountered.

For the contents in the Try block, we will have

  1. A service to check if a user exists.
$checkIfUserExists = $userService->userExists($request->email, $request->phoneNumber);

if ($checkIfUserExists) return errorResponseHelper('fail', 'User exists!');
Copy after login
  1. A service to register a new user and log the activity.
 $userService->registerUser($request);

 LogActivity($request->email, $request->phoneNumber);
Copy after login
  1. Generate a token, log it in the tokens table, and dispatch an event that is being listened to by two listeners VerificationEmailListener **and **VerificationSMSListener.
 $generateToken = generateTokenHelper();

$userService->tokenLog($request->email, $generateToken[0]);

event(new VerificationTokenDispatch($request->email, $request->PhoneNumber, $generateToken[1]));
Copy after login

Then, the most important part of this TRY block is to commit these changes if all the services run successfully and return a successful response.

 DB::commit();

return successResponseHelper('success', "OTP has been sent to your mobile/email, kindly note that OTP validity is 10 minutes");
Copy after login

If all the services in this try block are successful, the database commit will save these transactions into the database.

Now Let's look at the Catch block part.

If a transaction/service fails in the TRY block, it will come to the catch block. So we will call the DB facade again to rollback every transaction that have been inserted into the database like so:

DB::rollBack();

return errorResponseHelper('fail', "Operation not successful, please retry");
Copy after login

The DB::rollBack() facade will unsave/rollaback every transaction that have been inserted into the database without issues in milliseconds.

This is how I guide against data inconsistency especially when I am running more than one database transaction in Laravel.

The full code block:

use Illuminate\Support\Facades\DB;


 DB::beginTransaction();

        try {
            $checkIfUserExists = $userService->userExists($request->email, $request->phoneNumber);

            if ($checkIfUserExists) return errorResponseHelper('fail', 'User exists!');

            $registerUser = $userService->registerUser($request);

            LogActivity($request->email, $request->phoneNumber);

            $generateToken = generateTokenHelper(); // returns an array, the first is encrypted the second is not

            $userService->tokenLog($request->email, $generateToken[0]);

            event(new VerificationTokenDispatch($request->email, $request->PhoneNumber, $generateToken[1])); // both SMS listeners and email listeners are listening to this event

            DB::commit();

            return successResponseHelper('success', "OTP has been sent to your mobile/email, kindly note that OTP validity is 10 minutes");
        } catch (\Throwable $th) {
            DB::rollBack();
            return errorResponseHelper('fail', "Operation not successful, please retry");
        }
Copy after login

If you have any questions, do not hesitate to drop it.

The above is the detailed content of Opinionated: How to safely insert multiple records to more than one table in Laravel. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!