Laravel DB::select is breaking a future transaction - php

I have the following code :
DB::select($sql, $params);
DB::beginTransaction();
try {
DB::commit();
} catch (Exception $e) {
DB::rollback();
return [
'code' => 500,
'error' => true,
'message' => 'There was a problem saving your transaction.'
];
}
Which is causing the following error:
message: "There is no active transaction"
exception "PDOException"
There should be more instructions in the try statement but to show that none of them have an affect they have been removed. It seems to be that select is for some reason opening a transaction and not closing it. (The select is running an SP that returns two result sets but I only want one hence the use of select.) Everything works well without the select statement, and the select statement on it's own doesn't cause any errors and returns what I need. However, if I put the select statement in the try statement it causes an exception.
Thanks.

Does something like this work?
DB::beginTransaction();
DB::select($sql, $params);
try {
// your code that could fail
}
catch (Exception $e)
{
DB::rollback();
return [
'code' => 500,
'error' => true,
'message' => 'There was a problem saving your transaction.'
];
}
DB::commit();
return [
'code' => 200,
'error' => false,
'message' => 'Successful transaction.'
];

Related

how to work with laravel transaction rollback

I am trying to execute some queries which are dependant on each other, so what I want is if any error occurs then rollback all the queries inside transaction. what I've tried so far is
DB::transaction(function () use($user,$token,$request) {
$billing = User_billings::create([
'users_id' => $user->id,
'agent_id' => null,
'purpose' => 'Some Purpose',
'agent_token_id'=>$token->id,
'amount' => $request->amount,
'payment_method' => 'Agent Token',
'status' => 1
]);
if($billing){
$user_jorunal = User_journal::create([
'bill2_id' => $billing->id, //Intentionally made this error to test transaction, this should be 'bill_id'
'u_id' => $user->id,
'purpose' => 'Topup via Agent Token',
'debit' => $billing->amount,
'invoice_number' => time()
]);
if($user_jorunal){
if($this->agentTokenBalance($request->token_id) == 0){
$token->status=1;
$token->update();
}
return response()->json(['status'=>true,'message'=>'TopUp was Successful!']);
}
}
});
so when I execute this query It generates an error as SQLSTATE[HY000]: General error: 1364 Field 'bill_id' doesn't have a default value, but it also creates a row on user_billings table.
Can you please specify where I am wrong?
all of the above code is running fine, be sure that there is no logical error in query except the intentional one .
I am using laravel 5.7 in this project
PHP version is 7.2.19
following laravel documentation
Manually Using Transactions
use DB::beginTransaction(); to start transaction.
use DB::rollBack(); after each error.
use DB::commit(); when transaction confirmed. ;
laravel reference
Create a $status variable that will make sure that everything has been creeted in db. If any error occur, all db action will be rolled back.
Below, i have adapted your code with that logic.
$status = true;
try
{
DB::beginTransaction();
$billing = User_billings::create([
'users_id' => $user->id,
'agent_id' => null,
'purpose' => 'Some Purpose',
'agent_token_id' => $token->id,
'amount' => $request->amount,
'payment_method' => 'Agent Token',
'status' => 1,
]);
$user_jorunal = User_journal::create([
'bill2_id' => $billing->id, //Intentionally made this error to test transaction, this should be 'bill_id'
'u_id' => $user->id,
'purpose' => 'Topup via Agent Token',
'debit' => $billing->amount,
'invoice_number' => time(),
]);
$status = $status && $billing && $user_jorunal;
} catch (\Exception $e)
{
DB::rollBack();
//throw $e; //sometime you want to rollback AND throw the exception
}
//if previous DB action are OK
if ($status)
{
DB::commit();
if ($this->agentTokenBalance($request->token_id) == 0)
{
$token->status = 1;
$token->update();
}
return response()->json(['status' => true, 'message' => 'TopUp was Successful!']);
} else
{
DB::rollBack();
//return somme errors
}
Please note that MyIsam engine doesn't support transaction as explained here MyIsam engine transaction support.
Haven't used the DB::transaction with a callback method... but you can do the following
DB::beginTransaction();
$billing = new User_billings;
$billing->users_id = $user->id;
// rest of the assignments
$billing->save();
// Rest of your code... Inserts, Deletes, Updates...
DB::commit();
You don't need to implement the DB::rollBack() in this case, if anything fails between those two lines, the transaction won't commit.

Laravel API Validation errors to be displayed

