CodeIgniter Forums
How should I use DB Transactions - Printable Version

+- CodeIgniter Forums (https://forum.codeigniter.com)
+-- Forum: Using CodeIgniter (https://forum.codeigniter.com/forumdisplay.php?fid=5)
+--- Forum: General Help (https://forum.codeigniter.com/forumdisplay.php?fid=24)
+--- Thread: How should I use DB Transactions (/showthread.php?tid=66070)



How should I use DB Transactions - wolfgang1983 - 09-01-2016

I would like to be able to use Codeigniter Database Transactions. But I am new to this and I am unsure if have set it correct to what I am after.

What I am after if there is a error while trying to insert data into my insert_userdata() model function then will roll back data from my insert_user() and also insert_userdata() model functions

I have use the Database Transactions on my controller but not sure if that is correct.

Would like some guidance on this thanks.

Controller


PHP Code:
<?php

class Add extends MX_Controller {

    private $error = array();

    public function __construct() {
        parent::__construct();
        $this->load->library('form_validation');
        $this->load->library('upload');
        $this->load->model('admin/user/add_user_model');
    }

    public function index() {
        $this->form_validation->set_rules('username''Username''trim|required');
        $this->form_validation->set_rules('firstname''Firstname''trim');
        $this->form_validation->set_rules('lastname''Lastname''trim');
        $this->form_validation->set_rules('email''Email''trim|valid_email');
        $this->form_validation->set_rules('password''Password''trim');
        $this->form_validation->set_rules('confirm_password''Confirm Password''trim|matches[password]');

        if (($this->form_validation->run()) && $this->upload())  {

            $upload_data $this->upload->data();

            $this->db->trans_start();

            $insert_user = array(
                'status' => $this->input->post('status'),
                'date_added' => date('Y-m-d')
            );

            $set_user_id $this->add_user_model->insert_user($insert_user);

            if ($this->checkinsertedtodb($set_user_id)) {

                $insert_userdata = array(
                    'user_id' => $set_user_id,
                    'username' => ($this->input->post('username')) ? $this->input->post('username') : '',
                    'password' => '',
                    'firstname' => ($this->input->post('firstname')) ? $this->input->post('firstname') : '',
                    'lastname' => ($this->input->post('lastname')) ? $this->input->post('lastname') : '',
                    'email' => ($this->input->post('email')) ? $this->input->post('email') : '',
                    'image' => ($upload_data['file_name']) ? $upload_data['file_name'] : ''
                );

                $userdata_inserted $this->add_user_model->insert_userdata($insert_userdata);

                if (($this->checkinsertedtodb($userdata_inserted)) && $this->db->trans_status()) {
                    
                    redirect
('admin/user/users');
                    
                    $this
->db->trans_complete();
                
                
} else {

                    $this->db->trans_rollback();

                }
            }
            
        
}

        if (isset($this->error['warning'])) {
            $data['error'] = $this->error['warning'];
        } else {
            $data['error'] = '';
        }

        $data['header'] = Modules::run('admin/common/header/index');
        $data['footer'] = Modules::run('admin/common/footer/index');

        $this->load->view('user/add_view'$data);

    }

    public function upload($field 'userfile') {
        $users_dir $this->input->post('username');
        $directory FCPATH 'uploads/users/' $users_dir;

        if (isset($_FILES[$field]) && $_FILES[$field]['size'] > 0) {

            if (is_dir($directory)) {
                $this->error['warning'] = 'This ' $directory ' is all ready created!';
            }

            if (mkdir($directory)) {

                $config['upload_path'] = $directory '/';
                $config['allowed_types'] = 'gif|jpg|png';
                $config['max_size'] = 3000;
                $config['max_width'] = 0;
                $config['max_height'] = 0;
                $config['overwrite'] = true;

                $this->upload->initialize($config);

                if (!$this->upload->do_upload($field)) {    
                    $this
->error['warning'] = $this->upload->display_errors();
                }

            }

            return !$this->error;
            
    
}

    public function checkinsertedtodb($inserted) {
        if (!$inserted) {
            $this->error['warning'] = 'Opps somthing has gone wrong could not insert data!';
        }

        return !$this->error;
    }



Model


PHP Code:
<?php

class Add_user_model extends CI_Model {

    public function insert_user($data) {
        $this->db->set($data);
        $this->db->insert($this->db->dbprefix 'user');
        return $this->db->insert_id();
    }

    public function insert_userdata($data) {
        $this->db->set($data);
        $this->db->insert($this->db->dbprefix 'user_data');
    }





RE: How should I use DB Transactions - InsiteFX - 09-01-2016

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

$this->db->query('AN SQL QUERY...');
$this->db->query('ANOTHER QUERY...');
$this->db->query('AND YET ANOTHER QUERY...');

if (
$this->db->trans_status() === FALSE)
{
 
       $this->db->trans_rollback();
}
else
{
 
       $this->db->trans_commit();




RE: How should I use DB Transactions - Shawn - 09-01-2016

(09-01-2016, 02:12 AM)wolfgang1983 Wrote: I would like to be able to use Codeigniter Database Transactions. But I am new to this and I am unsure if have set it correct to what I am after.

What I am after if there is a error while trying to insert data into my insert_userdata() model function then will roll back data from my insert_user() and also insert_userdata() model functions

I have use the Database Transactions on my controller but not sure if that is correct.

Would like some guidance on this thanks.

Controller


PHP Code:
<?php

class Add extends MX_Controller {

    private $error = array();

    public function __construct() {
        parent::__construct();
        $this->load->library('form_validation');
        $this->load->library('upload');
        $this->load->model('admin/user/add_user_model');
    }

    public function index() {
        $this->form_validation->set_rules('username''Username''trim|required');
        $this->form_validation->set_rules('firstname''Firstname''trim');
        $this->form_validation->set_rules('lastname''Lastname''trim');
        $this->form_validation->set_rules('email''Email''trim|valid_email');
        $this->form_validation->set_rules('password''Password''trim');
        $this->form_validation->set_rules('confirm_password''Confirm Password''trim|matches[password]');

        if (($this->form_validation->run()) && $this->upload())  {

            $upload_data $this->upload->data();

            $this->db->trans_start();

            $insert_user = array(
                'status' => $this->input->post('status'),
                'date_added' => date('Y-m-d')
            );

            $set_user_id $this->add_user_model->insert_user($insert_user);

            if ($this->checkinsertedtodb($set_user_id)) {

                $insert_userdata = array(
                    'user_id' => $set_user_id,
                    'username' => ($this->input->post('username')) ? $this->input->post('username') : '',
                    'password' => '',
                    'firstname' => ($this->input->post('firstname')) ? $this->input->post('firstname') : '',
                    'lastname' => ($this->input->post('lastname')) ? $this->input->post('lastname') : '',
                    'email' => ($this->input->post('email')) ? $this->input->post('email') : '',
                    'image' => ($upload_data['file_name']) ? $upload_data['file_name'] : ''
                );

                $userdata_inserted $this->add_user_model->insert_userdata($insert_userdata);

                if (($this->checkinsertedtodb($userdata_inserted)) && $this->db->trans_status()) {
                    
                    redirect
('admin/user/users');
                    
                    $this
->db->trans_complete();
                
                
} else {

                    $this->db->trans_rollback();

                }
            }
            
        
}

        if (isset($this->error['warning'])) {
            $data['error'] = $this->error['warning'];
        } else {
            $data['error'] = '';
        }

        $data['header'] = Modules::run('admin/common/header/index');
        $data['footer'] = Modules::run('admin/common/footer/index');

        $this->load->view('user/add_view'$data);

    }

    public function upload($field 'userfile') {
        $users_dir $this->input->post('username');
        $directory FCPATH 'uploads/users/' $users_dir;

        if (isset($_FILES[$field]) && $_FILES[$field]['size'] > 0) {

            if (is_dir($directory)) {
                $this->error['warning'] = 'This ' $directory ' is all ready created!';
            }

            if (mkdir($directory)) {

                $config['upload_path'] = $directory '/';
                $config['allowed_types'] = 'gif|jpg|png';
                $config['max_size'] = 3000;
                $config['max_width'] = 0;
                $config['max_height'] = 0;
                $config['overwrite'] = true;

                $this->upload->initialize($config);

                if (!$this->upload->do_upload($field)) {    
                    $this
->error['warning'] = $this->upload->display_errors();
                }

            }

            return !$this->error;
            
    
}

    public function checkinsertedtodb($inserted) {
        if (!$inserted) {
            $this->error['warning'] = 'Opps somthing has gone wrong could not insert data!';
        }

        return !$this->error;
    }



Model


PHP Code:
<?php

class Add_user_model extends CI_Model {

    public function insert_user($data) {
        $this->db->set($data);
        $this->db->insert($this->db->dbprefix 'user');
        return $this->db->insert_id();
    }

    public function insert_userdata($data) {
        $this->db->set($data);
        $this->db->insert($this->db->dbprefix 'user_data');
    }



I suggest that you use a try catch block around the method calls that you want to include in the transaction. That way you can roll back if any kind of error occurs. Also you should check the success of your database calls for success/failure inside the methods and raise an exception on failure.

PHP Code:
{
 
   try {
 
       $this->db->trans_start();
 
       $set_user_id $this->add_user_model->insert_user($insert_user);
 
       
       $userdata_inserted 
$this->add_user_model->insert_userdata($insert_userdata);

 
      $this->db->trans_commit();
 
    catch (Exception $e) {
 
       $this->db->trans_rollback();
 
       log_message('error'$e->getMessage();
 
   }
 
   $this->load->view('user/add_view'$data);
}

{
 
   /**
      * @throws Exception
      */
    public function insert_user($data) {
        // this one may fail too, so you could do the same as below
 
       $this->db->set($data);
        if (!$this->db->insert($this->db->dbprefix 'user')) {
 
           $error $this->db->error();
 
           throw new Exception('message ' $error['code'] . ' ' $error['message']);
 
       }
        return $this->db->insert_id();
    }




RE: How should I use DB Transactions - wolfgang1983 - 09-02-2016

I have now done it this way but if there is a error on my file upload section how to roll it back also.

PHP Code:
<?php

class Add_user_model extends CI_Model {

    public function 
insert_user($file_name = array()) {
        
$this->db->trans_begin();

        
$user = array(
            
'status' => $this->input->post('status'),
            
'date_added' => date('Y-m-d')
        );

        
$this->db->set($user);
        
$this->db->insert($this->db->dbprefix 'user');

        
$user_id $this->db->insert_id();

        
$options = [
         
   'cost' => 12,
        ];

        
$hash password_hash($this->input->post('password'), PASSWORD_BCRYPT$options);

        
$userdata = array(
            
'user_id' => $user_id,
            
'username' => $this->input->post('username'),
            
'password' => $hash,
            
'firstname' => $this->input->post('firstname'),
            
'lastname' => $this->input->post('lastname'),
            
'email' => $this->input->post('email'),
            
'image' => ($file_name) ? $file_name '',
            
'country_code' => $this->input->post('country'),
            
'timezone' => $this->input->post('timezone')
        );

        
$this->db->set($userdata);
        
$this->db->insert($this->db->dbprefix 'user_data');

        if (
$this->db->trans_status() === FALSE) {
         
   
            $this
->db->trans_rollback();

        } else {

         
   $this->db->trans_commit();
        } 
    }


Controller

PHP Code:
<?php

class Add extends MY_Controller {

    private 
$error = array();

    public function 
__construct() {
        
parent::__construct();
        
$this->load->library('form_validation');
        
$this->load->library('countries');
        
$this->load->library('upload');
        
$this->load->model('admin/user/add_user_model');
    }

    public function 
index() {
        
$data['timezones'] = DateTimeZone::listIdentifiers(DateTimeZone::ALL);

        
$this->form_validation->set_rules('username''Username''trim|required');
        
$this->form_validation->set_rules('firstname''Firstname''trim|required');
        
$this->form_validation->set_rules('lastname''Lastname''trim');
        
$this->form_validation->set_rules('email''Email''trim|valid_email');
        
$this->form_validation->set_rules('password''Password''trim');
        
$this->form_validation->set_rules('confirm_password''Confirm Password''trim|matches[password]');
        
$this->form_validation->set_rules('status''Status''trim|required|callback_status[status]');
        
$this->form_validation->set_rules('country''Country''trim|required|callback_country[country]');
        
$this->form_validation->set_rules('timezone''Time Zone''trim|required|callback_timezone[timezone]');

        
$this->form_validation->set_message('required''<b>{field}</b> must be set!');

        if (
$this->form_validation->run($this)) {

            if (isset(
$_FILES['userfile']) && $_FILES['userfile']['size'] > 0) {

                if (!
is_dir(FCPATH 'uploads/users/' $this->input->post('username') . '/')) {
                    
mkdir(FCPATH 'uploads/users/' $this->input->post('username') . '/');
                }
            
                
$config['upload_path'] = './uploads/users/' $this->input->post('username') . '/';
 
               $config['allowed_types'] = 'gif|jpg|png';
 
               $config['max_size'] = 3000;
 
               $config['max_width'] = 0;
 
               $config['max_height'] = 0;

 
               $this->upload->initialize($config);

 
               if (!$this->upload->do_upload('userfile')) {
 
                   $this->error['warning'] = $this->upload->display_errors();
 
               }

 
               $upload_data $this->upload->data();
            }

            
$this->add_user_model->insert_user($upload_data['file_name']);
        }

        if (
validation_errors() != false) {
            
$this->error['warning'] = validation_errors('<div class="alert alert-danger">''</div>');
        }

        if (isset(
$this->error['warning'])) {
            
$data['warning_error'] = $this->error['warning'];
        } else {
            
$data['warning_error'] = '';
        }

        
$data['countries'] = $this->countries->get();

        
$data['header'] = Modules::run('admin/common/header/index');
        
$data['footer'] = Modules::run('admin/common/footer/index');

        
$this->load->view('user/add_view'$data);
    }

    public function 
country($str) {
        if (
$str) {
            return 
true;
        } else {
            
$this->form_validation->set_message('country''<b>{field}</b> must be set!');
            return 
false;
        }
    }

    public function 
timezone($str) {
        if (
$str) {
            return 
true;
        } else {
            
$this->form_validation->set_message('timezone''<b>{field}</b> must be set!');
            return 
false;
        }
    }

    public function 
status($str) {
        if (
$str) {
            return 
true;
        } else {
            
$this->form_validation->set_message('status''<b>{field}</b> must be set!');
            return 
false;
        }
    }




RE: How should I use DB Transactions - Shawn - 09-02-2016

(09-02-2016, 12:54 AM)wolfgang1983 Wrote: I have now done it this way but if there is a error on my file upload section how to roll it back also.

PHP Code:
<?php

class Add_user_model extends CI_Model {

 public function 
insert_user($file_name = array()) {
 
$this->db->trans_begin();

 
$user = array(
 
'status' => $this->input->post('status'),
 
'date_added' => date('Y-m-d')
 );

 
$this->db->set($user);
 
$this->db->insert($this->db->dbprefix 'user');

 
$user_id $this->db->insert_id();

 
$options = [
 
   'cost' => 12,
 ];

 
$hash password_hash($this->input->post('password'), PASSWORD_BCRYPT$options);

 
$userdata = array(
 
'user_id' => $user_id,
 
'username' => $this->input->post('username'),
 
'password' => $hash,
 
'firstname' => $this->input->post('firstname'),
 
'lastname' => $this->input->post('lastname'),
 
'email' => $this->input->post('email'),
 
'image' => ($file_name) ? $file_name '',
 
'country_code' => $this->input->post('country'),
 
'timezone' => $this->input->post('timezone')
 );

 
$this->db->set($userdata);
 
$this->db->insert($this->db->dbprefix 'user_data');

 if (
$this->db->trans_status() === FALSE) {
 
   
    $this
->db->trans_rollback();

 } else {

 
   $this->db->trans_commit();
 } 
 }


Controller

PHP Code:
<?php

class Add extends MY_Controller {

 private 
$error = array();

 public function 
__construct() {
 
parent::__construct();
 
$this->load->library('form_validation');
 
$this->load->library('countries');
 
$this->load->library('upload');
 
$this->load->model('admin/user/add_user_model');
 }

 public function 
index() {
 
$data['timezones'] = DateTimeZone::listIdentifiers(DateTimeZone::ALL);

 
$this->form_validation->set_rules('username''Username''trim|required');
 
$this->form_validation->set_rules('firstname''Firstname''trim|required');
 
$this->form_validation->set_rules('lastname''Lastname''trim');
 
$this->form_validation->set_rules('email''Email''trim|valid_email');
 
$this->form_validation->set_rules('password''Password''trim');
 
$this->form_validation->set_rules('confirm_password''Confirm Password''trim|matches[password]');
 
$this->form_validation->set_rules('status''Status''trim|required|callback_status[status]');
 
$this->form_validation->set_rules('country''Country''trim|required|callback_country[country]');
 
$this->form_validation->set_rules('timezone''Time Zone''trim|required|callback_timezone[timezone]');

 
$this->form_validation->set_message('required''<b>{field}</b> must be set!');

 if (
$this->form_validation->run($this)) {

 if (isset(
$_FILES['userfile']) && $_FILES['userfile']['size'] > 0) {

 if (!
is_dir(FCPATH 'uploads/users/' $this->input->post('username') . '/')) {
 
mkdir(FCPATH 'uploads/users/' $this->input->post('username') . '/');
 }
 
 
$config['upload_path'] = './uploads/users/' $this->input->post('username') . '/';
 
               $config['allowed_types'] = 'gif|jpg|png';
 
               $config['max_size'] = 3000;
 
               $config['max_width'] = 0;
 
               $config['max_height'] = 0;

 
               $this->upload->initialize($config);

 
               if (!$this->upload->do_upload('userfile')) {
 
                $this->error['warning'] = $this->upload->display_errors();
 
               }

 
               $upload_data $this->upload->data();
 }

 
$this->add_user_model->insert_user($upload_data['file_name']);
 }

 if (
validation_errors() != false) {
 
$this->error['warning'] = validation_errors('<div class="alert alert-danger">''</div>');
 }

 if (isset(
$this->error['warning'])) {
 
$data['warning_error'] = $this->error['warning'];
 } else {
 
$data['warning_error'] = '';
 }

 
$data['countries'] = $this->countries->get();

 
$data['header'] = Modules::run('admin/common/header/index');
 
$data['footer'] = Modules::run('admin/common/footer/index');

 
$this->load->view('user/add_view'$data);
 }

 public function 
country($str) {
 if (
$str) {
 return 
true;
 } else {
 
$this->form_validation->set_message('country''<b>{field}</b> must be set!');
 return 
false;
 }
 }

 public function 
timezone($str) {
 if (
$str) {
 return 
true;
 } else {
 
$this->form_validation->set_message('timezone''<b>{field}</b> must be set!');
 return 
false;
 }
 }

 public function 
status($str) {
 if (
$str) {
 return 
true;
 } else {
 
$this->form_validation->set_message('status''<b>{field}</b> must be set!');
 return 
false;
 }
 }


If you include the file upload section inside the try catch block then any errors should go the catch portion where you roll back the transaction. I say should but you will want to test by making deliberate errors in the file uploads and in the database inserts.