Wordpress - get_results() - How to know if failed or empty? - database

I use the Wordpress function $wpdb->get_results()
https://codex.wordpress.org/Class_Reference/wpdb#SELECT_Generic_Results
It says:
"If no matching rows are found, or if there is a database error, the return value will be an empty array."
Then how can I know if the query failed OR if it's empty?

Use
$results=$wpdb->get_results($yoursql);
if (count($results)> 0){
//do here
}
But if you want to know if query failed
$wpdb -> show_errors ();
$wpdb -> get_results ($wpdb -> prepare($sql));
$wpdb -> print_error ();

Bit late to the party here but I'm just looking for the same thing. I've had a browse through the wp-db.php code on version 4.4.2.
On line 1422, inside the method flush() there's a bit of code which resets the last_error property:
$this->last_error = '';
This flush() method is called in the query() method on line 1693:
$this->flush();
The get_results() method calls query() on line 2322:
if ( $query ) {
$this->query( $query );
} else {
return null;
}
With this we can be pretty sure that more or less every time get_results() (Or get_row() too for that matter) is called, query() and flush() are both called, which ensures that last_error is set to the empty string before the query is executed.
So assuming the query runs (If it doesn't, null is returned - if the query is empty for example), last_error should contain an error message if the query was to fail for some reason.
Since last_error is flush()ed/reset each time, it should only contain an error for the last query that was run, rather than the last error for any query that had been run previously. With this in mind it should be safe to rely on last_error to determine whether something went wrong with the query.
$results = $wpdb->get_results($sql);
if (is_null($results) || !empty($wpdb->last_error)) {
// Query was empty or a database error occurred
} else {
// Query succeeded. $results could be an empty array here
}
Not the most intuitive in my opinion, but it seems to be sufficient.
Personally, I've written my own class around wpdb for my own benefit. This is my getResults() method.
public function getResults($query, $bindings = [])
{
// Prepare the statement (My prepare method inspects $query and just returns it if there's no bindings, otherwise it uses $wpdb->prepare()
$prepared = $this->prepare($query, $bindings);
// Execute the statement
$rows = $this->db->get_results($prepared, ARRAY_A);
// If an array was returned and no errors occurred, return the result set
if (is_array($rows) && empty($this->db->last_error)) {
return $rows;
}
// On failure, return false
return false;
}
Hope this helps.

Wpdb->get_results function from wordpress returns the result if successful otherwise it will return null. There can be many reasons if a query get failed.Refer in-depth article on debugging get_results() returning empty results here
Although you can use functions like wpdb->show_error() to check what was the last error after executing the sql query. sometimes this error returns empty
then try to use wpdb->last_query to check the final query that get formed.

Related

Laravel 7: Showing error while passing multiple variable in str_replace

I'm facing error while passing multiple variable in str_replace function.
Error: Argument 1 passed to Xenon\LaravelBDSms\SMS::shoot() must be of the type string, null given, called in
Message Body:
Hello #name#,
Total Amount Purchased : #total#
Previous Due: #previous_due#
Deposit: #deposit#
Total Due: #total_due#
Controller:
$id = 1;
$sms_settings = SmsSetting::findOrFail($id);
if($sms_settings->order_create == 1){
$name = $request->name;
$previous_due = $customer->due;
$deposit = $request->deposit;
$total = $request->total;
$total_due = $request->total_due;
$msgs = $sms_settings->order_create_sms;
$msg = str_replace(array('#name#', '#total#','#previous_due#','#deposit#','#total_due#'), array($name,$previous_due, $deposit, $total, $total_due), $msgs);
$send= SMS::shoot($request->mobile, $msg);
}
Shoot Function:
public function shoot(string $number, string $text)
{
$this->sender->setMobile($number);
$this->sender->setMessage($text);
return $this->sender->send();
}
Here I'm using a Laravel Package for sending SMS to mobile number. How can I pass multiple variable in str_replace?
$request->mobile is null, confirm if you are passing the same in the request. Thats why the error.
Also use $request->validated('mobile'), that is safer.
str_replace seems to be fine. Take a look at Example, but Look at examples again, it might break if characters are overlapping with other arguments
I think the variable $msgs = $sms_settings->order_create_sms; contain empty that's why str_replace couldn't replace the data that you given so
$msg = str_replace(array('#name#', '#total#','#previous_due#','#deposit#','#total_due#'), array($name,$previous_due, $deposit, $total, $total_due), $msgs); , will return null.
I recommend checking $msgs again.
$msgs = $sms_settings->order_create_sms;
Make sure $msgs is not null place is_null($msgs) condition before feeding to str_replace
check more about str_replace: https://www.php.net/manual/en/function.str-replace.php

unexpected result in a query in laravel

I’m a beginner in Laravel but have a problem at first. I wrote this query and I’m waiting for Sonya Bins as result but unexpectedly I see ["Sonya Bins"]. what’s the problem?
Route::get('products', function () {
$articles=DB::table('users')->where('id','2')->get()->pluck('name');
return view('products',compact('articles'));
});
pluck will return array if you want to get only single value then use value
// will return array
$articles=DB::table('users')->where('id','2')->get()->pluck('name');
//will return string
$articles=DB::table('users')->where('id','2')->value('name');
// output Sonya Bins
here is an example from the documentation:
if you don't even need an entire row, you may extract a single value from a record using the value method. This method will return the value of the column directly:
$email = DB::table('users')->where('name', 'John')->value('email');
Read more about it here
Hope it helps.
Thanks
pluck() used to return a String before Laravel 5.1, but now it returns an array.
The alternative for that behavior now is value()
Try this:
Route::get('products', function () {
$articles=DB::table('users')->where('id','2')->get()->value('name');
return view('products',compact('articles'));
});
I think it's easier to use the Model + find function + value function.
Route::get('products', function () {
$articles = User::find(2)->value('name');
return view('products',compact('articles'));
});
pluck will return the collection.
I think id is your primary key.
You can just get the first record, and call its attribute's name:
DB::table('users')->where('id','2')->first()->name;
or
DB::table('users')->find(2)->name;
First thing is that you used invalid name for what you pass to view - you don't pass articles but user name.
Second thing is that you use get method to get results instead of first (or find) - you probably expect there is only single user with id = 2.
So to sum up you should use:
$userName = DB::table('users')->find(2)->name;
return view('products',compact('userName'));
Of course above code is for case when you are 100% sure there is user with id = 2 in database. If it might happen there won't be such user, you should use construction like this:
$userName = optional(DB::table('users')->find(2))->name;
($userName will be null if there is no such record)
or
$userName = optional(DB::table('users')->find(2))->name ?? 'No user';
in case you want to use custom string.

Can't update Boolean value in Apex

I cannot update update this Boolean value in Apex. What is going wrong? The if statement, and the fact that the front end representation is a checkbox, proves that it is indeed a boolean value. I am new to Apex so I feel its a basic misunderstanding of how it works. Can anyone help me out?
Here is the code that I'm executing in an Anonymous Window.
Account acc = new Account(Name='Test Name');
if (acc.Do_Not_Contact__pc == false) {
System.debug('DNC is false');
} else {
System.debug('DNC is true');
}
insert acc;
acc.Do_Not_Contact__pc = true;
update acc;
It fails on the second to last line, displaying the following message:
System.DmlException: Update failed. First exception on row 0 with id 001W000000fFiVbIAK; first error: INVALID_FIELD_FOR_INSERT_UPDATE, Account: bad field names on insert/update call: Do_Not_Contact__pc: [Do_Not_Contact__pc]
What's particularly frustrating is that when I change the second to last line to
acc.Do_Not_Contact__pc = 'true';
I get an error stating that I cannot assign a String to a Boolean value
Remove the single quotes and I assume you typed the field name wrong. Try acc.Do_Not_Contact__c = true;

Traverse a query result into a while loop

I'd like to traverse a resultset using a while() loop instead the most common foreach()
If I have this code for example:
$articles = $this->Articles->find();
foreach ($articles as $article) {
echo $article->name;
}
How can I access rows of $articles using a while loop ?
I already tried traverse it using next() or $articles->next() with no success.
I'm not sure that you really need to use a while() loop for what you're trying to achieve, but to answer the question, you have to first get the result set, and then use its Iterator::valid() implementation for the loop condition, this is where the current result is being fetched, which you can then access via current(). Advancing the cursor is then being done using next().
$query = $this->Articles->find();
$resultSet = $query->all();
while ($resultSet->valid()) {
$article = $resultSet->current();
// ...
$resultSet->next();
}
See also API > \Cake\ORM\ResultSet

Is there a way to link Save Results (for an insert DML operation) back to sObjects?

Background
I have a list of sObjects I need to insert, but I must first check if the insert will be successful. So, I'm setting a database save point before performing the insert and checking the save results (for the insert statement). Because, I don't want to process if any errors occurred, if there were any errors in the insert results, the database is rolled back to the save point.
Problem & Question
I need to collect the errors for each save (insert) result and associate each error to the specific sObject record that caused the error. According to the documentation Save results contain a list of errors, the Salesforce ID of the record inserted (if successful), and a success indicator (boolean).
How do I associate the Save Result to the original sObject record inserted?
Code/Example
Here's an example I put together that demonstrates the concept. The example is flawed, in that the InsertResults don't always match the sObjectsToInsert. It's not exactly the code I'm using in my custom class, but it uses the same logic.
Map<Id,sObject> sObjectsToInsert; // this variable is set previously in the code
List<Database.SaveResult> InsertResults;
Map<String,sObject> ErrorMessages = new Map<String,sObject>();
System.SavePoint sp = Database.setSavepoint();
// 2nd parameter must be false to get all errors, if there are errors
// (allow partial successes)
InsertResults = Database.insert(sObjectsToInsert.values(), false);
for(Integer i=0; i < InsertResults.size(); i++)
{
// This method does not guarantee the save result (ir) matches the sObject
// I need to make sure the insert result matches
Database.SaveResult ir = InsertResults[i];
sObject s = sObjectsToInsert.values()[i];
String em = null; // error message
Integer e = 0; // errors
if(!ir.isSuccess())
{
system.debug('Not Successful');
e++;
for(Database.Error dbe : ir.getErrors()) { em += dbe.getMessage()+' '; }
ErrorMessages.put(em, s);
}
}
if(e > 0)
{
database.rollback(sp);
// log all errors in the ErrorMessages Map
}
Your comment says the SaveResult list is not guaranteed to be in order, but I believe that it is. I've used this technique for years and have never had an issue.

Resources