Codeigniter 3: Can't catch database error using try catch block - php

I'm working on an api, it handles the requests which comes from clients, then gets the response from server(developed using codeigniter 3) and forwards that back to client.
But, in case of any database errors, like duplicate id, or null values, the model class cannot handle that error to display a proper error message. I've tried the try catch block but not succeeded yet.
Here's the model:
public function add() {
try {
$this->db->trans_start(FALSE);
$this->db->insert('users', $preparedData);
$this->db->trans_complete();
if ($this->db->trans_status() === FALSE) {
throw new Exception("Database error:");
return false;
}
return TRUE;
} catch (Exception $e) {
log_message('error: ',$e->getMessage());
return;
}
}
One thing to mention, I've set db_debug to FALSE.
Any help would be appreciated.

As for CI 3, below code gets database error code and error message. db_debug is set to FALSE.
public function add() {
try {
$this->db->trans_start(FALSE);
$this->db->insert('users', $preparedData);
$this->db->trans_complete();
// documentation at
// https://www.codeigniter.com/userguide3/database/queries.html#handling-errors
// says; "the error() method will return an array containing its code and message"
$db_error = $this->db->error();
if (!empty($db_error)) {
throw new Exception('Database error! Error Code [' . $db_error['code'] . '] Error: ' . $db_error['message']);
return false; // unreachable retrun statement !!!
}
return TRUE;
} catch (Exception $e) {
// this will not catch DB related errors. But it will include them, because this is more general.
log_message('error: ',$e->getMessage());
return;
}
}
Refer to documentation at https://www.codeigniter.com/userguide3/database/queries.html#handling-errors
saying
If you need to get the last error that has occurred, the error() method will return an array containing its code and message.
It is a bit incomplete in my opinion because it does not show error code and error message in the example code.

I just lost an hour trying to figure out why I can't get the error in my code. You have to check for an error after each statement! Working solution:
function insertUpdate($data) {
$order = $data->order;
$order_products = $data->order_products;
$this->db->trans_start();
$order->user_id = $this->session->user_id;
$error = "OK";
if (!$this->db->insert('_order', $order)) {
$error = $this->db->error()["message"];
}
$id = $this->db->insert_id();
foreach ($order_products as $row) {
$row->order_id = $id;
if (!$this->db->insert('_order_product', $row)) {
$error = $this->db->error()["message"];
break;
}
}
$order_code = substr(md5($id), 0, 6);
if (!$this->db->where('order_id', $id)) {
$error = $this->db->error()["message"];
}
if (!$this->db->update('_order', ["order_code" => $order_code])) {
$error = $this->db->error()["message"];
}
$this->db->trans_complete();
return [
'result' => $error, 'order_code' => $order_code
];
}

Suggestion in above code
Remove line $this->db->trans_complete();
If we see $this->db->error() after completing transaction it will be always empty
Remove semicolon - log_message('error :',$e->getMessage());
return;
public function add()
{
try {
$this->db->trans_start(FALSE);
$this->db->insert('users', $preparedData);
// documentation at
// https://www.codeigniter.com/userguide3/database/queries.html#handling-errors
// says; "the error() method will return an array containing its code and message"
$db_error = $this->db->error();
if (!empty($db_error)) {
throw new Exception('Database error! Error Code [' . $db_error['code'] . '] Error: ' . $db_error['message']);
return false; // unreachable return statement !!!`enter code here`
}
return TRUE;
} catch (Exception $e) {
// this will not catch DB related `enter code here`errors. But it will include them, because this is more general.
log_message('error ',$e->getMessage());
return;
}
}

Related

Catch Guzzle Exception and return string

