Klávesové zkratky na tomto webu - rozšířené Na obsah stránky

Translate to English… Ins Deutsche übersetzen…

Téměř v cíli: dibi 0.9b

Vývoj databázového layeru dibi se nezadržitelně blíží k finální verzi. Vyzkoušel jsem si trošku jiný přístup k open source, existoval pouze jediný článek o této knihovně a připomínkování probíhalo v komentářích nebo přes e-maily. Za podněty děkuji zejména Tomáši Bartoňovi. Komorní atmosféra vývoje mi sedla, nemusel jsem se tolik svazovat zpětnou kompatibilitou ani řešit podporu.

Co je dibi?

Jde o minimalistický databázový layer, dobře padnoucí do ruky. Jednosouborová verze obsahující ovladače pro 8 databází (MySQL, MySQLi, PostgreSQL, SQLite, ODBC a experimentální MS SQL, Oracle a PDO) má pouhých … a neřeknu :-) Tipněte si.

Dibi má plnit tyto tři cíle:

1) zapouzdřit funkce do intuitivního rozhraní

Samozřejmě do rozhraní objektového, s využitím syntaktických cukrlátek PHP 5 a vyhazováním výjimek. Prostě místo

$link = mysql_connect(...);

$res = mysql_query('...', $link);
while ($row = mysql_fetch_assoc($res)) {
   ...
}

a pozdějšího překopávání na mysqli_query, kde jsou navíc prohozené parametry, je víc sexy psát:

dibi::connect('driver=mysqli');

$res = dibi::query('...');
foreach ($res as $row) {
   ...
}

V tomto směru není dibi nikterak objevné, vlastně je jen náplastí na můj značně nedůvěřivý vztah k open source (a nejen můj), prostě co si nenapíšu sám…

Tip jak mít dibi vždy po ruce: v php.ini si jako auto_prepend_file nastavte soubor, který bude inkludovat dibi nebo tak učiní přes autoloading. Dále nastavte přihlašovací údaje do direktiv mysql.default_user, mysql.default_password a mysql.default_host. Pak stačí v kódu napsat jen dibi::connect(); a hned můžete databázovat.

Tip pro ladění: při ladění aplikací by se vám mohly hodit tyto statické proměnné:

echo dibi::$sql; // zobrazí poslední SQL příklaz
echo dibi::$elapsedTime; // jeho doba trvání v sec
echo dibi::$numOfQueries; // celkový počet SQL příkazů
echo dibi::$totalTime; // jejich celkový čas v sec

2) asistovat při psaní SQL dotazů

Jelikož píšu aplikace na míru konkrétním databázím, bod č. 1 by nikdy nebyl impulsem k psaní další vrstvy. Tím bylo nepohodlné a otravné skládání SQL dotazů. Potřeboval jsem něco, co mi dovolí

  • zapsat dotaz maximálně přehledně (kouknu a hned vidím)
  • bude uvozovat identifikátory a řetězce
  • konvertovat typy boolean nebo date do formátu databáze
  • bude to blbuvzdorné a navíc setsakramentsky rychlé

Hledání správné‚n‘kůl syntaxe trvalo nesmírně dlouho a dodnes nejde o uzavřenou kapitolu vývoje. Základ tvoří systém modifikátorů…

$name = "Sinead O'Connor";
$age = "41";

dibi::query('
    SELECT *
    FROM [people]
    WHERE [name]=%s', $name, 'AND [age]>%i', $age
);

// SQLite driver ->
//   SELECT * FROM [people] WHERE [name]='Sinead O''Connor' AND [age]>41
// MySQL driver ->
//   SELECT * FROM `people` WHERE `name`='Sinead O\'Connor' AND `age`>41

…a operace nad poli i políčky:

dibi::query('INSERT INTO `people`', array(
    'name' => $name,
    'active' => TRUE,
    'password' => hash('md5', 'nbusr123'),
));

// SQLite -> INSERT INTO [people] ([name], [active], [password])
//  VALUES ('Sinead O''Connor', 1, 'c2750a7d522eb4df4e842980ed3f3e78')
//
// PostgreSQL -> INSERT INTO "people" ("name", "active", "password")
//  VALUES ('Sinead O''Connor', TRUE, 'c2750a7d522eb4df4e842980ed3f3e78')

Dibi také disponuje podporou transakcí, má tzv. podmíněné modifikátory (ale váhám, zda je nezrušit) a pomocníka pro aplikování limitu či offsetu do SQL dotazu. Podrobnější informace o psaní SQL příkazů najdete ve zmíněném článku.

Tip: pokud nechce používat SQL asistenta, vykonávejte příkazy metodou dibi::nativeQuery(...SQL...). Pokud si naopak chcete asistenta vyzkoušet a neprovádět žádné příkazy, zkuste dibi::test(...SQL...).

A ještě jeden: dibi umí zobrazit SQL příkaz s obarvenou syntaxí:

$sql = 'DELETE * FROM [catalog]';
dibi::dump($sql);

dibi::dump(); // bez parametru: zobrazí posledně vykonaný příkaz

3) zapouzdřit result-set a asistovat při zpracování

Po dotazu následuje odpověď a tou je buď TRUE (u příkazů INSERT, UPDATE, …), množina výsledků (SELECT, DESCRIBE, EXPLAIN) nebo výjimka.

U množiny výsledků se zastavím. Přesněji řečeno u objektu, který ji reprezentuje.

$res = dibi::query('SELECT ...');

