laravel transaction called from other controllers - laravel

If I will have a function in my BaseController where there is a transaction like this
public static function add_lead_logs($lead_id, $module, $action)
{
DB::beginTransaction();
$lead_log = new LeadLogsModel();
$lead_log->lead_id = $lead_id;
$lead_log->create_by = Session::get('SESS_USER_ID');
$lead_log->module = $module;
$lead_log->action = $action;
if(!$lead_log->save())
{
DB::rollback();
return false;
}
else
{
DB::commit();
return true;
}
}
and then I am calling that function inside a controller, lets say I am updating something
DB::beginTransasction()
$lead = LeadModel::find(1);
$lead->status = '1';
if($lead->save())
{
if($this->add_lead_logs($id,$module,$action))
{
DB::commit();
}
}
else
{
DB::rollback();
}
How can I have just 1 transaction? I am not sure whether this will rollback successfully when there is an error.

Laravel supports nested transactions via a transaction counter. DB::beginTransasction() increments the counter, and DB::commit() and DB::rollback() decrement the counter.
The actual database commit/rollback actions only happen on the outermost transaction call. If you're going to manually call the DB::beginTransasction(), DB::commit(), and DB::rollback() methods, then you need to make sure you're always pairing them.
In the case of your current code, if $lead->save() returns true, but the $this->add_lead_logs() returns false, you're going to enter a codepath that does not call commit/rollback on your outermost transaction. You need to add a rollback in an else condition here.
if($lead->save()) {
if($this->add_lead_logs($id,$module,$action)) {
DB::commit();
} else {
// make sure to rollback if add_lead_logs failed
DB::rollback();
}
} else {
DB::rollback();
}
This will ensure that for all code paths, the transaction will always be committed or rolled back.

Related

Check Status Of All Orders In a Deal And Mark Deal as Completed

work_orders is hasMany() relationship.
foreach ($deal->work_orders as $work_order) {
if ($work_order->status != completed) {
return 0;
} else {
completeDeal($deal->id);
}
}
I want to check If All Of the Orders in a deal are completed then run a function to complete a deal. If any of work orders is not completed Then Just Do nothing and return back.
Issue with my current code is that If any of the work order is completed it marks deal complete.
But I want to check if all order are completed
You can do something link bellow
foreach ($deals as $key => $deal) {
$total_order_count = $deal->work_orders->count();
$completed_order_count = $deal->work_orders->where('status', 1)->count();
if ($total_order_count != $completed_order_count ) {
return 0;
} else {
completeDeal($deal->id);
}
}
Of Course you can optimize queries your self because for some reason my debugbar is not working.

How to refactor parameters in if-else condition coming from a request laravel?

I have this function in my controller that checks parameter requests and saves it into my table for tracking. However my if condition is quite too long because whenever a new request will be added I have to write individual if condition to each request.
Here is my code:
public function storeTracking(Request $request)
{
$traffic = new TrafficTracking();
if ($request->has('gclid')) { // check if request = gclid
$traffic->traffic_type = 'gclid';
$traffic->traffic_value = $request->gclid;
}
if ($request->has('token')) { // check if request = token
$traffic->traffic_type = 'token';
$traffic->traffic_value = $request->token;
}
if ($request->has('fbclid')) { // check if request = fbclid
$traffic->traffic_type = 'fbclid';
$traffic->traffic_value = $request->fbclid;
}
if ($request->has('cjevent')) { // check if request = cjevent
$traffic->traffic_type = 'cjevent';
$traffic->traffic_value = $request->cjevent;
}
$traffic->save();
return response()->json([
'message' => 'success'
], 200);
}
Is there any shorter approach for this one for the if condition? Because the code will be long whenever a new request is added in my storeTracking function in the controller.
you can try like this but you need to way to validate or in try catch you need to handle
this code can be like this
foreach ($request->except('_token') as $key => $value) {
$traffic = new TrafficTracking();
$traffic->traffic_type = $key;
$traffic->traffic_value = $value;
$traffic->save();
break; // if you want single time execution
}
NOTE i m not sure it is correct answer but it is an idea to solve this
Using Ternary Operators
(Condition) ? (Statement1) : (Statement2);
Condition: It is the expression to be evaluated which returns a boolean value.
Statement 1: it is the statement to be executed if the condition
results in a true state.
Statement 2: It is the statement to be executed if the condition
results in a false state.
Using switch case
switch (n) {
case label1:
code to be executed if n=label1;
break;
case label2:
code to be executed if n=label2;
break;
case label3:
code to be executed if n=label3;
break;
...
default:
code to be executed if n is different from all labels;
}

implement update in save

