I have read up on some stuff about transactions in Codeigniter. I have implemented them in my code and was wondering if someone could take a look and see if I am going in the right direction? So far I have not encountered any database issues but I want to make sure I have implemented transactions correctly.
In my code, I create the user details first and get the ID, then I insert that ID into the user accounts table.
Controller
if($this->form_validation->run()==false){
$this->index();
}else{
$password = md5($password);
$package = array(
'first_name'=>$first_name,
'last_name'=>$last_name,
'email'=>$email,
'client_id'=>$client_id,
'date_of_birth'=>$date_of_birth,
'phone_number'=>$phone_number,
'address'=>$address,
'country'=>$country,
'created_on'=>$this->get_date(),
'updated_on'=>$this->get_date()
);
if($this->AccountModel->user_account_exists($email)){
$this->session->set_flashdata('Error',"Account already exists");
redirect('/Register');
}else{
$this->db->trans_start();
$id = $this->AccountModel->create_person($package);
$error = $this->db->error();
$this->db->trans_complete();
$expiration_date = date('Y-m-d', strtotime($this->get_date() . "+1 month") );
if($this->db->trans_status()===false){
$this->index();
}else{
$account = array(
'username'=>$email,
'password'=>$password,
'user_type'=>'user',
'person_id'=>$id,
'is_active'=>true,
'created_on'=>$this->get_date(),
'updated_on'=>$this->get_date(),
'expires_on'=>$expiration_date,
'status'=>'active'
);
$this->db->trans_start();
$id = $this->AccountModel->create_user_account($account);
$error = $this->db->error();
$this->db->trans_complete();
if($this->db->trans_status()===false){
$this->index();
}else{
$this->session->set_flashdata('Success','Account has been created');
redirect('/Login');
}
}
}
if($error!=''){
$this->session->set_flashdata('Error',$error["message"]);
redirect('/Register');
}
}
Model
public function create_user_account($input){
$this->db->insert('user_accounts',$input);
return $this->db->insert_id();
}
public function create_person($input){
$this->db->insert('person',$input);
return $this->db->insert_id();
}
Hope someone can help me with this
The reason for transactions is to perform multiple db query operations and if any operations fail undo any that have already taken place.
You are only performing one operation within your transaction block so transactions are pointless. Other than that, you've got the idea.
In your case where you are only using db->insert() you can easily check the results and respond accordingly. db->insert() returns either true or false. If the return is false, get the error and set it into flashdata. Otherwise, go on with your work.
As #Topjka say, transactions should be in the model code.
Here's a sample model
class Some_model extends CI_Model
{
public function save_stuff($data)
{
//let's assume $data has values for two different tables
$newInfo = $data['newStuff'];
$updateInfo = $data['oldStuff'];
$this->db->trans_start();
$this->db->insert('other_table', $newInfo);
$this->db->update('one_table', $updateInfo);
$this->db->trans_complete();
if($this->db->trans_status() === FALSE)
{
$this->set_flash_error();
return FALSE;
}
return TRUE; //everything worked
}
public function set_flash_error()
{
$error = $this->db->error();
$this->session->set_flashdata('Error', $error["message"]);
}
}
Transactions are justified above because we do two db ops and if the either fails we don't want any changes to the db made.
Using the model/method in the controller
if($this->some_model->save_stuff($the_stuff) === FALSE)
{
redirect('/wherever');
}
//All OK, proceed
//do other controller things
Related
So i'm trying to run an query by using a transaction but it's not working somehow i did check all the posts but no fixes seems to be working ! whenever i remove the transaction the insert query works just fine.
Here's the controller :
public function addEmployee(){
$field = array(
'NomClient'=>$this->input->post('fullName'),
'TelClient'=>$this->input->post('tel'),
'WilayaClient'=>$this->input->post('wilaya'),
'CommuneClient'=>$this->input->post('commune'),
'AdresseClient'=>$this->input->post('adresse'),
'StatusID'=>$this->input->post('statusCommande'),
'TelevendeuseID'=>$this->input->post('televendeuse')
);
$result= $this->m->addEmployee($field);
$msg['success'] = false;
$msg['type'] = 'add';
if($result){
$msg['success'] = true;
}
echo json_encode($msg);
}
My model :
public function addEmployee($field){
$this->db->trans_start();
return $this->db->insert('Clients',$field);
$this->db->trans_complete();
}
Please note that when i switch the model to :
public function addEmployee($field){
return $this->db->insert('Clients',$field);
}
The record gets inserted successfully ! Which means that something is wrong with the transaction. I'm currently using one query to test if it's working so i can use multiples onces after that. Note that the tables are InnoDB tables so the problem isn't with the table type. Please help me out !
When you call return it will end the function, so when it hits
return $this->db->insert('Clients',$field);
it will not get to
$this->db->trans_complete();
so perhaps...
$this->db->trans_start();
$return = $this->db->insert('Clients',$field);
$this->db->trans_complete();
return $return;
In my first table(ts_users) update opening user_opening_balance at the same time, I want to update that user_opening_balance in my second table(ts_voucher) column is voucher_amount. But in my second table table(ts_voucher) voucher_amount updates all columns amount.
My code:
public function updateConsignor($myData){
extract($myData);
$this->db->set('user_full_name' , $user_full_name);
$this->db->set('user_opening_balance' , $user_opening_balance);
$this->db->where('user_id', $user_id);
if($this->db->update('ts_users')){
$userId = $myData['user_id'];
$this->db->trans_begin();
$openingBalTrxn = array(
'voucher_amount' => $myData['user_opening_balance'],
);
$this->db->update('ts_voucher', $openingBalTrxn);
$this->db->where('voucher_person_account_id',$userId);
if ($this->db->trans_status() === false){
$this->db->trans_rollback();
return false;
}else{
$this->db->trans_commit();
return true;
}
return $query_result;
return true;
}else{
return false;
}
}
I am giving where condition
$this->db->update('ts_voucher', $openingBalTrxn);
$this->db->where('voucher_person_account_id',$userId);
for update one record it updates all voucher_amount column record
you need to run first your .where before your .update. See documentation here
$this->db->where('voucher_person_account_id',$userId);
$this->db->update('ts_voucher', $openingBalTrxn);
Your update query false. where clause first and other condition where first than update function call just copy this function and fix your problem.
public function updateConsignor($myData){
extract($myData);
$this->db->set('user_full_name' , $user_full_name);
$this->db->set('user_opening_balance' , $user_opening_balance);
$this->db->where('user_id', $user_id);
if($this->db->update('ts_users')){
$userId = $myData['user_id'];
$this->db->trans_begin();
$openingBalTrxn = array(
'voucher_amount' => $myData['user_opening_balance'],
);
$this->db->where('voucher_person_account_id',$userId);
$this->db->update('ts_voucher', $openingBalTrxn);
if ($this->db->trans_status() === false){
$this->db->trans_rollback();
return false;
}else{
$this->db->trans_commit();
return true;
}
return $query_result;
return true;
}else{
return false;
}
Your update operation is working before the 'where' condition has a chance to work. That's why it's updating all records. Simply put the where condition first, then update.
I'm new to codeigniter and trying to get my mind around the query builder functionality. I currently have an update method where I pass user entered data to update a record in the db. I've noticed it seems to be successful no matter what kind of junk data I throw at it, and I'm wondering if there's a setting or something I need to change, or what.
As you can see below, in my model I'm bypassing the user entered value and putting in junk data and it is still successful. It just inserts 0000-00-00. DOB in the DB is a date datatype.
I always get a success result from this, and it updates the DB, so techically it was successful. I have controls in place to prevent junk data from ever being sent to the model, but it doesn't give me warm fuzzies knowing that it is behaving this way.
Controller:
$updateResult = $this->Patients_model->update_patient_profile($this->data['post_data']);
if($updateResult === true)
{
$this->data['patient_profile'] = $this->Patients_model->get_patient_profile($patientId);
$this->data['update_result'] = true;
$this->load->view('index', $this->data);
}
else
{
$this->data['update_result'] = false;
print_r($updateResult);
}
Model:
function update_patient_profile($data)
{
$patient_id = $data['patient_id'];
unset($data['patient_id']);
$data['dob'] = 'this is not even a date'; //will store 0000-00-00 in DB.
$this->db->where('patient_id', $patient_id);
$this->db->update($this->patientsTable, $data);
if($this->db->affected_rows()) {
return true;
}
else
{
return $this->db->error();
}
}
You can check with PHP and thorw an error for invalid date. try this:
function update_patient_profile($data)
{
$patient_id = $data['patient_id'];
unset($data['patient_id']);
$check_date = $data['dob'];
if(strtotime($check_date))
{
$data['dob'] = date("Y-m-d",strtotime($check_date)); // to confirm date is valid and equivalant to database format
}
else
{
throw new Exception("Invalid date", 1);
}
$data['dob'] = 'this is not even a date'; //will store 0000-00-00 in DB.
$this->db->where('patient_id', $patient_id);
$this->db->update($this->patientsTable, $data);
if($this->db->affected_rows()) {
return true;
}
else
{
return $this->db->error();
}
}
I am trying to test transaction management in codeigniter. Below method is a function in a model class. If update_user_company_id method returns false, wrapper method save_user_and_company also returns. In this case, because the method returns before it reaches to
$this->db->trans_complete();
call, changes made by save_company and delete_company_requests methods are rolled back. This is what I want.
But what I want to learn is that instead of calling
$this->db->rollback();
I directly return from method.
Is this approach safe?
Is there a possibility that I may encounter a lock or some other problem in the future?
function save_user_and_company($user, $company_request) {
$result[STATU] = ERROR;
$this->db->trans_start();
$company = $this->companies_dao->save_company($company_request->company_name, $user->id);
if (!$company) {
$result[MESSAGE] = COMPANY_SAVE_ERROR;
return $result;
}
$company_request_result = $this->company_requests_model->delete_company_requests($company_request->id);
if (!$company_request_result) {
$result[MESSAGE] = COMPANY_REQUEST_DELETE_ERROR;
return $result;
}
$user_update = $this->users_dao->update_user_company_id($user->id, $company->id);
if (!$user_update) {
$result[MESSAGE] = USER_UPDATE_ERROR;
return $result;
}
$this->db->trans_complete();
$result[STATU] = SUCCESS;
$result[MESSAGE] = SUCCESSFUL;
return $result;
}
Thanks in advance!
Did you try like this....
Following code returns TRUE if transaction completes successfully.Otherwise it rollback your transaction and returns FALSE.Hope it will help you a lot..
function save_user_and_company($user, $company_request) {
$this->db->trans_begin(); //Begins your transaction
//Performs the transaction operations
$company = $this->companies_dao->save_company($company_request->company_name, $user->id);
$company_request_result = $this->company_requests_model->delete_company_requests($company_request->id);
$user_update = $this->users_dao->update_user_company_id($user->id, $company->id);
//Check whether transaction fails
if ($this->db->trans_status() === FALSE)
{
$this->db->trans_rollback();
$status = FALSE;
}
else
{
$this->db->trans_commit();
$status = TRUE;
}
return $status;
}
In Ci, I've got the following function. How do I test that the query successfully inserted without error's?
public function postToWall() {
$entryData = $this->input->post('entryData');
$myChurchId = $this->session->userdata("myChurchId");
$this->db->query("INSERT IGNORE INTO wallPosts (entryData, entryCreationDateTime, wpChurchId)
VALUES('$entryData', NOW(), '$myChurchId')");
}
You can use $this->db->affected_rows() function of codeigniter.
See more information here
You can do something like this:
return ($this->db->affected_rows() != 1) ? false : true;
You can also do it using Transactions like this:
$this->db->trans_start();
$this->db->query("INSERT IGNORE INTO wallPosts (entryData, entryCreationDateTime, wpChurchId)
VALUES('$entryData', NOW(), '$myChurchId')");
$this->db->trans_complete();
if ($this->db->trans_status() === FALSE) {
return "Query Failed";
} else {
// do whatever you want to do on query success
}
Here's more info on Transactions in CodeIgniter!
if you are using bootstrap on codeigniter try flash message
or
simply redirect
$added = $this->your_modal->function_reference($data);
if ($added) {
$this->session->set_flashdata('success', 'Added successfully.');
redirect('home');
} else {
$this->session->set_flashdata('error', 'Something wrong.');
redirect('home');
ON CONTROLLER
I prefer use
echo $this->db->affected_rows();
in models file