I am valdating the fields sent through api and need to display the errors.
I tried using try and catch no errors thrown. I have already have a code validating the login
try {
$request->validate([
'email' => 'required|string|email',
'password' => 'required|string',
'remember_me' => 'boolean',
]);
} catch (Exception $e) {
return response()->json(['error' => $e->getMessage()], 500);
}
I found no errors return has json instead it is redirecting to the login page
How to handle rerros in API and sent the message as json?None of the example show the way to handle errors. I tried with everything
And also how to handle errors while creating the model
try {
$company = Company::create([
'first_name' => $data['first_name'],
'last_name' => $data['last_name'],
'email' => $data['email'],
'country_code' => $data['country_code']]);
} catch (Exception $e) {
return response()->json(['error' => $e->getMessage()], 500);
}
$request->validate() should automatically return a response to the browser with errors if it fails, it doesn't throw an exception.
If your request is json it should detect that and return the error in a json error response, you can catch this in your front-end javascript and interrogate the response to interpret the error message.
e.g. using axios:
this.$axios.post('your api url',{data})
.then(response=>{
// ALL Good
})
.error(error=>{
// Catch returned error and process as required
});
If as you say I found no errors return has json instead it is redirecting to the login page this probably means that Laravel thinks that the request is a standard request, in which case it will issue a response()->back()->withErrors() which is probably what's sending it back to your login.
Try checking the original request type and ensure it's json, it should have a header of Accept: application/json.
Alternatively you can define your own validator
https://laravel.com/docs/7.x/validation#manually-creating-validators, and process the validation on the server as you like.
If there is error into validation then it will automatilly handle by laravel. You don't need to catch exception for that. It doesn't through exception.
Look it sample function which I have used for store Region
public function createRegion(Request $request)
{
$data = $request->all();
// Create a new validator instance.
$request->validate([
'name' => 'required',
'details' => 'required'
]);
try {
$region = new Region();
$region->name = $data['name'];
$region->details = $data['details'];
$region->save();
$content = array(
'success' => true,
'data' => $region,
'message' => trans('messages.region_added')
);
return response($content)->setStatusCode(200);
} catch (\Exception $e) {
$content = array(
'success' => false,
'data' => 'something went wrong.',
'message' => 'There was an error while processing your request: ' .
$e->getMessage()
);
return response($content)->setStatusCode(500);
}
}

I cannot print the array that I am sending to the database - Laravel

I have the following function, but when I run it in Postman to see the result, it doesn't print any value to me, it doesn't even give me an error. The var_dump set if it detects them, but the array does not... I think there is something wrong in the method updateOrCreate , because when I print this variable with var_dump, I can't see anything in the console.
This is the function:
public function createBidRival(Request $request)
{
$response = array('code' => 400, 'error_msg' => []);
if (!$request->id_karatekas) array_push($response['error_msg'], 'id_karateka is required');
if (!$request->id_participant_bid_send ) array_push($response['error_msg'], 'id_participant_bid_send is required');
if (!$request->id_participant_bid_receive) array_push($response['error_msg'], ' id_participant_bid_receive is required');
if (!$request->bid_rival) array_push($response['error_msg'], 'bid rival is required');
if (!count($response['error_msg']) > 0) {
try {
var_dump($request->id_karatekas);
var_dump($request->id_participant_bid_send);
var_dump($request->id_participant_bid_receive);
var_dump($request->bid_rival);
$bidRival = new BidBetweenRivals();
$bidRival = BidBetweenRivals::updateOrCreate(
[
'id_participant_bid_send' => $request->id_participant_bid_send,
'id_participant_bid_receive' => $request->id_participant_bid_receive,
'id_karatekas' => $request->id_karatekas
],
[
'id_participant_bid_send' => $request->id_participant_bid_send,
'id_participant_bid_receive' => $request->id_participant_bid_receive,
'id_karatekas' => $request->id_karatekas,
'bid_rival' => $request->bid_rival
]
);
$bidBetweenRivals->save;
$response = array('code' => 200, 'bidBetweenRivals' => $bidRival, 'msg' => 'Bid created');
}catch(\Exception $exception) {
$response = array('code' => 500, 'error_msg' => $exception->getMessage());
}
}
}
Dump to see whether if (!count($response['error_msg']) > 0) true or not and also dump something in the catch block to see if exception is occurring or not.
You can also test by commenting out the updateOrCreate part to see if it is interfering.

DB Transaction Laravel not rolling back