So I need some help on building out one of my methods for retrieving twitter lists using IDs. Below, I will describe and go into detail on what it's returning.
Code:
public static function get_list($list_id)
{
$lists = self::get_lists();
$params = [
'list.fields' => 'created_at,follower_count,member_count,private,description,owner_id',
'user.fields' => 'created_at,description,entities,id,location,name,pinned_tweet_id,profile_image_url,protected,public_metrics,url,username,verified,withheld'
];
try {
$list = $lists->get($list_id, $params);
} catch (\GuzzleHttp\Exception\ClientException $e) {
return $e;
}
return $list;
}
When $lists->get() has an issue, it throws the following items object(GuzzleHttp\Exception\ClientException)#1640 (10) { ["request":"GuzzleHttp\Exception\RequestException":private]=> error.
What I'd like to achieve:
Return $e so that I can read the error (Unable to get this to work).
If I switch out return $e for return 'Hello', I still see the object and not the string.
The IDE suggests that it #throws GuzzleException.
Does anyone see anything wrong in how I'm handling my exception and why I'm unable to properly return the exception error?
Try to use exception hierarchy to catch any exception. ClientException only catches status code between 400x-499. To catch other exception or catch within the same Exception you can use RequestException.
public static function get_list($list_id)
{
$lists = self::get_lists();
$params = [
'list.fields' => 'created_at,follower_count,member_count,private,description,owner_id',
'user.fields' => 'created_at,description,entities,id,location,name,pinned_tweet_id,profile_image_url,protected,public_metrics,url,username,verified,withheld'
];
try {
$list = $lists->get($list_id, $params);
if($list->getStatusCode() == 200)){
$return_list = json_decode($list->getBody(),true);
}
} catch (\GuzzleHttp\Exception\ClientException $e) {
$error['error'] = $e->getMessage();
$error['request'] = $e->getRequest();
if($e->hasResponse()){
// you can pass a specific status code to catch a particular error here I have catched 400 Bad Request.
if ($e->getResponse()->getStatusCode() == '400'){
$error['response'] = $e->getResponse();
}
}
return $error;
} catch(\GuzzleHttp\Exception\RequestException $se){
$error['error'] = $e->getMessage();
$error['request'] = $e->getRequest();
return $error;
} catch(Exception $e){
//other errors
}
return $list;
}

When I update my data with PHP CodeIgniter, It gives an error. But data is saving

I am using 'CodeIgniter-3.1.3'. When I update my data, it gives an error as follow. But my data is saving in database. I can't find what is the issue. Is there any issue with my model function related to version..?
Error : Fatal error: Call to undefined method CI_DB_mysqli_driver::_error_number()
In Controller
public function saveUpdateData(){
$updateDataArray = array(
"fname" => $_POST['fname'],
"lname" => $_POST['lname'],
"username" => $_POST['user'],
"userlevel" => $_POST['userlevel'],
"contact" => $_POST['contact_no']
);
$whereArr=array("user_id"=>$this->input->post("user_id"));
$rst = $this->MyModel->updateData("admin", $updateDataArray, $whereArr);
if ($rst) {
echo "updated";
}
else{
echo "error";
}
}
In model
function updateData($tablename, $data_arr, $where_arr) {
try {
$this->db->update($tablename, $data_arr, $where_arr);
$report = array();
$report['error'] = $this->db->_error_number();
$report['message'] = $this->db->_error_message();
return $report;
} catch (Exception $err) {
return $err->getMessage();
}
}
enter image description here
Do like this
In Model
function updateData($tablename, $data_arr, $where_arr)
{
if (!$this->db->update($tablename, $data_arr, $where_arr)) {
$result = $this->db->error();
}
else {
return TRUE;
}
}
In Controller
$rst = $this->MyModel->updateData("admin", $updateDataArray, $whereArr);
if ($rst == TRUE) {
echo "updated";
}
else{
print_r($rst);
}
Read Error Handling Codeigniter
In CodeIgniter 3+, you can get errors with error no and messages as by using the following:
$error = $this->db->error();
Reference: Handling Query Errors in CodeIgniter
The functions you are trying to access have been deprecated.
Replace:
$this->db->_error_number()
$this->db->_error_message()
With:
$this->db->error()
The new function will return an array with both the error number and message.
Refer to this CodeIgniter page:
https://www.codeigniter.com/userguide3/changelog.html?highlight=_error_number

