Łapanie wyjątku / błędu w transakcji bazy danych

11

Używam następującego sposobu w Joomla 2.5 i 3 do wykonania zapytania do bazy danych -

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

ale jak wychwycić błędy / wyjątki, jeśli zapytanie nie powiedzie się z jakiegokolwiek powodu, ponieważ $database->getErrorNum()jest przestarzałe?

dev-m
źródło

Odpowiedzi:

13

JError został przestarzały w J3.x, na korzyść wyjątków PHP, ponieważ łączył 2 różne koncepcje programowania : rejestrowanie i obsługę błędów (strona logowania została teraz zaimplementowana jako JLog ).

W twoim przypadku możesz owinąć swój kod blokiem try / catch, aby uzyskać błąd, jak pokazano w tej odpowiedzi SO :

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

Zauważ, że $database->execute()stwierdzono, że NIE działa w J2.5 . Powinieneś użyć, $database->query()jeśli potrzebujesz ekwiwalentu.

W Joomla 2.5 i 3.x JDatabasemetody obiektowe, updateRecord() a insertRecord()także zgłaszanie błędów, które można wychwycić, jeśli zawiodą:

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

Jeśli programujesz tylko dla Joomla 3.x, możesz również użyć bloku try catch z transakcjami SQL, aby uzyskać szczegółowe informacje o błędzie:

$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);
}
kodowania
źródło
w mojej bazie danych joomla 2.5.11 $-> execute (); działa dobrze, ponieważ tworzę pojedynczy komponent dla Joomla 2.5 i 3. Ale twój pierwszy blok try-catch z execute () nie działa w 2.5.11. Jak powiedziałeś, metody obiektowe Jdatabase działają tylko w wersjach 2.5 i 3.1, więc nie będziesz ich używać. Więc jakie inne metody są dostępne do implementacji tego i są kompatybilne z wersjami J 2.5 i 3 ??.
dev-m
Co dziwne, dokumenty wydają się stwierdzać, że -> execute () nie działa w wersji 2.5. Będzie edytować. Metody obiektowe JDatabase powinny działać we wszystkich wersjach
J3.X
1
„Ale twój pierwszy blok try-catch z execute () nie działa w 2.5.11” ... jaki błąd się pojawia, jeśli występuje?
codinghands
Nie sprawdziłem wiadomości, ale zwróciłem false; tam, ale na pewno nie zwraca false, więc kontrola nie wchodzi w blok catch na mojej stronie 2.5.11.
dev-m
Czy możesz włączyć raportowanie błędów w konfiguracji globalnej, aby sprawdzić, czy PHP generuje jakieś błędy.
codinghands
0

Idealnie zainstaluj pecl, a następnie rozszerz odpowiednią klasę JDatabase * i przesłon JFactory :: getDbo () za pomocą implementacji poniżej, aby wyeliminować potrzebę aktualizacji kodu squillion, aby zawijał każde krytyczne zapytanie db w instrukcjach try catch.

Kolejną najlepszą rzeczą dla mnie jest poniższe wsparcie starej i nowej drogi:

Uwzględnij to gdzieś

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

Następnie użyj tego w ten sposób

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
źródło