// můžeme ji číst po řádcích:
while ($row = $res->fetch()) {
   ...
}

// nebo ráz naráz:
$table = $res->fetchAll();

// lze nad ní iterovat:
foreach ($res as $row) ...

// a je možné dokonce rozsah iterace omezit:
foreach ($res->getIterator(3, 5) as $row) ...

// užitečná je i metoda pro získání hodnoty prvního sloupce:
dibi::query('SELECT [name] FROM ...')->fetchSingle();

Statická třída dibi umí cestu k výsledkům ještě zkrátit. Místo dibi::query()->fetch() je možné psát dibi::fetch()

$row = dibi::fetch('SELECT ...');

$field = dibi::fetchSingle('SELECT ...');

$table = dibi::fetchAll('SELECT ...');

Experimentálně jsem zkusil do dibi implementovat práci s automatickým přetypováním vrácených výsledků podle metadat, ale sám to nepoužívám.

Skutečným killerem jsou nenápadné metody fetchPairs() a především fetchAssoc(). První z nich vrátí výsledek v podobě asociativního pole ve tvaru key => value. Který sloupec představuje klíč a který hodnotu je možné volitelně specifikovat parametry.

$pairs = dibi::query('SELECT [name], [age] FROM [people]')->fetchPairs();
// --> array(
//   'Jane Doe' => 25,
//   'John Doe' => 29,
//   ...

Splněným mokrým snem programátorů je však fetchAssoc. Máte SQL dotaz spojující několik tabulek s různými typy vazeb. Databáze z toho udělá prachobyčejnou plochou tabulku. fetchAssoc jí vrátí přirozený tvar a krásu.

Příklad. Mějme tabulku zákazníků a objednávek (vazba N:M) a položíme dotaz:

$res = dibi::query('
  SELECT customer_id, customers.name, order_id, orders.number, ...
  FROM customers
  INNER JOIN orders USING (customer_id)
  WHERE ...
');

A rádi bychom získali vnořené asociativní pole podle ID zákazníka a poté podle ID objednávky:

$all = $res->fetchAssoc('customer_id,order_id');

// budeme jej procházet takto:
foreach ($all as $customerId => $orders) {
   foreach ($orders as $orderId => $order) {
       ...
   }
}

Asociativní deskriptor má obdobnou syntax, jako když pole píšete pomocí přiřazení v PHP. Tedy 'customer_id,order_id' představuje sérii přiřazení $all[$customerId][$orderId] = $row;, postupně pro všechny řádky.

Někdy by se hodilo, aby se asociovalo podle jména zákazníka namísto jeho ID:

$all = $res->fetchAssoc('name,order_id');

// k prvkům pak přistupujeme třeba takto:
$order = $all['Arnold Rimmer'][$orderId];

Co když ale existuje více zákazníků se stejným jménem? Tabulka by měla mít spíš tvar:

$data = $all['Arnold Rimmer'][0][...];
$data = $all['Arnold Rimmer'][1][...];
...

Rozlišujeme tedy více možných Rimmerů pomocí klasického pole. Asociativní deskriptor má opět formát podobný přiřazování, s tím, že sekvenční pole představuje mřížka:

$all = $res->fetchAssoc('name,#,order_id');

// iterujeme všechny Arnoldy ve výsledcích
foreach ($all['Arnold Rimmer'] as $arnoldOrders) {
   foreach ($arnoldOrders as $orderId => $order) {
       ...
   }
}

Je to srozumitelné? Pokud ne, zkuste si to přečíst ještě jednou. Bude následovat další level.

Vrátím se k příkladu s deskriptorem 'customer_id,order_id' a zkusím vypsat objednávky jednotlivých zákazníků:

$all = $res->fetchAssoc('customer_id,order_id');

foreach ($all as $customerId => $orders) {
   echo "Objednávky zákazníka $customerId":

   foreach ($orders as $orderId => $order) {
       echo 'Číslo dokladu: ',  $order['number'];
       // jméno zákazníka je v $order['name'];
   }
}

Bylo by hezké místo ID zákazníka vypsat jeho jméno. Jenže to bych musel dohledávat v poli $orders. Docela by se šiklo, kdyby výsledky byly v takovémto nějakém tvaru:

$all[$customerId]['name'] = "John Doe";
$all[$customerId]['order_id'][$orderId] = $row;
$all[$customerId]['order_id'][$orderId2] = $row2;

Tedy mezi $customerId a $orderId vrazit ještě mezičlánek. Tentokrát ne číslované indexy, jaké jsem použil pro odlišení jednotlivých Rimmerů, ale rovnou databázový záznam. Řešení je velmi podobné, jen si stačí zapamatovat, že záznam symbolizuje rovnítko:

$all = $res->fetchAssoc('customer_id,=,order_id');

foreach ($all as $customerId => $record) {
   echo "Objednávky zákazníka $record[name]":

   foreach ($record['order_id'] as $orderId => $order) {
       echo 'Číslo dokladu: ',  $order['number'];
   }
}

Docela by mě zajímalo, jestli jste teď zmatení nebo nadšení :-) Asociativní deskriptor je úžasně trefný způsob, jak popsat strukturu libovolně složitého vnořeného pole, jenže uvažovat v několika rozměrech dává lidskému mozku docela zabrat. Přiznám se, že sám občas docela tápu. Celá nápad s deskriptory a realizaci metody fetchAssoc připisuji nějakému vyššímu vnuknutí, protože ji pokaždé musím vstřebávat znovu a znovu. Ano, tento článek si píšu jako tahák pro vlastní kód :-)

