• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Struggling with transaction using multiple models

#1
I'm struggling with how to get transactions to work when saving with multiple models.  I am developing a Property Management application.  When a single tenant property is created, the data for the property as well as a default unit is saved to the database.  Here is my code:

PHP Code:
$property_model = new PropertyModel;
$unit_model = new UnitModel;

$property_model->transStart();

$property_save = $property_model->save($property);
$unit_save = $unit_model->save($unit);

$property_model->transComplete(); 

if(!$property_save || !$unit_save) {
   //Handle validation errors
} elseif($property_model->transStatus() !== TRUE) {             
   
//Handle failed transaction
} else {
   
//Success action


When I force $unit_model->save($unit) to fail, the $property-model->save($property) is still inserted into the database.  I know I am probably using transactions incorrectly with my models, but I am not experienced enough with CodeIgniter 4 to know what I am doing wrong.
Reply

#2
Your calling them wrong. To run your queries using transactions you will use the

PHP Code:
$this->db->transStart(); 

and

PHP Code:
$this->db->transComplete(); 

You do not call them using your model.
What did you Try? What did you Get? What did you Expect?

Joined CodeIgniter Community 2009.  ( Skype: insitfx )
Reply

#3
(10-09-2020, 12:05 PM)InsiteFX Wrote: Your calling them wrong. To run your queries using transactions you will use the

PHP Code:
$this->db->transStart(); 

and

PHP Code:
$this->db->transComplete(); 

You do not call them using your model.

I tried that originally when I reviewed the documentation, but when I do an Error Exception Undefined property: App\Controllers\Properties::$db occurs.  I am calling it from my controller.

Okay, I realized that I had not loaded the database connection in the BaseController.  I added this to the constructor:

PHP Code:
$this->db = \Config\Database::connect(); 

The Error Exception is now gone, however, the first record is still being inserted when I force the second query to fail.
Reply

#4
I just had a realization... the validation is failing before the insert even occurs. The second insert is never happening. I'm going to have to rethink this...
Reply

#5
Ok, let me know how you make out on this.
What did you Try? What did you Get? What did you Expect?

Joined CodeIgniter Community 2009.  ( Skype: insitfx )
Reply

#6
(10-09-2020, 10:07 PM)InsiteFX Wrote: Ok, let me know how you make out on this.

I like to perform most of my validation at the model level.  It saves a lot of duplicate code and in my opinion better protects the data going into the database.

Once I realized that the validation was failing before the database query executed, I had to figure out a way to validate the data for two different models before beginning the database transaction.  I also wanted to leave my rules in the model for the reasons I stating above.  I ended up merging the two validationRules arrays for each model and then perform validation at the controller level.  After the POST data passes validation in the controller, the database transaction executes.  This does mean that the data is validated multiple times, once in the controller and then once again by each model, but there is basically no code duplication and I don't think it requires that much extra overhead.  Hopefully this will help someone else struggling with the same quandary:

PHP Code:
if($this->request->getMethod() == 'post') {
    $property = $this->request->getPost(); //Save array of POST data

    //Instantiate database model
    $property_model = new PropertyModel;
    $unit_model = new UnitModel;

    //Merge model validation rules for controller level validation
    $ctrlr_validation_rules = array_merge($property_model->validationRules, $unit_model->validationRules);

    //Perform validation at the controller level before starting transaction
    if($this->validate($ctrlr_validation_rules)) {
        $this->db->transStart(); //Begin Transaction

        $property_model->insert($property);
        $property['property_id'] = $property_model->getInsertUniqID();
        $unit_model->insert($property);

        $this->db->transComplete(); //End Transaction

        if($this->db->transStatus() === TRUE) {
            $data['property']->fill($property);
            session()->setFlashdata('success', $data['property']->property_name . ' added successfully!');
            return redirect()->to('/properties/' . $property_model->getInsertUniqID());
        }
    }
    $data['errors'] = $this->validator->getErrors();

Reply


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2021 MyBB Group.