In a CakePHP application, if there is any SQL error and debug level is set to greater than 0, then the complete error message from the database is displayed on the screen, but if the debug is set to 0 it just gives something like “unable to add” or worse a blank page. This can be very frustrating for the end users.
How do you gracefully handle SQL errors with debug level set to 0? Well, CakePHP has less known callback for handling these errors, onError. This post is a mini how-to on how to use this callback.
The onError callback gets called by DboSource class in create(), read(), update() and delete() methods. So, if you are writing a custom query and calling it through model’s query() method then onError() won’t get called automatically, but don’t worry, you can still track the SQL error(s). These CRUD methods, alongwith query(), in turn use execute() method which sets SQL error to a class variable, named ‘error’
The lastError() methods have been already implemented in each DBO source (mysql, mssql etc.).
Lets move forward to write our model callback. An example code to log the error in a text file would be would be something like
- function onError()
- {
- // The SQL error
- $error = $this->getDataSource()->error;
- // Log file
- $logFile = LOGS . 'sql_errors.txt';
- // Log the error
- file_put_contents($logFile, file_get_contents($logFile) . $error . "\n\n");
- }
This code can go in your app_model.
Another example code to mail the error would be something like
- function onError()
- {
- // The SQL error
- $error = $this->getDataSource()->error;
- // Send the error
- mail('webmaster@example.com', 'SQL errors', $error);
- }
That’s it for now. Please do let me know your ideas too on implementing onError() callback and also your comments, feedback, suggestions are most welcome.
Happy Coding

My onError code:
public function onError() {
$caller = debug_backtrace(false);
$inf = "";
if (isset($caller[2]["file"]) && isset($caller[2]["line"])) {
$inf = " - File:" . $caller[2]["file"] . " - Line:" . $caller[2]["line"];
}
$src = $this->getDataSource();
$this->log($this->name . " error: " . (isset($src->error) ? " (" . $src->error . ")" : "") . $inf);
}
Hey Amit,
You can simplify your logging to file with:
function onError()
{
// The SQL error
$error = $this->getDataSource()->error;
// Log file
CakeLog::write('sql_errors', $error);
}
The log file will reside in /app/tmp/logs/sql_errors.log along with the framework’s log files (error, debug etc).
Regards,
Donovan
Sorry, I broke the layout of my comment