Tip: při ladění aplikace se může hodit vykreslení množiny výsledků v podobě HTML tabulky:

$res = dibi::query('SELECT ...');
$res->dump();

Téměř v cíli

Teď pracuji na logování a profilování provozu. Dibi umožní volat před a po každém SQL příkazu handler, takže bude možné sledovat provoz vlastními nástroji. Stejně jako celé dibi, tak i tato funkčnost se rodí a formuje za chodu. S tím, jak zjišťuji, co vlastně potřebuji a co mi nejlépe vyhovuje. Trvá to sice déle, ale jen tak může vzniknout skutečně užitečný nástroj.

A co Active Record, Object-relational mapping? Dibi bylo zamýšleno jinak, jako pomocník při psaní SQL příkazů. Faktem je, že by mohlo fungovat i jako spolehlivá low-level vrstva pro ORM nadstavbu, ale nemám v plánu to programovat. Tyto techniky sice elegantně řeší určitou sortu úloh, ale vybírají si za to daň v podobě zcela nových problémů. Nejsem jejich fanda (toho času).

Co dibi versus PDO? Obojí jsou data-access abstraction layer, liší se však v jedné podstatné věci: dibi je. Kdežto narazit na hosting s pdo_mysql je úkol hodný zlatokopa. Navíc po dvou letech vývoje mi dibi vyhovuje natolik, že přejít k PDO by byl skok zpět (dokonce i výkonostní). V PDO také chybí některé důležité funkce, např. vyznačení identifikátorů. Stále jej považuji za nedodělek, nicméně má budoucnost jistou, proto existuje PDO driver pro dibi.

Jo, a ještě licence. Dibi šířím pod Dibi licencí (překlad), což je licence ve stylu velmi volné BSD, přidal jsem však několik omezení navíc, které se běžných uživatelů nedotknou. Dibi můžete použít prakticky v jakémkoliv projektu (komerčním, nekomerčním), nesmíte však odstranit nebo zatajit copyrighty. To byste se nedostali do nebe!

Download dibi 70kB

Komentáře RSS 2.0 komentářů » přidat

avatar

#1 Jakub Lucký http://blog.cxl.cz nový

>> To byste se nedostali do nebe!
Pokud narážíš na Švejka, tak tam je: To by vás ani nesměli pohřbít na hřbitově! (Scéna s Janem Marvanem jako velitelem četnické stanice a jejich posluhovačkou)

Jinak dibi licence vypadá velmi dobře, protože nejde o úchylné GPL ale rozumné BSD

Posláno 9. 11. 2007 v 1.22 | Odpovědět
Na komentář reagoval [13] tark
avatar

#2 Ivan http://www.gastrojob.sk nový

Tejto vety sa stale desim: Hledání správné‚n‘kůl syntaxe trvalo nesmírně dlouho a dodnes nejde o uzavřenou kapitolu vývoje.

BTW: ako to, ze tato kadibudka nema PR, je v tom nejaka certovina?

Posláno 9. 11. 2007 v 7.52 | Odpovědět
Na komentář reagoval [15] David Grudl

#3 Tom nový

hip hip hurá, na tohle se těším víc než na Vánoce :)

Posláno 9. 11. 2007 v 8.44 | Odpovědět
Na komentář reagoval [15] David Grudl

#4 Milan nový

No ještě dokončit Nette a bude to paráda

Posláno 9. 11. 2007 v 9.36 | Odpovědět
Na komentář reagoval [6] veena

#5 Honza nový

Super práce, díky.

Posláno 9. 11. 2007 v 9.51 | Odpovědět

#6 veena nový

#4 Milan: Nechcete někdo přeložit článek http://phpfashion.com/…bazovy-layer do angličtiny a přidat k němu zpracování odpovědi z tohoto článku?
Ať má David čas na programování? :-)

Posláno 9. 11. 2007 v 11.38 | Odpovědět
Na komentář reagoval [13] tark [15] David Grudl

#7 veena nový

S tim fetchAssoc je to skvělý nápad. Před prvním použitím bych si to sice musel znovat přečíst, ale chápu, o co ti jde. A věřim, že to rychle přeleze do krve.

V této souvislosti mě napadlo toto. Když má člověk model typicky jako objekty, tak by se mu hodilo aby tam bylo i něco jako fetchObject(), které by nacpalo výsledek do atributů objektu.
Což by chtělo zas nějak pěkně pořešit výsledek ze spojených tabulek, že se třeba instancují objekty do pole…

Příklad by pak mohl vypadat takto:

