Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CodeIgniter: Try Catch is not working in model class

I have a unique constraint on of the column. When this code runs, I get error log from framework but it is not what I have given in Exception block.
If unique column exists then I want to query its primary key and set it as $id and return to the page. Right now it is stopping on db error and not going into Catch block.
Here is my code:

try {
            $result = $this->db->insert('email', $new_email);
            if ($result)
            {
                $id = $this->db->insert_id();    
            } else {
                throw new Exception("$$$$$$$$$$$$$Log database error");
            }
        } catch (Exception $e) {
            log_message('error',$e->getMessage());
            return;
        }

**Error Messages** I get from framework:

DEBUG - 2013-04-07 05:00:38 --> DB Transaction Failure
ERROR - 2013-04-07 05:00:38 --> Query error: Duplicate entry 

I don't know what is wrong with it.

like image 844
Himanshu Yadav Avatar asked Apr 07 '13 02:04

Himanshu Yadav


People also ask

How to display error in CodeIgniter?

In addition, it has an error logging class that permits error and debugging messages to be saved as text files. By default, CodeIgniter displays all PHP errors. You might wish to change this behavior once your development is complete. You'll find the error_reporting() function located at the top of your main index.


2 Answers

CI has no good support for exceptions. You DB queries will call some vague CI error_logging thingie called show_error(). What you need to do is setup proper exception handling.

Basically you can follow the entire recipe.

Now all your database errors will automatically throw exceptions. And as a bonus you have good exception handling in your entire CI application.

Register a custom errorhandler that transforms PHP errors into exceptions, for instance put this in top of your config/config.php

function my_error_handler($errno, $errstr, $errfile, $errline)
{
    if (!(error_reporting() & $errno))
    {
        // This error code is not included in error_reporting
        return;
    }
    log_message('error', "$errstr @$errfile::$errline($errno)" );
    throw new ErrorException( $errstr, $errno, 0, $errfile, $errline );
}
set_error_handler("my_error_handler");

Register an uncaught exception handler, put something like this in your config/config.php

function my_exception_handler($exception)
{
    echo '<pre>';
    print_r($exception);
    echo '</pre>';
    header( "HTTP/1.0 500 Internal Server Error" );
}
set_exception_handler("my_exception_handler");

Set a termination handler:

function my_fatal_handler()
{
    $errfile = "unknown file";
    $errstr  = "Fatal error";
    $errno   = E_CORE_ERROR;
    $errline = 0;
    $error = error_get_last();
    if ( $error !== NULL )
    {
        echo '<pre>';
        print_r($error);
        echo '</pre>';
        header( "HTTP/1.0 500 Internal Server Error" );
    }
}
register_shutdown_function("my_fatal_handler");

Set a custom assert handler that converts asserts into exceptions, put something like this in your config/config.php:

function my_assert_handler($file, $line, $code)
{
    log_message('debug', "assertion failed @$file::$line($code)" );
    throw new Exception( "assertion failed @$file::$line($code)" );
}
assert_options(ASSERT_ACTIVE,     1);
assert_options(ASSERT_WARNING,    0);
assert_options(ASSERT_BAIL,       0);
assert_options(ASSERT_QUIET_EVAL, 0);
assert_options(ASSERT_CALLBACK, 'my_assert_handler');

Use wrappers like this in your controllers

public function controller_method( )
{
    try
    {
        // normal flow
    }
    catch( Exception $e )
    {
        log_message( 'error', $e->getMessage( ) . ' in ' . $e->getFile() . ':' . $e->getLine() );
        // on error
    }
}

You can tune and customize the whole thing to your likings!

Hope this helps.

You will also need to intercept the CI show_error method. Place this in application/core/MY_exceptions.php:

class MY_Exceptions extends CI_Exceptions
{
    function show_error($heading, $message, $template = 'error_general', $status_code = 500)
    {
        log_message( 'debug', print_r( $message, TRUE ) );
        throw new Exception(is_array($message) ? $message[1] : $message, $status_code );
    }
}

And leave in application/config/database.php this setting on FALSE to have database errors converted into exceptions.

$db['default']['db_debug'] = TRUE;

CI has a few (very) weak points, such as exception-handling but this will go a long way correcting that.

If you are going to use transactions, make sure you do rollbacks on exceptions. Related to this NEVER (as in EVER) use persistant connections as open transactions and other session specific DB state will be picked up / continued by other sessions.

like image 62
Patrick Savalle Avatar answered Sep 30 '22 16:09

Patrick Savalle


If database debugging is turned on, errors from the DB will be routed to the Exceptions core class, and exit() is called after, meaning the script will never even reach your if conditional.

Open application/config/database.php and try setting db_debug to false. This is a good idea to do for production websites, anyways, because you don't want any SQL query issues to release info about your database structure.

Also, unrelated, be careful using $ inside of double quotes, because it'll get parsed as a variable (even a bunch of them in a row -- it'll literally be a variable variable variable variable ...).

like image 42
Aken Roberts Avatar answered Sep 30 '22 15:09

Aken Roberts