Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

timgavin's avatar

Exception handling: how would you do this?

Proper exception handling has always kind of escaped me, so I'm really trying to get a handle on it and do away with the if/else checks and use more try/catch.

Here's my scenario: I'm performing an INSERT into 3 tables. Insert 1 is a record of the user's transaction and is being called in a controller, INSERTs 2 and 3 are additional INSERTs into other models, inside of a DB transaction, being called from a model.

So it's basically like this

class SomeController extends Controller
{
    public function store()
    {
        try {
            $transaction = Transaction::create([
                'foo' => 'bar'
            ]);
            MyModel::doOtherStuff($transaction);
        } catch(\Exception $exception) {
            // show toast to user
        }
    }
}

class MyModel extends Model
{
    public static function doOtherStuff(Transaction $transaction)
    {
        try {
            DB::transaction(function () use ($transaction) {
                static::create([
                    'transaction_id' => $transaction->id,
                ]);
                MyModel3::create([
                    'transaction_id' => $transaction->id,
                ]);
            });
        } catch (\Throwable$e) {
            throw new \Exception('Some error message');
        }
    }
}

The problem with this approach is that if the DB::transaction fails in MyModel, the first record in the controller's store method is still created.

How would you handle this scenario? Would you do a DB::transaction in the controller's store() method and omit it in MyModel (#2)? Or would you use a transaction in both the controller and MyModel (#3)? Or some other way?

# 2

class SomeController extends Controller
{
    public function store()
    {
        try {
            DB::transaction(function () {
                $transaction = Transaction::create([
                    'foo' => 'bar'
                ]);
                MyModel::doOtherStuff($transaction);
            });
        } catch(\Exception $exception) {
            // show toast to user
        }
    }
}

class MyModel extends Model
{
    public static function doOtherStuff(Transaction $transaction)
    {
        try {
            static::create([
                'transaction_id' => $transaction->id,
            ]);
            MyModel3::create([
                'transaction_id' => $transaction->id,
            ]);
        } catch (\Throwable$e) {
            throw new \Exception('Some error message');
        }
    }
}

# 3

class SomeController extends Controller
{
    public function store()
    {
        try {
            DB::transaction(function () {
                $transaction = Transaction::create([
                    'foo' => 'bar'
                ]);
                MyModel::doOtherStuff($transaction);
            });
        } catch(\Exception $exception) {
            // show toast to user
        }
    }
}

class MyModel extends Model
{
    public static function doOtherStuff(Transaction $transaction)
    {
        try {
            DB::transaction(function () use ($transaction) {
                static::create([
                    'transaction_id' => $transaction->id,
                ]);
                MyModel3::create([
                    'transaction_id' => $transaction->id,
                ]);
            });
        } catch (\Throwable$e) {
            throw new \Exception('Some error message');
        }
    }
}
0 likes
1 reply
Sinnbeck's avatar
Sinnbeck
Best Answer
Level 102

I would move all if this logic to a specialized action that had the transaction inside it. You can then try catch in the controller if you want

https://freek.dev/1371-refactoring-to-actions

Quick example. Remember validation

class SomeController extends Controller
{
    public function store(StoreTransactionWithRelations $action, Request $request)
    {
        try {
            $action->execute($request->all());
        } catch(\Exception $exception) {
            // show toast to user
        }
    }
} 

Please or to participate in this conversation.