CRUD icon indicating copy to clipboard operation
CRUD copied to clipboard

[Bug] Save relationship data using DB transaction

Open YosraHamza opened this issue 1 year ago • 3 comments

Bug report

What I did

I added a relationship field to my form, saved the form with its relation. One of the relations threw an error from the database (field cannot be null).

What I expected to happen

All the data will not be stored in the database. Main entity data and its relations.

What happened

The main entity data were saved without the relations

What I've already tried to fix it

The original function needs to use DB transactions in the store/update function

Is it a bug in the latest version of Backpack?

Yes

Backpack, Laravel, PHP, DB version

When I run php artisan backpack:version the output is:

backpack/basset: 1.2.2
backpack/crud: 6.3.0
backpack/generators: v4.0.2
backpack/logmanager: v5.0.1
backpack/pro: 2.0.18
backpack/settings: 3.1.0
backpack/theme-coreuiv2: 1.2.2
backpack/theme-tabler: 1.1.1

YosraHamza avatar Dec 09 '23 10:12 YosraHamza

Hey @YosraHamza

We need more info from you to reproduce the issue you're facing so that we can look for a possible solution.

See here for an example of a good issue with necessary details.

Thanks!

phpfour avatar Dec 09 '23 13:12 phpfour

Hello @phpfour

Here's an example of the issue:

$this->crud->field('title')->size(6);
$this->crud->field('branch')->type('text')->size(6);
$this->crud->field('items')->type('relationship')
        ->subfields([
            [
                'name' => 'name',
                'type' => 'text',
                'wrapper' => [ 'class' => 'form-group col-md-4' ],
            ],
            [
                'name' => 'amount',
                'type' => 'number',
                'wrapper' => [ 'class' => 'form-group col-md-4' ],
            ],
            [
                'name' => 'quantity',
                'type' => 'number',
                'wrapper' => [ 'class' => 'form-group col-md-4' ],
            ]
]);

Here, as an example. I have an order with 1-many items. If somehow, one of the items has an error and the database threw it (for example empty name, or long name that exceeded the column limits) and this error passed from the application validation. I found that the order was saved to the database along with the previous correct items.

Expected behavior: The order and the items will be saved together, or fail together. As now we have an incomplete order created on the system. And the creator will not notice it when he saw the error page.

This can be fixed if we wrap the create function with the database transaction operation in vendor/backpack/crud/src/app/Library/CrudPanel/Traits/Create.php

Current:

$item = $this->model->create($directInputs);
$this->createRelationsForItem($item, $relationInputs);

New:

DB::transaction(function () use ($directInputs, $relationInputs){
     $item = $this->model->create($directInputs);
     $this->createRelationsForItem($item, $relationInputs);
});

So we can keep the saved data always consistent.

Thanks in advance.

YosraHamza avatar Dec 09 '23 15:12 YosraHamza

Hey @YosraHamza thanks for the suggestion.

I think it makes sense, yes. 👍

Not 100% sure about all the implications (I mean, pitfall in other rdms like nosql,), so I talked with my colleges and we decided that we can push something like this, but it needs to be behind a feature flag.

I am polishing the PR with the changes and I will have it ready either today or tomorrow and we can review if something is missing.

Thanks again for the suggestion.

🙏

pxpm avatar Dec 11 '23 16:12 pxpm

This is already done a few versions ago. https://backpackforlaravel.com/docs/6.x/crud-how-to#enable-database-transactions-for-create-and-update-1

Thanks for the suggestion @YosraHamza

pxpm avatar Mar 29 '24 10:03 pxpm