web-dev-qa-db-fra.com

Catching exception / error dans la transaction de base de données

J'utilise la manière suivante dans joomla 2.5 et 3 pour exécuter une requête de base de données -

$database = JFactory::getDBO();
$database->setQuery
$database->execute();

mais comment puis-je intercepter des erreurs/exceptions si la requête échoue pour une raison quelconque, étant donné que $database->getErrorNum() est obsolète?

11
dev-m

JError est déconseillé dans J3.x, en faveur de PHP exceptions, car entremêlant 2 concepts de programmation différents) : journalisation et gestion des erreurs (le côté de la journalisation est maintenant mis en œuvre en tant que JLog ).

Pour votre cas exact, vous pouvez envelopper votre code dans un bloc try/catch pour obtenir l'erreur, comme indiqué dans this SO answer :

try {
    ...
    $db->setQuery($query);
    $result = $db->loadResult();
}
catch (Exception $e){
    echo $e->getMessage();
}

Notez que $database->execute() est indiqué à NE fonctionne PAS en J2.5 . Vous devez utiliser $database->query() si vous avez besoin d'un équivalent.

Dans Joomla 2.5 et 3.x, les JDatabase méthodes d'objetupdateRecord() et insertRecord() génèrent également des erreurs que vous pouvez intercepter si elles échouent:

try {
    JFactory::getDbo()->updateObject('#_table_name', $data);
} catch (Exception $e) {
    //...handle the exception
}

Si vous développez uniquement pour Joomla 3.x, vous pouvez également utiliser un bloc catch try avec transactions SQL pour obtenir les détails de l'erreur:

$db = JFactory::getDbo();

try {
    $db->transactionStart();

    $query = $db->getQuery(true);

    $values = array($db->quote('TEST_CONSTANT'), $db->quote('Custom'), $db->quote('/path/to/translation.ini'));

    $query->insert($db->quoteName('#__overrider'));
    $query->columns($db->quoteName(array('constant', 'string', 'file')));
    $query->values(implode(',',$values));

    $db->setQuery($query);
    $result = $db->execute();

    $db->transactionCommit();
}
catch (Exception $e) {
    // catch any database errors.
    $db->transactionRollback();
    JErrorPage::render($e);
}
13
codinghands

Idéalement, installez pecl, puis étendez la classe JDatabase * appropriée et remplacez JFactory :: getDbo () par une implémentation de ce qui suit pour éviter le recours à des mises à jour de code afin d'encapsuler toutes les requêtes de base de données critiques dans les instructions catch.

La meilleure chose à faire pour moi est le support ci-dessous pour l'ancienne méthode et la nouvelle:

Inclure ceci quelque part

class jDbUtils
{
    protected static $dbErrorMessage = '';

    public static function stupidJ3CatchDatabaseExecute($db, $cmd, $report = false) {
        self::$dbErrorMessage = '';
        try {
            $res = $db->$cmd();
            // legacy db error support
            if (method_exists($db, 'getErrorNum') && $db->getErrorNum())
                throw new Exception($db->getErrorMsg());
            return $res;
        } catch(Exception $e) {
            self::$dbErrorMessage = $e->getMessage();
            if ($report)
                self::reportIfDbError();
            return false;
        }
    }

    public static function reportIfDbError()
    {
        if (self::$dbErrorMessage) {
            JFactory::getApplication()->enqueueMessage(self::$dbErrorMessage, 'error');
            return true;
        }
    }
}

Alors utilisez-le comme ça

function someDbInteraction(){
    $db = JFactory::getDbo();
    $db->setQuery('SELECT no_such_col FROM no_such_table LIMIT 1');
    $res = jDbUtils::stupidJ3CatchDatabaseExecute($db, 'loadResult');
    if (jDbUtils::reportIfDbError())
        return false;
    // do more processing
    return $res;
}
0
ekerner