Kde se pojit k databázi a chytat výjimky dibi?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
maarlin
Člen | 207
+
0
-

V tuto chvíli se připojuji standardně v bootstrapu:

<?php
require LIBS_DIR . '/Nette/loader.php';
require LIBS_DIR . '/dibi/dibi.min.php';

// Connect to database
$dibiOptions = array(
                    'driver'   => 'mysql',
                    'host'     => 'localhost',
                    'username' => '...',
                    'password' => '...',
                    'database' => '...',
                    'charset'  => 'utf8',
                );
dibi::connect($dibiOptions);
// ... etc.
?>

kde ale nechytám výjimky, jako je např. tato:

Fatal error: Uncaught exception 'DibiDriverException' with message 'Lost connection to MySQL server at 'waiting for initial communication packet', system error: 95' in /var/home/.../www/libs/dibi/dibi.min.php:1135
Stack trace:
#0 /var/home/.../www/libs/dibi/dibi.min.php(235): DibiMySqlDriver->connect(Array)
#1 /var/home/.../www/libs/dibi/dibi.min.php(230): DibiConnection->connect()
#2 /var/home/.../www/libs/dibi/dibi.min.php(952): DibiConnection->__construct(Array, 0)
#3 /var/home/.../www/app/bootstrap.php(14): dibi::connect(Array)
#4 /var/home/.../www/index.php(18): require('/var/home/.../www/...')
#5 {main} thrown in /var/home/.../www/libs/dibi/dibi.min.php on line 1135

Protože ještě afaik nemůžu přímo směrovat na error presenter (nebyl zatím volán $app->run();).

Jak tohle řešíte? Rád bych, kdyby při takové výjimce to přesměrovalo na nějaký error presenter s HTTP 503 (Temporarily unavailable)…

mkoubik
Člen | 728
+
0
-

Já to řeším líně v BaseModelu:

namespace App\Model;

/**
 * @property-read \Nette\Database\Connection $db
 */
abstract class BaseModel extends \Nette\Object
{
    /** @var \Nette\Database\Connection */
    private static $connection;

    /** @return \Nette\Database\Connection */
    public function getDb()
    {
        if (self::$connection === null) {
	    // tady používám Nette\Database, ale stejné by to bylo pro dibi
            $config = \Nette\Environment::getConfig('database');
            self::$connection = new \Nette\Database\Connection("$config->driver:host=$config->host;dbname=$config->dbname", $config->user, $config->password);
        }
        return self::$connection;
    }
}

A v konkrétním modelu pak

$this->db->query('..');

Takže případná výjimka vyhřezne až tam, kde model použiju.

Jan Tvrdík
Nette guru | 2595
+
0
-
$application->onStartup[] = function () {
	dibi::connect(...);
};
Petr Motejlek
Člen | 293
+
0
-

Já používám Doctrine 2, ke kterému se dostávám přes služby, kterou mám pojmenovanou EntityManager. Takže se mi výjimka vyhodí, až když někdo zavolá <?php Environment::getService(‚EntityManager‘); ?>.

maarlin
Člen | 207
+
0
-

mkoubik napsal(a):

Já to řeším líně v BaseModelu:

A v konkrétním modelu pak

$this->db->query('..');

Takže případná výjimka vyhřezne až tam, kde model použiju.

Představa BaseModelu se mi docela líbí… Jen jsem to neřešil pomocí getteru, ale prostě pomocí konstruktoru s dibi::connect() a uložení spojení do proměnné.

Jen jsem přišel na to, že dibi::connect() je opravdu defaultně líné… :))

Tedy připojí se až když je to potřeba… což znamená, že se začne vykreslovat šablona, dojde se k nějakému výpisu, který potřebuje data z databáze, ihned zjistí, že je nějaký problém, tak vloží 503… čili mám polovinu stránky (kde nebylo potřeba databázových dotazů) vykreslenou a pak najednou vloženou HTTP 503…

Asi by bylo ideální, kdyby na nějaký problém přišel co nejdříve, nejlépe ještě před vykreslováním v šabloně, aby se stihla poslat nějaká nice hláška a ne ten paskvil, jako nyní…

Sice nevolání ->fetchAll() v presenteru šetří paměť, ale pak imho způsobuje popsané problémy (vložení HTTP erroru do polonačtené stránky).

Editoval maarlin (30. 3. 2011 10:44)

Filip Procházka
Moderator | 4668
+
0
-

To je o přístupu…

Pokud máš výpis článků, tak ti s jakoukoliv chybou databáze nebude vadit, když napíšeš uživateli „nebyly nalezeny žádné záznamy“ popř z toho udělat nějakou user friendly větu typu „články nejsou na skladě“ apod.