How to "catch" a handled exception in a class from the script using the the class?

I have a script that looks like this:
require ("class-pdowrapper.php");
$db = new DB();
$baddata = 'abc'; //should be an integer!!
$db->bind("myinteger", $baddata);
$sql = "INSERT INTO t_numbers (theinteger) VALUES (:myinteger)";
$result = $db->query($sql);
if ($result == 1) {
echo "success.";
} else {
echo "didn't work..."; //question relates to this line
}
If $baddata is "abc" i.e. a string, the class will handle the exception and output something like this:
Unhandled Exception.
SQLSTATE[HY000]: General error: 1366 Incorrect integer value: 'abc' for column 'theinteger' at row 1
You can find the error back in the log
The class does this by something like:
private function query($statement) {
try {
// stuff
}
catch (PDOException $e) {
echo $this->ExceptionLog($e->getMessage(), $query);
die();
}
}
private function ExceptionLog($message, $sql = "") {
$exception = 'Unhandled Exception. <br />';
$exception .= $message;
$exception .= "<br /> You can find the error back in the log.";
if (!empty($sql)) {
$message .= "\r\nRaw SQL : " . $sql;
}
return $exception;
}
So the question is, how can a script acknowledge the exception thrown and handled in the class and use the knowledge to do something. In my case, I could show the user an error or email the administrator to show that something isn't working with the database-related code.
If you catch the exception, then it is stopped from travelling up the stack, so you do not have the opportunity to »re-catch« it.
Basically you can either »re-throw« an Exception of a custom type, by creating a custom Error type like so:
class DataInsertException extends Exception {}
and than later:
try {
// stuff
}
catch (PDOException $e) {
echo $this->ExceptionLog($e->getMessage(), $query);
throw new DataInsertException();
}
That way you can »filter« exceptions within the try catch statement:
try {} catch (DataInsertException $error) {}
whenever you deal with the database. All other Errors wont be caught by that block.
Or you can also add a $errors property to your DB class.
class DB {
private $errors;
public function __construct(){
$this->errors = [];
}
public function insert(){
try {}
catch($error) {
array_push($this->errors, $error);
}
}
public function getErrors() {
return $this->errors;
}
}
That way, you can check the $db Object after each Transaction if it has Errors and react on that.
I would prefer a custom Error
You need validate all your variables before you send it to server
it is right way because you don't send incorrect request to server side.
like this (it is only sample)
<?php
class sampleClass
{
public function __construct($data) {
if ($this->validateData($data)) {
//do something
$this->runRequest($data);
} else {
//parse errors
//var_dump($data);
}
}
private function validateData($data) {
foreach($data as $currentData) {
if ($currentData['type'] == 'integer' && is_int($currentData['value'])) {
return false;
}
if ($currentData['type'] == 'string' && is_string($currentData['value'])) {
return false;
}
}
return true;
}
private function runRequest($data) {
}
}
$data = [
'correct_age' => [
'type' => 'integer',
'value' => 88
],
'incorrect_age' => [
'type' => 'integer',
'value' => 'abc'
],
'incorrect_name' => [
'type' => 'string',
'value' => 111
]
];
$test = new sampleClass($data);
There are many options here. Here're some of them:
You can rethrow an Exception in you catch (PDOException $e) { block and make another try ... catch ... in your script. So you would handle logging in your query method and then handle application-related logic in the script file itself:
try {
$result = $db->query($sql);
} catch (AnotherException $e) {
...
}
You can return complex result from query(), like this (it's only a draft):
$result = array(
'status' => true|false (or 'error' => true|false),
'data' => ... (valid data on success, error details data on error)
)
And then you can handle this result with no problems.

Use error outside catch block

Let's work with an example like this:
try {
if( $var == false ) {
throw new Exception('Fail');
}
} catch (Exception $e) {
$error = $e->getMessage();
}
Is there any way i can use $error outside the catch block?
If i try to print it outside,it shows nothing , so i'm sure i'm doing this wrong. Any help would be apreciated.
EDIT: This is my exact situation of the code click
I need to use $error , in another piece of code , outside of the class
Actually you are returning the error message, if you remove the return false statement, and try to print outside the loop it will print.
you can do that in 2 way:
Option1:
try {
if( $var == false ){
throw new Exception('Fail');
}
} catch (Exception $e){
$error = $e->getMessage();
// return false;
}
print_r($error);
Option 2:
try {
if( $var == false ){
throw new Exception('Fail');
}
} catch (Exception $e){
return $error = $e->getMessage();
}
This will return true if no error happens. Else it will return the error.
$error = false;
try {
if( $var == false ){
throw new Exception('Fail');
}
} catch (Exception $e){
$error = $e->getMessage();
}
return $error;
It depends on your implementation whether to return true or false.
You should not
The $error is declard inside the catch.
You your function throws a Exception don't use try cactch. just throw the Exception
Your function should return just one type;
If it returns boolean, return aways boolean
Maybe if you need to print the error, print it inside the catch

How to return errors from PHP method?

I have a save method in my User class.
If the save method encounters validation errors it returns an array of errors that I display to the user. However this means in my code I have to write:
if (!$user->save()) {
//display success to user
}
Surely my save method should return true on success. But how do I handle errors in that case?
Use try ... catch syntax.
For example:
try {
$user->save();
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
http://php.net/manual/en/language.exceptions.php
I would throw an exception in the event that save() runs into any problems.
If you want to provide an array of validation errors, your could subclass Exception and provide a mechanism for storing the validation errors.
A custom Exception subclass will also help you differentiate between exceptions your code throws explicitly (which you'd like to catch) and exceptions that you didn't expect (which should be fatal).
Here's the subclass:
class UserException extends Exception
{
private $userMessages;
public function __construct($message = "", $code = 0, Exception $previous = null, array $userMessages = null)
{
parent::__construct($message, $code, $previous);
if ($userMessages === null) {
$this->userMessages = array();
} else {
$this->userMessages = $userMessages;
}
}
public function getUserMessages()
{
return $this->userMessages;
}
}
Here's a silly version of a User class that always throws an Exception on save().
class User
{
public function save()
{
$userMessages = array(
'Your password is wrong',
'Your username is silly',
'Your favorite color is ugly'
);
throw new UserException('User Errors', 0 , null, $userMessages);
}
}
To use it:
$user = new User();
try {
$user->save();
} catch (UserException $e) {
foreach ($e->getUserMessages() as $message) {
print $message . "\n";
}
}
You could also accomplish something like this by populating the Exception's $message with, say a semi-colon-delimited list of messages. You could even build a list of constants for error types, then combine them as a bitmask and use that for the Exception's $code. The advantage of these options is you would be using the built in members and not adding anything extra.
More on exceptions:
http://php.net/manual/en/language.exceptions.php
A (bad?) habit I picked up after playing a good bit with erlang is to return tuple values (as a php array).
function my_func() {
$success = true;
$errors = array();
if ( something_fails() ) {
$success = false;
$errors[] = 'something failed..';
}
return array( $success, $errors );
}
list($success, $errors) = my_func();
if ( ! $success ) {
do_somthing_with( $errors );
}
In my experience, this has been really handy when the wild modify legacy code tickets appear and you don't really dare modify anything but could more easily add more legacy to it.
Cheers -
Return either true, or the error array.
And when you check for it, use this:
if ($user->save()===true) {
// display success to user
} else {
// display error to user
}
the === operator performs a typesafe comparison, meaning that it not only checks if the value is true, but also if the type is a boolean. If the array is being returned it's handled as false.
Would be good to return array from validation function like this
$result['ACK'] = 'true';
$result['message'] = 'Success validation'];
on failure
$result['ACK'] = 'false';
$result['message'] = 'validation error message';
Now you can use this array in front end like this
if ($result['ACK']) {
//No Error
} else {
echo $result['message'];
}
Change your condition to, If true then success else return array of errors.
if ($user->save() === true) {
//display success to user
}

Categories