$res = dibi::query('
  SELECT customer_id, customers.name, order_id, orders.number, ...
  FROM customers
  INNER JOIN orders USING (customer_id)
  WHERE ...
');

Získaní dat:

$customers = $res->fetchObject('customer_id,order_id');

Struktura metody fetchObject by mohla vypadat nějak takhle:

function fetchObj() {
$customers = array();
$i = 0;
while ($row = $this->res->fetch()) {
  $customers[$i] = new Customer($row['customer_id']);
/* nebo variata takhle:
  $customers[$row['customer_id']] = new Customer($row['customer_id']);
*/
  $customers->setName($row['name']);
  $customers->orders = array();
  for ($j = 0; $j < pocet objednavek; $j++) {
    $customers->orders[$j] = new Order($row['order_id']);
    $customers->orders[$j]->setNumber($row['number']);
  }
  $i++
}
return $customers;
}

// budeme jej procházet takto:
foreach ($customers as $customer) {
   foreach ($customer->orders as $order) {
       ...
   }
}

Ještě by se mohla mít metoda fetchObj() volitelné parametry jestli instancovat třídy (a jaké na které idčka) pomocí new, nebo jestli získat objekt pomocí (tovární) metody. A které atributy nastavit set metodama a které narvat přímo do konstruktoru.

Neni to ORM a přitom dostaneš výsledek jako bys použil ORM :-) A nemusíš se trápit s ruční jednotvárnou prací vytvářenim objektů po každym selektu (opruz :-(

Pak by byl new Order nastolen ;-)

Posláno 9. 11. 2007 v 11.50 | Odpovědět
Na komentář reagoval [9] rarouš [16] David Grudl
avatar

#8 Taco taco@taco-beru.name nový

Mám takový pocit, že už nejsi tak kategoricky proti ORM jako na začátku. Že by jsi při svém vývoji dibi narazil na její omezení? :-P

Posláno 9. 11. 2007 v 11.53 | Odpovědět
avatar

#9 rarouš http://www.rarous.net/ nový

#7 veena: to co navrhuješ je ORM, ne že neni.

Posláno 9. 11. 2007 ve 13.06 | Odpovědět
Na komentář reagoval [11] veena

#10 veena nový

[12222] nejsem si jistý, jestli to, co píšete, se dá hodit právě na dibi. Jak tuhle knihovnu chápu, tak si můžete napsat libovolný sql příkaz.

S různě formátovanými daty (i datumy) v různých db enginech by právě mělo dibi pomoci. Viz odstavec modifikátory v dokumentaci dibi na:
http://phpfashion.com/…bazovy-layer
Jasně asi Vám to příliš nepomůže s procedurami, rozšířeními SQL jazyka apod. To ale Vámi zmiňované knihovny také ne.

PDO je povedený nástroj v php. Ale není to database abstraction layer ale data-access abstraction layer. Takže s úpravou sql dotazů pro různé db enginy vám nepomůže.
Nicméně jak David dneska popsal, zaimplementoval i experimentální adaptér na PDO.

Ze začátku jsem byl k dibi skeptický. Nyní ale oceňuji dobrý návrh a užitečné funkce, které programátorům šetří čas. Pokud myslíte, že vám ne, tak to samozřejmě nepoužívejte.

Posláno 9. 11. 2007 ve 13.19 | Odpovědět
Na komentář reagoval [15] David Grudl

#11 veena nový

#9 rarouš: Já myslim, že ne. ORM by mělo fungovat obousměrně. O->R i R->O. V ORM nepíšeš žádný SQL dotaz, ale voláš metodu mapperu, která pozná, jaké SQL má zkonstruovat.

To, co navrhuju, je „jen“ jednosměrný mapper výsledku do objektů. R->O.

Posláno 9. 11. 2007 ve 13.23 | Odpovědět
Na komentář reagoval [30] rarouš
avatar

#12 David Majda http://www.majda.cz/ nový

„Po dotazu následuje odpověď a tou je buď TRUE (u příkazů INSERT, UPDATE, …)“

A nebylo by lepší vracet automatické ID vloženého/upra­vovaného záznamu, existuje-li? Docela se to hodí v případě, kdy s ním potřebuju dál pracovat (vložím záznam a pak chci vložit další záznamy do jiné tabulky, která je s tou původní v relaci 1:N nebo N:M).

Posláno 9. 11. 2007 v 16.47 | Odpovědět
Na komentář reagoval [15] David Grudl [26] Milan Svoboda
avatar

#13 tark miroslav.navratil@gmail.com nový

Vypadá to fajnově, nemůžu se dočkat, až vyzkouším kombinaci Dibi + Texy + Nette. Nemáš v záloze ještě nějaký sexy projekt? ;)

#1 Jakub Lucký: JJ, GPL je úchylné, pokud není (např. jako u Texy!) možnost použít jinou licenci v uzavřené aplikaci… Pak má člověk chuť aplikaci pro jistotu nepoužít, protože pak není možnost distribuovat aplikaci jinak, třeba komerčně pro klienty s uzavřeným zdrojákem a tak.

#6 veena: Já bych to klidně udělal, jenže problém je v tom, že anglicky nějak moc neumím, takže bych Davidovi udělal leda ostudu :-)

Posláno 9. 11. 2007 ve 20.34 | Odpovědět
Na komentář reagoval [15] David Grudl
avatar

#14 Keff http://www.tomaskafka.com nový

DGX, můžu se zeptat jaké jsou ty problémy které ORM přináší? Momentálně jsem ve stadiu téměř nekritického nadšení a upravil jsem si jeden malý ORM framework, ale rád bych věděl co mě čeká :)

Posláno 9. 11. 2007 ve 22.10 | Odpovědět
Na komentář reagoval [15] David Grudl
avatar

#15 David Grudl http://davidgrudl.com nový

#2 Ivan: obáváš se toho kvůli nekompatibilitě? Už mi dibi běží na tolika projektech, že bych do toho nešáhl.

#3 Tom: ovšem to bude chyba ve výchově a rodiném zázemí :-)

#6 veena: vydržte, chodili by mi sem lidi ;)

#10 veena: joj, než jsem si všiml, že reaguješ, tak doběhl Indiana Jones a pána smazal… On je někdy strašně ukvapený, kluk ušatá.