I'm trying to use Laravel DB facade to rollback my database transactions if a certain condition is met. But my rollback is not working.
First I started my DB transaction with DB::beginTransaction();
Secondly, I wrote my queries to create the following :
Create a new payment batch
Create payment batch record
Create payment approval
Create payment approvers
Thirdly I then did some condition to know when to rollback or commit my DB transactions. But the rollback is not working. Example this block of condition was met in my code but never rollback
if(!$mail_status){
DB::rollBack();
return back()->with('error', 'Mail not send to approvers. Try again or contact system administrator.');
}
Below is the full block of code.
//Start transaction
DB::beginTransaction();
try{
//Run Queries
//Create a new payment batch
$batch = Batch::create([
'uuid' => uniqid(),
'batch_name' => $batch_config->batch_name,
'service_code' => Auth::user()->service_code,
'created_by' => Auth::user()->name,
]);
//Create parameters for new payment batch record
foreach($batch_record_config as $data){
$record[] = [
'batch_id' => $batch->batch_id,
'payee_name' => $data['payee_name'],
'bank_id' => $data['bank_id'],
'bank_name' => $data['bank_name'],
'account_type' => $data['account_type'],
'account_number' => $data['account_number'],
'amount' => $data['amount'],
'description' => $data['description'],
'year' => date("Y"),
'month' => date("F", mktime(0, 0, 0, date("n"), 10)),
'uuid' => uniqid(),
'service_code' => Auth::user()->service_code,
'created_at' => now(),
'created_by' => Auth::user()->name,
];
}
$batch_record_status = DB::table('batch_record')->insert($record);
//Generate new payment approval
$payment_approval = PaymentApproval::create([
'uuid' => uniqid(),
'batch_id' => $batch->batch_id,
'service_code' => Auth::user()->service_code,
'created_by' => Auth::user()->name,
'deleted' => 0,
]);
//Generate payment approvers for the payment approval
$payment_approvers = [];
foreach($approval_users as $data){
$payment_approvers[] = [
'uuid' => uniqid(),
'payment_approval_id' => $payment_approval->id,
'approval_user_id' => $data->id,
'approval_level_id' => $data->approval_level_id,
'batch_id' => $batch->batch_id,
'approval_position_value' => $data->approval_level->approval_position,
'approval_level_name' => $data->approval_level->approval_level,
'user_id' => $data->user_id,
'batch_name' => $batch->batch_name,
'service_code' => Auth::user()->service_code,
'approved' => 0,
'deleted' => 0,
'created_at' => now(),
'created_by' => Auth::user()->name,
];
}
$payment_approvers_status = DB::table('payment_approvers')->insert($payment_approvers);
// If DB transcation is successful.
if($batch && $batch_record_status && $payment_approval && $payment_approvers_status){
//get the next approvers
$next_approvers = $this->next_approvals($payment_approval->id);
if($next_approvers){
//send mail to the next approvers
$mail_status = $this->send_approvers_mail($next_approvers,$batch);
if(!$mail_status){
DB::rollBack();
return back()->with('error', 'Mail not send to approvers. Try again or contact system administrator.');
}else{
DB::commit();
return back()->with('success', 'Batch has being initialized');
}
}else{
DB::rollBack();
return back()->with('error', 'Approvers not found. Try again or contact system administrator.');
}
}else{
DB::rollBack();
return back()->with('error', 'Something went wrong. Try again.');
}
}catch(\Exception $e){
DB::rollBack();
dd($e);
return back()->with('error', 'Something went wrong... Contact system administrator. Thanks.');
}
I had a look at your and as others have rightly pointed you need to commit the transactions. Which i can't see in your code. There are basically two ways of using transactions which i am aware of.
1.
\DB::beginTransaction();
try {
DB::table('users')->update(['votes' => 1]);
DB::table('posts')->delete();
} catch (\Exception $e) {
$count = 0;
\DB::rollBack();
\Log::info(self::LOG_PREFIX . 'Some Msg ', [$e->__toString()]);
}
\DB::commit();
2.
DB::transaction(function () {
DB::table('users')->update(['votes' => 1]);
DB::table('posts')->delete();
});
If you're using second method you won't have to do any commit, this will be rolled back automatically on failure.
I persume the error is in this line of yours
$next_approvers = $this->next_approvals($payment_approval->id);
I couldn't find *next_approvals8 property defined in your code, Plus you're using both Laravel ORM and Raw Statements (PaymentApproval::create & DB::table('batch_record')->insert($record);)
Try sticking to 1 and see if this works.
You didn't mention that either your DB get commit or throw some error?.Check what are you getting in mail function response. I thin you got success in mail because your else condition is not execute any case.

Multiple records are created for same order

I am using Database Transaction for a endpoint where staff can accept the order perform certain operation thereafter. I don't want same order to be assigned to different staff.I used Database transaction for that but the problem is multiple staff are assigned to same order when the staff accepts the order at same time.
The sample code is provided below:
try {
$message = [
"status_validation" => "Input status must have value assigned",
"unique" => "Order is assigned to other driver"
];
$this->validate($request, [
"restaurant_id" => 'required|integer|min:1',
"order_id" => 'required|integer|min:1|unique:driver_order,order_id',
"status" => 'required|status_validation'
], $message);
} catch (\Exception $ex) {
return response()->json([
"status" => "422",
"message" => $ex->response->original
], 422);
}
try {
DB::beginTransaction();
$assignOrderToDriver = $this->driverOrder->createDriverOrder($request);
DB:commit();
return response()->json([
"status" => "200",
"message" => "Order has been sucessfully assigned."
], 200);
}
catch (\Exception $ex) {
return response()->json([
"status" => "500",
"message" => $ex->getMessage()
], 500);
}
This issue is really creating problem in my project. Am I doing something wrong here?

Categories