Je nejvyšší čas rozseknout FUD a nejasnosti kolem
databázových vrstev.
Databázovou vrstvu dibi jsem
začal psát cca před devíti lety se záměrem shrnutým v tomto historickém článku. Šlo mi
především o to sjednotit API různorodých klientů, ošetřovat chybové
stavy, přidat uživatelsky pohodlné bindování parametrů a také dynamické
generování základních konstrukcí SQL, jako jsou například podmínky,
řazení a INSERT & UPDATE:
$db = new DibiConnection(...); // or via monostate dibi::connect(...)
$pairs = $db->fetchPairs('SELECT id, name FROM countries');
$arr = array(
'name' => 'John',
'modified%d' => time(),
);
$db->query('UPDATE users SET ', $arr, ' WHERE `id`=%i', $id);
// UPDATE users SET `name`='John', `modified`= '2005-10-12' WHERE `id` = 123
Časem se v PHP objevila nativní knihovna PDO, která v podstatě řešila polovinu
věcí, co dibi, nicméně její API pro bindování parametrů bylo
těžkopádné, neporadilo si s datumy a skládání základních konstrukcí
SQL chybělo úplně. Takže dibi nenahradilo.
V dibi jsem si hrál i s experimenty, jako DibiTable, DibiFluent nebo
DibiDataSource, ale sám jsem je nikdy nepoužíval. Jsou tam pochopitelně
i věci, které bych dnes udělal lépe, ale z hlediska zpětné kompatibility
je takřka nemožné do nich zasahovat. Třeba mám zmatek v tom, co který
modifikátor znamená – je jich příliš mnoho. (Moc se to neví, ale
místo přemýšlení, který modifikátor použít, můžete obvykle použít
otazník.)
Protože téměř v každém demu pro Nette bylo potřeba pracovat
s databází, vyžadovalo to nainstalovat dibi nebo Doctrine (jiné vrstvy se
v podstatě nepoužívají). Dnes je to díky Composeru otázka
pár úderů do klávesnice, ale tehdy neexistoval. Přemýšlel jsem proto, že
bych si v příkladech vystačil jen s čistým PDO. Jenže pokud jste
rozmlsaní z dibi, není návratu zpět. Chybí vám nejen přívětivé API,
ale i pohodlí Tracy (tj. Laděnky) pro
monitorování dotazů či chyb.
Tehdy mě napadlo, že by nebylo od věci udělat „dibi model 2010“,
nově, bez historických zátěží, založené čistě nad PDO. Vyhodit hromadu
driverů, všechny modifikátory nahradit jedním otazníkem a implementovat jen
vlastnosti, které budou skutečně potřeba.
Nette Database
Takhle vzniklo Nette Database
(NDB). Moderní ekvivalent dibi:
$db = new Nette\Database\Connection(...);
$pairs = $db->fetchPairs('SELECT id, name FROM countries');
$arr = array(
'name' => 'John',
'modified' => new DateTime,
);
$db->query('UPDATE users SET ', $arr, ' WHERE `id`= ?', $id);
Brzy jsem narazil na hromadu nedostatků PDO, nareportoval a obešel mraky
chyb a když bylo Nette Database odladěné, vyšlo v únoru 2012 jako
součást finálního Nette Framework 2.0.
Tady musím zdůraznit, že navzdory šiřitelům FUD v Nette Database
skutečně takřka žádné chyby nebyly a jediným větším problém se
ukázal bug v PDO způsobující memory
leaky, kvůli němuž musely být třídy NDB přepsány a v Nette
2.1 již Connection není potomkem PDO (dědit od PDO byla z dnešního
pohledu stejně blbost.)
Dnes nevidím důvod, proč pro nový projekt použít staré dibi namísto
NDB. Chybí asi jen:
- bohatší možnosti skládání v klauzuli WHERE (zatím se nezdá, že by
byla potřeba)
- statická obálka
dibi:: (tu v Nette nahrazuje DI
Container)
- samostatnost (vyřeší Nette 2.2)
- fetchAssoc (tu v Nette nahrazuje NDBT,
eventuálně by ji šlo
doplnit je v 2.2-dev)
A tím se dostáváme k Nette Database Table
(NDBT), prapříčině mnoha zmatků.
Nette Database Table (nyní
Explorer)
V prosinci 2010 jsem do tehdy beta verze Nette 2.0 začlenil knihovnu
Jakuba Vrány NotORM, ve kterém jsem viděl
úžasný nástroj pro dolování dat z databáze:
$pairs = $db->table('countries')->fetchPairs('id', 'name');
// SELECT `id`, `name` FROM `countries`
$name = $db->table('book')->get($id)->author->name;
// SELECT `id`, `author_id` FROM `book` WHERE `id` = 123
// SELECT `id`, `name` FROM `author` WHERE (`author`.`id` IN (456))
$arr = array(
'name' => 'John',
'modified' => new DateTime,
);
$db->table('users')->where('id', $id)->update($arr);
// UPDATE users SET `name`='John', `modified`= '2005-10-12' WHERE `id` = 123
Kód i API jsem upravil tak, aby zapadlo do koncepce Nette, v podstatě
z myšlenky využít NotORM v Latte pochází i nápad na tzv. předbíhání
budoucnosti, neboli načítání jen těch sloupců, které budou později
potřeba, taktéž s Latte může skvěle fungovat koncept NotORM 2.
A právě NotORM v NDB nese označení NDBT (nyní Nette Database
Explorer). Přičemž její použití je volitelné.
Zapojení do Nette vyvolalo o NDBT resp. NotORM velký zájem a ukázalo se,
že byť byla knihovna pro potřeby Jakuba odladěná, pro různorodější
požadavky bylo třeba odvést ještě hodně práce. Té se od poloviny roku
2011 ujal Hrach a z velké části původní NDBT přepsal a pečlivě doplnil
testy. Knihovna procházela mnohem rychlejším vývojovým cyklem než zbytek
frameworku, nicméně nebýt jeho součástí, nevyvíjí se asi vůbec.
Nette tedy má
- NDB (nyní Nette Database Core), obdobu dibi, stabilní od verze 2.0.0
- NDBT (nyní Database Explorer), obdobu NotORM, vhodnou pro produkční
nasazení až od verze 2.1
Dibi nadále udržuji, koneckonců běží mi na něm většina webů, ale
žádné novinky nechystám. V podstatě ani do NDB ne. Naopak s NDBT, jenž
pohání mimo jiné i tento blog, má Hrach ambiciózní plány.
Aktualizace 2017: Původní Nette Database Table (NDBT) nese nový název
Nette Database Explorer a samotné jádro je Nette Database Core