#12 David Majda: nad tím jsem váhal, ale nakonec ve prospěch čitelnosti kódu aplikací, které dibi používají, to zavrhl. Nehledě na další problémy s tím spojené (jak zjistit který SQL dotaz ID vrací, co když je dotazů víc, jak to řešit u databází s odlišným přístupem, atd). Nad čím ale uvažuju, tak je fluent interface a vracení $this.

#13 tark: obvykle je nejjednodušší napsat autorovi a domluvit se s ním. GPL vůbec nezavrhuji, jen mám pocit, že se pro tento typ knihovny nehodí.

#14 Keff: to je značně subjektivní. Souvisí to s pocitem, kdy se dostaneš do situace, kterou bys uměl hned a snadno vyřešit v SQL, ale s ORM je to hodně složitější. Nebo budeš muset zoptimalizovat operace nad databází, v SQL by věděl hned, ale s ORM to třeba vůbec nepůjde.

Posláno 10. 11. 2007 ve 2.01 | Odpovědět
Na komentář reagoval [17] tark
avatar

#16 David Grudl http://davidgrudl.com nový

#7 veena: tak teď si ale držte klouboky :-)

// znáte od tvůrců jazyka JavaScript
function DibiResult_prototype_fetchObject(DibiResult $obj, $param, $param, ...)
{
    $customers = array();
    ... // Veenův kód
    return $customers;
}

$res = dibi::query('
    SELECT customer_id, customers.name, order_id, ...
    FROM customers
    INNER JOIN orders USING (customer_id)
');

$customers = $res->fetchObject('customer_id,order_id');
// $customers je naplněn tvou metodou!

Jinými slovy, můžete si přidávat vlastní metody do každé třídy dibi (tedy nestatické). Naznačoval jsem to na frameworkové konferenci, v dibi už to běží naostro.

Takže pokud ráčíte používat třeba novou fetch metodu, netřeba mě přesvědčovat o její implementaci, snadno si ji doplníte sami :-)

Posláno 10. 11. 2007 ve 2.15 | Odpovědět
Na komentář reagoval [17] tark [20] veena
avatar

#17 tark miroslav.navratil@gmail.com nový

#15 David Grudl: Jo, to je pravda, to mi nedošlo ;)

#16 David Grudl: Fajné a pěkné ;)

Posláno 10. 11. 2007 v 9.33 | Odpovědět
avatar

#18 Dundee http://blog.milde.cz nový

Ta funkce fetchAssoc vypadá opravdu zajímavě. Nikdy mě nic podobného nenapadlo.

Posláno 10. 11. 2007 v 16.01 | Odpovědět

#19 Inza nový

Problematika DB se nám teď, ze dne na den, posunula na novou úroveň. Fascinující. Velmi se těším:-) – Jestli se o někom z naší republiky dá říct že UMÍ programovat v PHP, tak je to David – On není jako my ostatní, co se v tom jen patláme:-)…on programuje vysoko, kam mi nedosáhneme – o důvod víc, proč ho podporovat:-) – jen tak dál!!

Posláno 11. 11. 2007 v 9.37 | Odpovědět

#20 veena nový

#16 David Grudl: kurňa, teď nevím, jestli mám jásat, nebo plakat, že si to musím naprogramovat sám ;-D

Posláno 11. 11. 2007 ve 12.52 | Odpovědět
avatar

#21 johno http://johno.jsmf.net/ nový

Čo mi dáte, keď nad DiBi spravím pekný, malý a šikovný OR mapper?

Posláno 11. 11. 2007 v 15.33 | Odpovědět
Na komentář reagoval [22] tark [23] David Grudl [25] veena
avatar

#22 tark miroslav.navratil@gmail.com nový

#21 johno: To je co, smím-li se zeptat? ;)

Posláno 11. 11. 2007 v 19.28 | Odpovědět
Na komentář reagoval [24] johno
avatar

#23 David Grudl http://davidgrudl.com nový

#21 johno: polovina ekonomického zisku z dibi je tvá :-)

(pak ti pošlu své číslo účtu, abysme se vyrovnali)

Posláno 11. 11. 2007 ve 20.08 | Odpovědět
Na komentář reagoval [24] johno
avatar

#24 johno http://johno.jsmf.net/ nový

#22 tark: Počkejte, ttto to jsem se měl přece zeptat já.

#23 David Grudl: Pričom, ten prevod peňazí by ma stál asi najviac.

Posláno 11. 11. 2007 ve 22.34 | Odpovědět

#25 veena nový

#21 johno: johno podvádí, von už to má vymyšlený dopředu ;-)

P.S. jdi do toho!

Posláno 11. 11. 2007 ve 23.40 | Odpovědět

#26 Milan Svoboda nový

#12 David Majda: To co navrhuješ není zase tak triviální. Některé DB systémy jsou takovou informaci schopny vracet, ale bohužel najdou se i systémy, které pokud tě ID zajímá musíš ho nejdříve získat a poté teprve s ním pracovat, tzn. musíš ho použít přímo do insertu.

Posláno 12. 11. 2007 v 8.38 | Odpovědět
avatar

#27 David Grudl http://davidgrudl.com nový

Aktualizace: do článku jsem doplnil odstaveček na téma „dibi vs. PDO“ a pět praktických tipů ze života dibaře

Posláno 12. 11. 2007 v 10.48 | Odpovědět
avatar

#28 Tomik http://tomik.jmx.cz nový

Davide, moc se mi to líbí! Zatím jsem to nikde nepoužil, ale už se vyloženě těším. :-)

