skip to Main Content

Transaction does not rollback when exception occurs outside controller

The methods used inside the register function are implemented in a trait, and all side methods throw an exception in case of an error.
But unfortunately, when an exception is thrown inside one of the side methods outside controller (for example: findRefererIdFromRequest() or findRefererIdFromRequest() or collectDataFromRequest()), the database return operation does not happen And the new user that was created by the create method is still inside the database and cannot be rolled back

class RegisterController extends Controller
{
    use AuthenticationTrait;

    public function register(RegisterRequest $request)
    {

        DB::beginTransaction();

        try {

            # Collect data from request
            $dataCollect = $this->collectDataFromRequest($request);

            # Create a new user
            $this->createUser($dataCollect);

            # Find ReferrerID from the request by invitation code
            $referrerId = $this->findRefererIdFromRequest($request);

            # Put ReferrerId into the user profile
            $this->putReferrerId($referrerId);

            DB::commit();

            # Return success response
            return response()->json($this->registerSuccessResponse());
        } catch (Exception $ex) {
            DB::rollBack();
            return response()->json(['status' => false, 'message' => $ex->getMessage()], 422);
        }
    }
}
trait AuthenticationTrait
{

    protected function collectDataFromRequest($request)
    {
        try {
            return collect($request->only([
                'name', 'email', 'password', 'country_id', 'language_id'
            ]));
        } catch (Throwable $th) {
            throw new CustomException(__("The system is unable to collect input data."));
        }
    }



    protected function createUser($dataCollect)
    {
        try {

            # Generate hashed password
            $hashedPassword = bcrypt($dataCollect->get('password'));
            $dataCollect->put('password', $hashedPassword);

            # Create a new user
            $this->user = $this->userRepository->create($dataCollect->toArray());

        } catch (Exception $th) {
            throw new CustomException(__('Sorry! The system is unable to create a new user account.'));
        }
    }



    protected function findRefererIdFromRequest($request)
    {
        # I have intentionally thrown an exception
        throw new CustomException(__("The invitation code is invalid."));
    }



    protected function putReferrerId($referrerId)
    {
        # Update user profile and put referrerId into the user profile
        $this->user->update(['referrer_id' => $referrerId]);

    }

    // Other funtions ... 

   }

    

2

Answers


  1. Chosen as BEST ANSWER

    I found the answer to my question.

    After a deep look, I realized that the database engine was on the default value, MyISAM,which does not support transactions. 😉

    In order for the transactions to be controllable, you must set the database engine to InnoDB.

    Go to the database configuration file and change the database engine to InnoDB

    config/database.php

     'connections' => [
        'mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
    
            // 'engine' => "MyISAM",
            'engine' => "InnoDB",
    
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],
     ]
    

  2. first put your db transaction outside the try block, and as regards the exception handling in your trait function if invitation_code is true just return it. also is this method "getUserIdByInvitationCode" present in the trait?

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search