Détection d'une exception / erreur dans une transaction de base de données

11

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

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

mais comment puis-je détecter les erreurs / exceptions si la requête échoue pour une raison quelconque, comme elle $database->getErrorNum()est déconseillée?

dev-m
la source

Réponses:

13

JError a été déconseillé dans J3.x, au profit des exceptions PHP, car il mélangeait 2 concepts de programmation différents : la journalisation et la gestion des erreurs (le côté de la journalisation a maintenant été implémenté 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 cette réponse SO :

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

Notez que $database->execute()cela 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 JDatabaseméthodes d'objet updateRecord() et insertRecord()génèrent également des erreurs que vous pouvez détecter en cas d'échec:

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

Si vous développez pour Joomla 3.x uniquement, vous pouvez également utiliser un bloc try catch avec des 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);
}
codinghands
la source
dans mon joomla 2.5.11 $ database-> execute (); fonctionne bien car je fais un composant unique pour joomla 2.5 et 3. Mais votre premier bloc try-catch avec execute () ne fonctionne pas dans 2.5.11. Comme vous l'avez dit, les méthodes d'objet Jdatabase ne fonctionnent que 2.5 et 3.1, donc je ne vais pas l'utiliser. Quelles sont les autres méthodes disponibles pour l'implémenter et compatibles avec les versions J 2.5 et 3 ??.
dev-m
Huh, bizarre, les documents semblent indiquer que -> execute () ne fonctionne pas en 2.5. Va éditer. Les méthodes d'objet JDatabase devraient fonctionner dans toutes les versions
J3.X
1
"Mais votre premier bloc try-catch avec execute () ne fonctionne pas en 2.5.11" ... quelle erreur obtenez-vous, le cas échéant?
codinghands
Je n'ai pas vérifié le message mais j'ai mis un retour faux; là mais ça ne retourne pas faux à coup sûr, donc le contrôle n'entre pas dans le bloc catch sur mon site 2.5.11.
dev-m
Pourriez-vous activer le rapport d'erreurs dans la configuration globale Pour voir si PHP génère des erreurs.
codinghands
0

Idéalement, installez pecl, puis étendez la classe JDatabase * appropriée et remplacez JFactory :: getDbo () avec une implémentation de ce qui suit pour éliminer la nécessité de mettre à jour un milliard de code pour encapsuler chaque requête db critique dans les instructions try catch.

La prochaine meilleure chose pour moi est le support ci-dessous pour l'ancienne et la nouvelle façon:

Inclure cela 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;
        }
    }
}

Ensuite, utilisez-le comme ceci

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;
}
ekerner
la source