Kdyby se rozdávali Nobelovy ceny za PHP, byl bych svými všemi 104 klávesami pro udělení té ceny Tobě.

Posláno 13. 11. 2007 v 11.12 | Odpovědět
avatar

#29 Tomas Lembacher tomas.lembacher@seznam.cz nový

Ahoj, nevim jestli to tu uz nekdo napsal, nebo jestli jste na to uz nahodou neprisel…ale mam pocit, ze jsem nasel malou chybu ve zdrojovem kodu dibi. V souboru DibiTranslator.php na radku 116 jsem presvedcen, ze by misto „REPLAC“ melo byt „REPLACE“.

S pozdravem
Tomas Lembacher

Posláno 14. 11. 2007 v 10.39 | Odpovědět
Na komentář reagoval [32] David Grudl
avatar

#30 rarouš http://www.rarous.net/ nový

#11 veena: ORM je proces při kterém mapuješ relační data na objekty či naopak. Je celkem fuk, jestli k tomu použiješ nějakej framework (mapper) nebo všechno uděláš růčo. Tak či tak jde o ORM.

Posláno 14. 11. 2007 v 11.40 | Odpovědět
avatar

#31 Washo http://washo.glum.cz nový

Jak je to s chybovosti? Docela me zklamalo, kdyz jsem zahodil PHPDoctrine, protoze jsem prisel kazdou chvili na chyby, ktere me nastvaly. Znate to: Pouzivate cizi kod, nevite jestli chybu delate vy a nebo knihovna ⇒ nekolik hodin v haji kvuli blbosti.

Chtel jsem se proto zeptat o kolika chybach vis, resp. kolik jich ocekavas?

Posláno 14. 11. 2007 v 16.04 | Odpovědět
Na komentář reagoval [32] David Grudl
avatar

#32 David Grudl http://davidgrudl.com nový

#29 Tomas Lembacher: díky za report, ale chyba to není.

#31 Washo: dibi sem o nějaké věděl, tak bych ji už opravil

Posláno 15. 11. 2007 v 0.02 | Odpovědět
avatar

#33 Pavel Stehule http://www.pgsql.cz nový

Ahoj.

podporuje to prepared statements? Mám na mysli hlavně Asistenta?

Posláno 15. 11. 2007 v 9.55 | Odpovědět
Na komentář reagoval [34] David Grudl
avatar

#34 David Grudl http://davidgrudl.com nový

#33 Pavel Stehule: prepared statements podporované nejsou, vysvětlení zde. Technicky není problém je do knihovny přidat, ale smysl v tom nevidím.

(prepared statements prý v MySQL zhoršují výkon)

Posláno 15. 11. 2007 ve 12.17 | Odpovědět

#35 Michal Till http://www.json.cz nový

Velmi pěkné!

Mě se ještě často hodí funkce, co vrátí jednu jedinou hodnotu z SQL výsledku, něco jako

$count = dibi::fetchVa­lue(„SELECT count(id) FROM …“);

Posláno 17. 11. 2007 v 15.18 | Odpovědět
Na komentář reagoval [37] Jan Škrášek [38] David Grudl
avatar

#36 PIF http://www.broskev.cz nový

žeru MyDateTime :))

Posláno 17. 11. 2007 v 16.59 | Odpovědět
Na komentář reagoval [38] David Grudl
avatar

#37 Jan Škrášek http://hrach.netuje.cz nový

#35 Michal Till:

// užitečná je i metoda pro získání hodnoty prvního sloupce:
dibi::query('SELECT [name] FROM ...')->fetchSingle();
Posláno 17. 11. 2007 v 18.30 | Odpovědět
avatar

#38 David Grudl http://davidgrudl.com nový

#35 Michal Till: dibi::fetch($sql), dibi::fetchSin­gle($sql) a dibi::fetchAll($sql) tam je

#36 PIF: tak dobrou chuť ;)

Posláno 18. 11. 2007 ve 2.13 | Odpovědět
avatar

#39 Luke luke@luke.sk nový

Nefungoval mi driver postgre a tak po úprave súboru v drivers, konkretne >

$this->connection = @pg_pconnect("host=".$config['host']." user=".$config['username']." password=".$config['password']." dbname=".$config['database'], PGSQL_CONNECT_FORCE_NEW);

to už ide … neviem ci to bolo spôsobené len tým že som sa pripájal na iný host alebo či si len robil dáke zmeny a na tento driver si zabudol.

Posláno 23. 11. 2007 v 15.02 | Odpovědět
Na komentář reagoval [40] David Grudl
avatar

#40 David Grudl http://davidgrudl.com nový

#39 Luke: no, já předávám funkci pg_connect přímo ten poskládaný connection_string, ale asi by nebylo špatné přidat i skládací funkci. Tak zkus aktuální verzi:

dibi::connect(array(
    'driver'     => 'postgre',
    'host'       => 'localhost',
    'port'       => 5432,
    'dbname'     => 'mary',
));
Posláno 24. 11. 2007 v 0.28 | Odpovědět
Na komentář reagoval [46] Luke

#41 Mastodont nový

No já tedy nevím, ale „správnou a cool syntaxi“ psaní SQL dotazů bych si představoval úplně jinak. O asistenci se taky moc mluvit nedá.

Když už, tak bych si nepomáhal jednou metodou, ale používal bych jich víc:

dao->getAllRows("orders", Array("id", "date"));
// = select id, date from orders
dao->getSomeRows("orders", Array("id", "date",), "customer_id", 6);
// = select id, date from orders where customer_id = 6)