$ahorroga = Ahorroga::findOrFail($id);
$ahorroga->junta_id = $request->junta_id;
$ahorroga->socio_id = $request->socio_id;
$ahorroga->ahorro = $request->ahorro;
$ahorroga->estado = $request->estado;
if ($ahorroga->isDirty()) {
$ahorroga->save();
toast('Ahorro Garantia Editado', 'success');
return redirect('ahorroga');
}
toast('No se detectaron cambios', 'error');
return redirect('ahorroga');
I know I can use and save lines of code, But how to apply the isDirty
Ahorroga::findOrFail($id)->update($request->all());
If I get it correct, then if you want to detect whether you updated stuff updated the table or not then below is the solution.
The best solution for this is to use update(), it returns true or false and based on this you can do your further logic. For ex:
$ahorroga = Ahorroga::find($id);
$ahorroga->junta_id = $request->junta_id;
$ahorroga->socio_id = $request->socio_id;
$ahorroga->ahorro = $request->ahorro;
$ahorroga->estado = $request->estado;
$id_updated = $ahorroga->update();
if($id_updated ) {
//if ture
}else{
//false
}
public function update($id)
{
$ahorroga->fill($request->only([
'junta_id', 'socio_id', 'ahorro','estado',
]);
if(!$ahorroga->isDirty()) {
toast('No se detectaron cambios', 'error');
return back();
}
$ahorroga->save();
toast('Ahorro Garantia Editado', 'success');
return redirect()->route();
}
In place of using isDirty(), you can also use isClean()
if($ahorroga->isClean()) {
// some error handling here
}
isDirty means there was changes. isClean means there was no change.

Single transaction on multiple model function with CodeIgniter

I need to insert into 2 tables if anything goes wrong while inserting in any of the table I want to rollback commited queries.
I wrote queries inside controller
for example:
$this->db->trans_start();
$this->db->insert_batch('market_users_mapping', $marketData);
$this->db->insert_batch('maincategory_users_mapping', $maincategoryData);
$this->db->trans_complete();
if ($this->db->trans_status() === FALSE) {
throw error
}
This works perfectly. But I think it's not good practice to write queries inside controller. So I did this, called model function and I wrote those insert_batch queries in respective model function.
$this->db->trans_start();
$this->maincategory_model->function_name()
$this->market_model->function_name();
$this->db->trans_complete();
if ($this->db->trans_status() === FALSE) {
throw error
`enter code here`
}
but this didnt work as expected
You changed places of queries in those examples regarding names in case it matters. I think that you can't have tied transactions between different methods (your second example). But you can and should set your DB related code to model.
So make those queries in model:
// controller code
$this->db->trans_start();
$this->maincategory_model->first_function($maincategoryData);
$this->market_model->second_function($marketData);
$this->db->trans_complete();
if ($this->db->trans_status() === FALSE) {
throw error
`enter code here`
}
// Maincategory_model code
public function first_function($maincategoryData)
{
return $this->db->insert_batch('maincategory_users_mapping', $maincategoryData);
}
// Market_model code
public function second_function($marketData)
{
return $this->db->insert_batch('market_users_mapping', $marketData);
}
First shift your db related operation in module and then start transaction.
Sample code in module,
First module :
function insert_data_market_maincategory($marketData,$maincategoryData)
{
$status = TRUE;
$this->db->trans_start();
$this->db->insert_batch('market_users_mapping', $marketData);
$this->second_module_name->maincategoryData($maincategoryData)
$this->db->trans_complete();
if ($this->db->trans_status() === FALSE) {
$status = FALSE;
}
return $status;
}
second module :
function maincategoryData($data)
{
$this->db->insert_batch('table_name', $data);
}
and your controller call this function
sample code in controller,
function inser_user_data()
{
$result = $this->module_name->maincategoryData($marketData,$maincategoryData)
if($result == FALSE)
{
throw error
`enter code here`
}
else
{
//data inserted successfully
}
}
I am using CI 3 and I can use single transaction on multiple model in Controller.
I have tried to insert error data to test if rollback or not, the transaction is successfully rollback.
I did not use Tpojka's anwser but my model methods return true or false. Everything seems okay.

Query error handling in CodeIgniter

I am trying to execute a MySQL query using the CI active record library. If the query is malformed, then CI invokes an internal server error 500 and quits without processing the next steps.
I need to roll back all the other queries processed before that error statement, and the roll back is also not happening.. can you help please?
The code snippets is as below:
function dbInsertInformationToDB($data_array)
{
$returnID = "";
$uniqueDataArray = array();
// I prepare a array of values here
$uniqueTableList = filter_unique_tables($data_array[2]);
$this->db->trans_begin();
// inserting is done here
// when there is a query error in $this->db->insert().. it is not rolling back the previous query executed
foreach($uniqueTableList as $table_name)
{
$uniqueDataArray = filterDataArray($data_array,$table_name,2);
$this->db->insert($table_name,$uniqueDataArray);
if ($this->db->_error_message())
{
$error = "I am caught!!";
}
$returnID = $this->db->affected_rows();
}
if ($this->db->trans_status() === FALSE)
{
$this->db->trans_rollback();
}
else
{
$this->db->trans_commit();
}
return "ERROR";
}
Try a try catch block: http://php.net/manual/en/language.exceptions.php

Resources