Když ale budeš třeba vypisovat něco, co opravdu potřebuješ, je nejlepší si to načíst už v render(data šablony)/action(data komponent) a do šablony vložit už surová data, takhle můžeš ošetřit, že se ti nevykreslí půl stránky a chyba.

maarlin
Člen | 207
+
0
-

HosipLan napsal(a):

To je o přístupu…

Pokud máš výpis článků, tak ti s jakoukoliv chybou databáze nebude vadit, když napíšeš uživateli „nebyly nalezeny žádné záznamy“ popř z toho udělat nějakou user friendly větu typu „články nejsou na skladě“ apod.

Nedovedu si moc dobře představit, že „nebude vadit“ uživateli tahle hláška třeba na blogu, nebo jiném webu, který je prakticky postaven na článcích…
Stačí si jen představit třeba http://www.sedmicka.cz/ , která mmj. taky jede na Nette – opravdu chce uživatel vidět půl stránky, boční panel s počasím a pak vidět, že články (= to hlavní, pro co přišel) nejsou k dispozici?

Když ale budeš třeba vypisovat něco, co opravdu potřebuješ, je nejlepší si to načíst už v render(data šablony)/action(data komponent) a do šablony vložit už surová data, takhle můžeš ošetřit, že se ti nevykreslí půl stránky a chyba.

Ty nejdůležitější výpisy jsou většinou taky nejdelší (= obsahují nejvíce dat), tzn. ukládat třeba seznam 20ti článku s delším perexem a vším všudy do pole a to pak předávat do šablony… jen proto, abych zjistil, jestli databáze funguje… je šílená představa

Čili spíše řešíme otázku, zda je pro uživatele lepší vidět kostru stránky bez dat (tedy prakticky stránku k ničemu), nebo „čistokrevnou“ HTTP 503…

Bereme v úvahu web, který opravdu 95% všech dat získává z databáze a nebereme v úvahu případ, kdy by databáze fungovala na první dotaz a před prováděním dalších (to vše během jednoho HTTP requestu) se třeba odmlčela…

Editoval maarlin (30. 3. 2011 11:17)

Filip Procházka
Moderator | 4668
+
0
-

ono je taky potřeba rozlišovat důležitost chyby

když se nejde připojit do databáze – zabít stránku
nemůže najít záznamy (nejsou/chyba scriptu) – zobrazit zprávu ze nema zaznamy

Ale výpis článků je zrovna asi blbý příklad. Třeba kdyby byl problém načíst anketu, tak kvůli tomu nezabiju celý web…

Proč je neoptimální vytáhnout z databáze 20 článků v presenteru? Pokud je máš v entitě, tak stejně jenom předáváš referenci na objekt a neduplikuješ data.

maarlin
Člen | 207
+
0
-

HosipLan napsal(a):

ono je taky potřeba rozlišovat důležitost chyby

když se nejde připojit do databáze – zabít stránku
nemůže najít záznamy (nejsou/chyba scriptu) – zobrazit zprávu ze nema zaznamy

tak najití záznamů není snad chyba v původním slova smyslu… tedy z pohledu vykonání toho dotazu to chyba není. Dotaz se v pořádku vykoná, jen nevrátí data (->fetchAll() vrátí FALSE). Což ošetřuji až v šabloně:

{if count($articles) > 0}
	{foreach $articles...} {/foreach}
{else}
	... žádné články ...
{/if}

Pod pojmem chyba chápu třeba nesprávná syntax, změna struktury databáze (= chybějící/přejmenovaný sloupec nebo tabulka), aktivní zámek na tabulce… etc.

Ale výpis článků je zrovna asi blbý příklad. Třeba kdyby byl problém načíst anketu, tak kvůli tomu nezabiju celý web…

Anketa je asi dobrý příklad, který by měl být extra ošetřen try {} catch () {} blokem a nějakou nice hláškou, ale obecně se ta „důležitost“ hledá dost špatně… nebo na to máš nějaké pravidlo?

Proč je neoptimální vytáhnout z databáze 20 článků v presenteru? Pokud je máš v entitě, tak stejně jenom předáváš referenci na objekt a neduplikuješ data.

To ano, jen jsem si teď vzpomněl, jak důležité je do každého SELECTu pak vyjmenovávat opravdu jen ty sloupce, které aktuálně potřebuji. :-)

Pak to neoptimální není. Za předpokladu SELECT * … to neoptimální je.

Editoval maarlin (30. 3. 2011 12:28)