A pokud se týká zpracování výsledků, tak to by měla být starost jiné třídy, ne db layeru. Přičemž rozhraní mezi třídami tvoří result.

echo formatter::Table(dao->getRows(...));
Posláno 24. 11. 2007 v 16.08 | Odpovědět
Na komentář reagoval [42] David Grudl
avatar

#42 David Grudl http://davidgrudl.com nový

#41 Mastodont: jenže to už není „psaní SQL dotazů“. Všimni si podstatné věci – tvůj zápis je delší a mnohem méně intuitivní, než pod tím vygenerovaný SQL příkaz. Proto to hodnotím jako krok zpět (viz Zlo si říká Database Abstraction Layer). Jdu jinou cestou, která tu přímočarost SQL příkazů zachovává.

Experimentuji taky s více inteligentním zapouzdřením příkazů SELECT, INSERT nebo UPDATE, vlastně už pár let, ale stále nejsem spokojen.

ad zpracování výsledků: dibi samozřejmě končí u poskytnutí resultu, výsledky nezpracovává.

Posláno 25. 11. 2007 v 1.15 | Odpovědět
avatar

#43 Honza M. http://texyla.jaknato.com/ nový

Fatal error: Class ‚NClass‘ not found in C:\…\dibi.com­pact.php on line 326.

Kde vezmu NClass? Bývalo to v souboru NObject.php, ale teď už se asi NClass nevyrábí…

Posláno 25. 11. 2007 v 19.50 | Odpovědět
Na komentář reagoval [44] David Grudl
avatar

#44 David Grudl http://davidgrudl.com nový

#43 Honza M.: divné, nic se totiž neměnilo. Zkus stáhnout aktuální verzi. Podívat se, jestli to nekoliduje s jinou třídou, jiným souborem…

(update: NClass je nyní v samostatném souboru, ale stále součástí dibi.compact.php)

Posláno 25. 11. 2007 ve 21.22 | Odpovědět
Na komentář reagoval [45] Honza M.
avatar

#45 Honza M. http://texyla.jaknato.com/ nový

#44 David Grudl: Tlouklo se mi to se souborem NObject.php z NFormů…
Doufám, že tyhlety NObejcty a NClassy od dibi a NForm jsou navzájem kompatibilní :-D Zatim to vypadá dobře.

Posláno 26. 11. 2007 v 10.28 | Odpovědět
avatar

#46 Luke luke@luke.sk nový

#40 David Grudl: To som samozrejme skúsil a nešlo to, overil som to teraz ešte raz … podla mňa je asi problém v skladaní toho connection stringu, kde názov databázy je s podtržítkom … aspon z vyhodenej výnimky tomu tak rozumiem …

Posláno 3. 12. 2007 v 9.31 | Odpovědět
avatar

#47 Luke luke@luke.sk nový

A neviem ci mam niekde chybu, ale nevracia mi insertId posledne idcko, ak je postgre verzia 8.0 …

Posláno 7. 12. 2007 ve 14.43 | Odpovědět
Na komentář reagoval [48] David Grudl
avatar

#48 David Grudl http://davidgrudl.com nový

#47 Luke: v postgre se používá dibi::insertId($sequenceName);. Každopádně si stáhni poslední verzi, v rev. 99 byl bug.

Posláno 7. 12. 2007 v 15.23 | Odpovědět

#49 liquid nový

Ahoj,
mám takovej problém s regexp, tak mi tu snad někdo poradí. Přepsal jsem si dibi do C++, ale umí to zatím jenom nativeQuery. Chtěl bych udělat i query, ale nemůžu se poprat s jedním použitým regexp v C++. Konkrétně se jedná o tenhleten:

