contributte / planette-site

💀 [DISCONTINUED] All the roads go through the Planette
https://planette.vercel.app
MIT License
9 stars 3 forks source link

2012-01-30: nette-database-vs-dibi #85

Open paveljanda opened 7 years ago

paveljanda commented 7 years ago

Mezi některými uživateli Nette Frameworku v poslední době vznikají zmatky: myslí si, že knihovny Nette\Database a dibi spolu nějak souvisí. Takže si nejprve připomeneme elementární rozdíl mezi těmito dvěmi rozdílnými knihovnami.

dibi

Každý nějak začínal. Ti největší punkeři ještě pamatují mysql_* funkce, které jsou neohrabané a samy o sobě pouze nabízí PHPku přístup k databázi. Cokoliv, co se přibližuje bezpečnosti, si uživatel musí zařídit sám.

Proto vznikla knihovna dibi, která obaluje tyto hloupé funkce do chytré knihovny. Řeší SQL injekci a lahodí oku programátora.

Dibi dosáhla svého vrcholu, a jak sám autor říká, už není nic dalšího, co by měla umět. Je to stabilní konzervativní (bez magie) knihovna, perfektní, pokud znáte alespoň základy SQL a učíte se programovat, nebo vyvíjíte masivní aplikaci. Prostě vám kryje záda.

Dibi je externí knihovna a není součástí Nette.

Nette\Database

Nette Database je velice inovativní ale i magická knihovna. Nette Database je z většiny "něco jako dibi", ale k tomu kombinuje hlavní feature NotORM od Jakuba Vrány a pozměnuje (příliš) magické API, aby se lépe používala.

Tou feature převzatou z NotORM je inteligentní získávání dat z databáze. Snaží se ušetřit nás od psaní opakujících se SQL dotazů a pokládá minimální množství maximálně efektivních SQL dotazů. Může se tvářit příliš magicky, ale to je právě její výhoda.

Nette Database je součástí Nette, ale používat jej nemusíte, pokud vám nevyhovuje. Můžete používat klidně dibi, Doctrine2, nebo jiný nástroj.

Použití dibi

Pokud začínáte nový projekt, je nejlepší zaregistrovat DibiConnection jako službu.

common:
        parameters:
                database:
                        host: localhost
                        username: root
                        password: ***
                        database: foo
                        lazy: TRUE

        services:
                connection:
                        class: DibiConnection(%database%)

Tohle nám může zjednodušit rozšíření pro dibi, které je součástí dibi (ve verzi 2). Zaregistrovat ho můžeme v app/bootstrap.php, před tím, než vytvoříme DI Container.

$configurator->onCompile[] = function ($configurator, $compiler) {
        $compiler->addExtension('dibi', new DibiNetteExtension);
};

Nyní se nám konfigurace zjednoduší na

common:
        dibi:
                host: localhost
                username: root
                password: ***
                database: foo
                lazy: TRUE

a službu budeme odkazovat né @connection, ale @dibi.connection.

V Presenteru

V presenteru k připojení přistoupíme přes DI.

class ArticlePresenter extends Nette\Object
{
        /** @var DibiConnection @inject */
        public $db;

        public function actionDefault($id)
        {
                $row = $this->db->query('SELECT * FROM articles WHERE id = %i', $id);
                // ...
        }

        // ...
}

V Modelu

Pokud pracujete s modely (což je velice dobře), tak by váš model mohl vypadat cca takto

namespace MyApp;

class Articles extends \Nette\Object
{
        /** @var \DibiConnection */
        private $db;

        public function __construct(\DibiConnection $connection)
        {
                $this->db = $connection;
        }

        // zde následují vlastní metody na práci s články

        public function find($id)
        {
                // dibi dovoluje i fluent zápis (místo klíčových slov SQLka jsou metody)
                return $this->db->select('*')->from('articles')
                        ->where('id = %i', $id)
                        ->fetch();
        }

        public function delete($id)
        {
                $this->db->delete("articles")->where("id = %i", $id)->execute();
        }

        // další metody ...
}

Takový model se správně zaregistruje do DI Containeru a nastavíme DI Container, aby mu při vytvoření předal službu connection, kterou jsme si definovali na začátku.

common:
        services:
                articles:
                        class: MyApp\Articles(@dibi.connection)

Nyní máme model zaregistrovaný v DI Containeru a můžeme ho použít v presenteru stejně, jako jsme použili samotné připojení.

class ArticlePresenter extends Nette\Object
{
        /** @var Articles @inject */
        public $articles;

        public function actionDefault($id)
        {
                $row = $this->articles->find($id);
                // ...
        }

        // ...
}

O modelech s dibi si můžete přečíst i můj starší článek z praxe.

Stará aplikace, se statickými modely

Nový DI Container je stále ještě velice čerstvá záležitost a je možné, že vaše aplikace má modely statické a došli jste do bodu, kdy vám takovéto řešení nestačí. Není nic jednoduššího, než si zaregistrovat dibi tak, aby fungovaly staré statické modely, ale zároveň bylo dibi jako služba. Díky tomu můžete bezbolestně přepisovat statické modely a psát nové modely lépe.

common:
        parameters:
                database:
                        driver: mysql
                        host: localhost
                        username: root
                        password: ***
                        database: foo
                        lazy: TRUE

        services:
                connection:
                        class: DibiConnection
                        factory: dibi::connect(%database%)
                        run: TRUE

DI Container umožňuje pověřit vytvořením služby i jinou službu, nebo třídu a klidně i statickou. Takže toho využijeme a nadefinujeme si, aby dibi bylo vytvářeno staticky, jeho instance se uložila jako služba a automaticky se spouštěla při startu aplikace.

Tento zápis je identický se zastaralým zápisem z app/boostrap.php

dibi::connect($container->parameters['database']);

Použití Nette\Database

Zde nejsem ten nejoprávněnější něco obsáhlého psát, takže jen stručně. Platí v podstatě vše, co bylo napsáno o dibi, jen modely a použití bude malinko jiné, kvůli povaze knihovny.

Ukáži tedy pouze základ.

v Presenteru

Protože Nette\Database je součástí Nette Frameworku, ten toho využívá naplno a usnadňuje nám vytváření služby s Nette\Database pro připojení. Nastavení konfiguračního souboru si můžete prohlédnout zde.

Použití bude podobné, jako u dibi:

class ArticlePresenter extends Nette\Object
{
        /** @var Nette\Database\Connection @inject */
        public $db;

        public function actionDefault($id)
        {
                // získáme si selector pro tabulku
                $articles = $this->db->table('articles');
                $row = $articles->get($id);

                // ...
        }

        // ...
}

Jak vidíte, Nette\Database nám ze začátku vývoje aplikace může plně suplovat vlastní třídy s modely, dokud nebude potřebné oddělit složitější logiku. Toto prosím neznamená, že modelové třídy nemáte psát. To znamená, že může nějakou dobu trvat, než zjistíte, že je potřebujete.

{{tags: dibi, database}}

{{author: Filip Procházka|2118}}

paveljanda commented 7 years ago

author: Honza Kuchař (honza.kuchar@grifart.cz)