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

gollumeo-109650634's avatar

DB::transaction(), DB::commit() & DB::rollBack() issues

Hello there!

I'm trying to use DB transactions to ensure every step is done properly before saving everything in DB (in different tables). However, I do not understand at ALL why this is still commited, although I do pass in the catch part (even dumped it)... does anyone might have any clue about the issue I'm facing, please?

Here's the snippet: (disclaimer: I know it's messy, but that was for testing purposes only. I'll obviously refactor this and use the proper FormRequests right after I've figured out why this doesn't work

public function __invoke($tierId, Request $request)
    {
        $newEstateRules = [
            'type' => ['bail','required', Rule::enum(Type::class)],
            'usage' => ['bail','required', Rule::enum(Usage::class)],
            'start_lease' => ['bail','required', 'date', 'date_format:Y-m-d'],
            'end_lease' => ['bail','date', 'date_format:Y-m-d', 'nullable', 'after_or_equal:start_lease'],
            'street' => 'required',
            'number' => 'required',
            'box' => 'nullable',
            'zip_code' => 'required',
            'city' => 'required',
            'country' => 'required'
        ];

        $newRealEstateByExRules = [
            'bookyear' => ['required', 'integer'],
            'percentage_pro' => ['bail', 'required', 'numeric', 'digits_between:0,100'],
            'yearly_rent_account' => ['required', 'integer'],
            'rental_advantage' => ['nullable', 'numeric'],
            'rental_advantage_account' => ['nullable', 'integer'],
            'is_furnished' => 'boolean',
            'has_late_payment' => 'boolean',
            'late_payment' => ['nullable', 'numeric'],
            'rc' => ['required', 'numeric'],
        ];

        $rentalsRules = [
            'rentals.*.bookyear' => ['required', 'integer'],
            'rentals.*.date' => ['required', 'date', 'date_format:Y-m-d'],
            'rentals.*.amount' => ['required', 'numeric'],
            'rentals.*.real_estate_id' => ['required', 'integer'],
            'rentals.*.id' => ['nullable', 'integer'],
        ];

        DB::beginTransaction();

        try {
            $tier = Tier::findOrFail($tierId);

            $realEstateValidator = Validator::make($request->all(), $newEstateRules);
            $realEstateValidated = $realEstateValidator->validate();
            $realEstateValidated['tier_id'] = $tier->id;

//            dd($realEstateValidated);

            $realEstate = RealEstate::create($realEstateValidated);

            $realEstateByExValidator = Validator::make($request->all(), $newRealEstateByExRules);
            $realEstateByExValidated = $realEstateByExValidator->validate();
            $realEstateByExValidated['real_estate_id'] = $realEstate->id;

            RealEstateByEx::create($realEstateByExValidated);

            $rentalsValidator = Validator::make($request->all(), $rentalsRules);
            $rentalsValidated = $rentalsValidator->validate();

            RealEstateRental::upsert($rentalsValidated['rentals'], 'id');

            DB::commit();
            dump('commited');

            return response()->json(['message' => 'Les loyers ont été enregistrés avec succès'], 200, [], JSON_PRETTY_PRINT);

        } catch (Exception|ValidationException $e) {
            DB::rollBack();
            dump('rollbacked');
            throw new ApiException($e->getMessage(), 500);
        }
    }

In advance, thanks a lot!!

0 likes
6 replies
Snapey's avatar

You say you do hit the catch?

gollumeo-109650634's avatar

@Snapey Yes, I do reach it. I dumped some dumb things like "rollbacked" and could have the message, but the first part of my transaction still got persisted for some reason.

gollumeo-109650634's avatar

@Snapey As you can notice in the below code, I've just tried it, yet my real estate still gets saved although I'm getting proper ValidationExceptions

    public function __invoke($tierId, Request $request)
    {
        $newEstateRules = [
            'type' => ['bail', 'required', Rule::enum(Type::class)],
            'usage' => ['bail', 'required', Rule::enum(Usage::class)],
            'start_lease' => ['bail', 'required', 'date', 'date_format:Y-m-d'],
            'end_lease' => ['bail', 'date', 'date_format:Y-m-d', 'nullable', 'after_or_equal:start_lease'],
            'street' => 'required',
            'number' => 'required',
            'box' => 'nullable',
            'zip_code' => 'required',
            'city' => 'required',
            'country' => 'required'
        ];

        $newRealEstateByExRules = [
            'bookyear' => ['required', 'integer'],
            'percentage_pro' => ['bail', 'required', 'numeric', 'digits_between:0,100'],
            'yearly_rent_account' => ['required', 'integer'],
            'rental_advantage' => ['nullable', 'numeric'],
            'rental_advantage_account' => ['nullable', 'integer'],
            'is_furnished' => 'boolean',
            'has_late_payment' => 'boolean',
            'late_payment' => ['nullable', 'numeric'],
            'rc' => ['required', 'numeric'],
        ];

        $rentalsRules = [
            'rentals.*.bookyear' => ['required', 'integer'],
            'rentals.*.date' => ['required', 'date', 'date_format:Y-m-d'],
            'rentals.*.amount' => ['required', 'numeric'],
            'rentals.*.real_estate_id' => ['required', 'integer'],
            'rentals.*.id' => ['nullable', 'integer'],
        ];


        try {
            DB::beginTransaction();
            $tier = Tier::findOrFail($tierId);

            $realEstateValidator = Validator::make($request->all(), $newEstateRules);
            $realEstateValidated = $realEstateValidator->validate();
            $realEstateValidated['tier_id'] = $tier->id;

//            dd($realEstateValidated);

            $realEstate = RealEstate::create($realEstateValidated);

            $realEstateByExValidator = Validator::make($request->all(), $newRealEstateByExRules);
            $realEstateByExValidated = $realEstateByExValidator->validate();
            $realEstateByExValidated['real_estate_id'] = $realEstate->id;

            RealEstateByEx::create($realEstateByExValidated);

            $rentalsValidator = Validator::make($request->all(), $rentalsRules);
            $rentalsValidated = $rentalsValidator->validate();

            RealEstateRental::upsert($rentalsValidated['rentals'], 'id');

            DB::commit();

            return response()->json(['message' => 'Les loyers ont été enregistrés avec succès'], 200, [], JSON_PRETTY_PRINT);

        } catch (Exception|ValidationException $e) {
            DB::rollBack();
            throw new ApiException($e->getMessage(), 500);
        }
    }
gollumeo-109650634's avatar

@Snapey it did work, thanks!! I didn't catch that transactions were only rollbacking on SQL Exceptions, so thanks for this as well :D

Please or to participate in this conversation.