preg_replace_ca­llback(
‚/(?=|\[|\'|"|%)(?:(.+?)`|\[(.+?)\]|(\‘)(­(?:\‚\‘|[^\‚]))\‘|(„)((?­:""|[^“]))„|%(el­se|end)|%([a-zA-Z]{1,3})$|(\‚­|“))/s‘,
array($this, ‚cb‘),
substr($value, $toSkip)
 );

umístěný v Translatoru. Díky za každej tip, kterej mi to pomůze vyřešit.

Posláno 18. 12. 2007 v 17.27 | Odpovědět
avatar

#50 Honza M. http://texyla.jaknato.com/ nový

Ahoj, jako vždy mám geniální nápad… Co kdyby dibi umělo vybírat více položek podle pole.

$res = dibi::query("select * from [table] where [id]=%or", array(1, 6, 7, 4));
// select * from `table` where (`id`=1 or `id`=6 or `id`=7 or `id`=4)

// nebo

$res = dibi::query("select * from [table] where [id]=%and", array(1, 6, 7, 4));
// select * from `table` where (`id`=1 and `id`=6 and `id`=7 and `id`=4)

Jistě by to bylo prospěšné, teď to řeším jakousi externí funkcí.

$res = dibi::query("select * from [table] where " . sqlOr("id", array(1, 6, 7, 4))); // nebo sqlOr("id", "1,6,7,4");
Posláno 22. 12. 2007 v 11.06 | Odpovědět
Na komentář reagoval [51] David Grudl
avatar

#51 David Grudl http://davidgrudl.com nový

#50 Honza M.: to lze:

$res = dibi::query("
select *
from [table]
where [id] IN ", array(1, 6, 7, 4)
);
Posláno 22. 12. 2007 v 11.47 | Odpovědět

#52 Finwe http://weblog.finwe.info nový

Mám nějakou možnost zjistit (nejlépe při volání dibi::dump()), na kterém řádku v mém kódu byla volána metoda dibi::query(), resp. dibi::fetch() a ostatní?

přidávám si (za určitých podmínek pro testování) handler

function dumpAfterQuery() {
        dibi::dump();
}

a tam by se toto značně hodilo

Posláno 10. 1. 2008 v 11.35 | Odpovědět
Na komentář reagoval [53] David Grudl [55] Finwe
avatar

#53 David Grudl http://davidgrudl.com nový

#52 Finwe: zkus analyzovat debug_backtrace.

Posláno 10. 1. 2008 ve 12.43 | Odpovědět
Na komentář reagoval [54] Finwe

#54 Finwe http://weblog.finwe.info nový

#53 David Grudl: No jasně, tam je pod klíčem 5, myslel jsem, jestli to dibi neumí nějak interně.

Systém handlerů je boží a bude ještě víc, až bude hotov a zdokumentován :) Takhle se mi ta query dumpuje dvakrát…

Posláno 10. 1. 2008 v 15.10 | Odpovědět

#55 Finwe http://weblog.finwe.info nový

Zatím asi ideální řešení na #52 Finwe: je subclassovat dibi. Například takto:

class db extends dibi
{

        public static $debug = false;

        public static function setDebug($debug = true)
        {
                self::$debug = $debug;
        }


        public static function query($args)
        {
                $return = parent::query($args);

                if (self::$debug) {
                        $bt = debug_backtrace();

                        echo '<pre>';
                        echo $bt&#91;0&#93;['file'] . ':' . $bt&#91;0&#93;['line'];
                        echo '</pre>';

                        dibi::dump();
                }

                return $return;
        }
}

pokud je pak v kódu nastaveno db::setDebug(), po db::query() se vypíše dump spolu se souborem a číslem řádku.

bohužel jsem ještě nepřišel na to, jak zajistit, aby se to tak chovalo automaticky i pro metody db::fetch() a ostatní :(

Posláno 10. 1. 2008 v 15.40 | Odpovědět

#56 miloš nový

ahoj, nechcem ti to tu meniť na poradňu, ale s takýmto errorom si ako poradím? :)

Fatal error: Interface 'Countable' not found in .../www_root/dibi.compact.php on line 206

všetko čo som o interface Countable vygooglil je, že releasol vo verzii 5.1. Hmm phpversion() mi vráti 5.2.4. Niečo som zabudol, alebo som hlúpy? :). Na localhoste mi to beži, na webe nie.
Všetko čo robím je: dibi::connect(…)

Ďakujem za prípadné odpovede.

Posláno 12. 1. 2008 v 5.11 | Odpovědět
Na komentář reagoval [57] David Grudl
avatar

#57 David Grudl http://davidgrudl.com nový

#56 miloš: leda že jde o nějaký obskurní hosting, na kterém není SPL. Poznáš to z phpinfo()

Posláno 12. 1. 2008 v 6.32 | Odpovědět

#58 Finwe http://weblog.finwe.info nový

Podle toho, co jsem zjistil, načítá dibi drivery sama a používá k tomu class_exists – tato funkce ovšem defaultně používá autoload, a to může aplikaci s pro dibi netypickým formátem autoloadu solidně zmást. Pokud tedy nemám explicitně spolu s dibi requirovat php soubor ovladače, nebylo by lepší místo

if (!class_exists($class)) {

použít

if (!class_exists($class, false)) {

?

Jde o soubor DibiConnection.php:77 rev. 104 (v revizi 110 je to stejně)

Posláno 13. 2. 2008 ve 12.56 | Odpovědět
Na komentář reagoval [59] David Grudl
avatar

#59 David Grudl http://davidgrudl.com nový

#58 Finwe: to je správná připomínka, false tam skutečné chybí. Jen nějak nerozumím tomu zmatení a netypickému formátu autoloadu…

Posláno 13. 2. 2008 ve 23.45 | Odpovědět
Na komentář reagoval [60] Finwe

#60 Finwe http://weblog.finwe.info nový

#59 David Grudl: Zmást = nechat vyhodit fatal error :-) A netypický = „blbý“ (například ve stylu „očekávám třídu ve formátu {classname}.class.php a ne jinak“).

Nic víc :-)

Posláno 14. 2. 2008 v 10.09 | Odpovědět
avatar

#61 Petr petr.dana@gmail.com nový

Ahoj, narazil jsem na drobný problém, a sice, jak se při výjímce dostat k číselnému kódu poslední chyby? Konkrétně u ovladače pro sqlite. Jde o PHP funkci sqlite_last_error, eventuelně metodu SQLiteDatabase->lastError(). Prolezl jsem zdrojáky i dokumentaci API, ale žádnou cestu jsem nenašel :(

Posláno 20. 2. 2008 v 19.57 | Odpovědět

Tento článek byl uzavřen. Už není možné k němu přidávat komentáře ani hlasovat

Výtah na začátek článku na první komentář

Názory čtenářů v diskusích nejsou názory provozovatele webu, a ten za jejich obsah neodpovídá.

phpFashion © 2004, 2010 David Grudlo webu

Pokud není uvedeno jinak, podléhá obsah těchto stránek licenci Creative Commons BY-NC-ND Creative Commons License BY-NC-ND

Ukázky zdrojových kódů smíte používat s uvedením autora a URL tohoto webu bez dalších omezení.