Query error handling in CodeIgniter - 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

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;
}

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.

Why isn't my Where working as I think it should?

I'm trying to get some data from a database whose results can be more than one row.
I've the following code for that:
public System.Linq.IQueryable<Users> getUser2(string idUser)
{
try
{
using (Entities c = new Entities())
{
c.ContextOptions.LazyLoadingEnabled = false;
c.ContextOptions.ProxyCreationEnabled = false;
return c.Users.Include("Empresas").Where(x => x.Login == idUser && x.Empresas.Activa == true);
}
}
catch (Exception ex)
{
throw ex;
}
}
But it doesn't seem to get any result, it shows something like a badly formed Iqueryable, I mean if I expand its results view I can see a message that says "ObjectContext instance has been eliminated and cannot be used for operations that need a connection" If I try to access any Users element with the function ElementAt(index) I get an IndexOutOfBounds error as it looks like it has no data if watched on debug mode.
I've deduced that it's Where fault because this code Works fine in returning the first user it finds that fulfills the condition:
public Users getUser(string idUser)
{
try
{
using (Entities c = new Entities())
{
c.ContextOptions.LazyLoadingEnabled = false;
c.ContextOptions.ProxyCreationEnabled = false;
return c.Users.Include("Empresas").FirstOrDefault(x => x.Login == idUser && x.Empresas.Activa == true);
}
}
catch (Exception ex)
{
throw ex;
}
}
Does that Where work differently than what I think I should? If then, how could I get several data that fulfills the conditions I'm passing the same as in getUser but for several rows?
Thanks for your attention.
You need to enumerate the result, so after the "where" statement add. ToList() which will enumerate and execute the query against your database. FirstOrDefault is executing the query thats why you get a result.
You need to check the deferred methods and understand how they work.
EDIT
The following are some links to show you the deference between the Deferred method vs Immediate methods in LINQ
1- http://www.dotnetcurry.com/showarticle.aspx?ID=750
2- http://www.codeproject.com/Articles/627081/LINQ-Deferred-Execution-Lazy-Evaluation
3- http://visualcsharptutorials.com/linq/deferred-execution
Hope that helps.

Update object in foreach loop

I am using EF4/LINQ for the first time and have run into an issue. I am looping thru the results of a LINQ query using a foreach loop as follows:
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
CallOutcomeSubmission los = new CallOutcomeSubmission();
client = connectToService();
try
{
using (var context = new CallOutcomeContext())
{
// List of available actions
private static string ACTION_CALL_ATTEMPT = "Call Attempt";
DateTime oneDayAgo = DateTime.Now.AddHours(-24);
var query = from co in context.T_MMCallOutcome
join ca in context.T_Call on co.CallID equals ca.CallID
join lv in context.T_LeadVendorEmailHeader on co.LeadVendorEmailID equals lv.LeadVendorEmailID
where co.EnteredOn > oneDayAgo && co.MMLeadActionID == null
select new
{
co.CallOutcomeID,
co.CallID,
co.LeadVendorEmailID,
MMLeadID = lv.email_text,
ca.OutcomeID,
lv.FranchiseNumber,
co.MMLeadActionID,
co.LeadAction
};
// if any results found for query
if (query.Any())
{
foreach (var call in query.ToList())
{
// if the franchise exists
if (client.FranchiseExists(int.Parse(call.FranchiseNumber)))
{
switch (call.OutcomeID)
{
case 39: // Not Answered
call.LeadAction = ACTION_CALL_ATTEMPT;
break;
case 43: // Remove from Call List
break;
default: // If the OutcomeID is not identified in the case statement
break;
} // switch
}
else
{
los.eventLog.WriteEntry("CallOutcomeSubmission.OnTimedEvent: No franchise found with franchise ID " + call.FranchiseNumber);
}
// Save any changes currently on context
context.SaveChanges();
} // foreach
}
// if no results found from query write system log stating such
else
{
los.eventLog.WriteEntry("CallOutcomeSubmission.OnTimedEvent: No new entries found");
}
} // using
client.Close();
}
catch (System.TimeoutException exception)
{
los.eventLog.WriteEntry("CallOutcomeSubmission.OnTimedEvent:" + exception.ToString());
client.Abort();
}
catch (System.ServiceModel.CommunicationException exception)
{
los.eventLog.WriteEntry("CallOutcomeSubmission.OnTimedEvent:" + exception.ToString());
client.Abort();
}
}
When I try to do the assignment:
call.LeadAction = ACTION_CALL_ATTEMPT;
I get a build error of
Property or indexer 'AnonymousType#2.LeadAction' cannot be assigned to -- it is read only
I can't seem to find anything on this specific error doing a Google search and am not sure what I am doing wrong. Is it because the original query contains a join?
How can I do the assignment of call.LeadAction within the foreach loop?
I would also like to know if there are design issue withe way I have written the query or performed any of the operations since this is my first foray into EF/LINQ.
You're creating a new anonymous type - with the Linq joins and then trying to set that value. What you're really wanting to do, is update the call's LeadAction correct?
How would EF know to translate your new query back to an entity so it can go back to the database? It would have to go through alot of hoops, and it's not capable of that.
What you could do, is retrieve the Call from your database and set the LeadAction that way - I'm using Find, assuming that CallID is your PK:
case 39: // Not Answered
var thisCall = context.T_Call.Find(call.CallID)
thisCall.LeadAction = ACTION_CALL_ATTEMPT;
break;

Resources