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!
Komentáře
Jakub Lucký #1
>> 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
Ivan #2
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?
Tom #3
hip hip hurá, na tohle se těším víc než na Vánoce :)
Milan #4
No ještě dokončit Nette a bude to paráda
Honza #5
Super práce, díky.
veena #6
#4 Milane, Nechcete někdo přeložit článek https://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í? 🙂
veena #7
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:
Získaní dat:
Struktura metody fetchObject by mohla vypadat nějak takhle:
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 😉
Taco #8
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í? 😛
rarouš #9
#7 veeno, to co navrhuješ je ORM, ne že neni.
veena #10
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:
https://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.
veena #11
#9 rarouši, 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.
David Majda #12
„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/upravované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).
tark #13
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 Jakube 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 veeno, 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 🙂
Keff #14
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á :)
David Grudl #15
#2 Ivane, obáváš se toho kvůli nekompatibilitě? Už mi dibi běží na tolika projektech, že bych do toho nešáhl.
#3 Tome, ovšem to bude chyba ve výchově a rodiném zázemí 🙂
#6 veeno, vydržte, chodili by mi sem lidi ;)
#10 veeno, 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 Davide Majdo, 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 tarku, 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 Keffe, 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.
David Grudl #16
#7 veeno, tak teď si ale držte klouboky 🙂
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 🙂
tark #17
#15 Davide Grudle, Jo, to je pravda, to mi nedošlo ;)
#16 Davide Grudle, Fajné a pěkné ;)
Dundee #18
Ta funkce fetchAssoc vypadá opravdu zajímavě. Nikdy mě nic podobného nenapadlo.
Inza #19
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!!
veena #20
#16 Davide Grudle, kurňa, teď nevím, jestli mám jásat, nebo plakat, že si to musím naprogramovat sám ;-D
johno #21
Čo mi dáte, keď nad DiBi spravím pekný, malý a šikovný OR mapper?
tark #22
#21 johno, To je co, smím-li se zeptat? ;)
David Grudl #23
#21 johno, polovina ekonomického zisku z dibi je tvá 🙂
(pak ti pošlu své číslo účtu, abysme se vyrovnali)
johno #24
#22 tarku, Počkejte, ttto to jsem se měl přece zeptat já.
#23 Davide Grudle, Pričom, ten prevod peňazí by ma stál asi najviac.
veena #25
#21 johno, johno podvádí, von už to má vymyšlený dopředu 😉
P.S. jdi do toho!
Milan Svoboda #26
#12 Davide Majdo, 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.
David Grudl #27
Aktualizace: do článku jsem doplnil odstaveček na téma „dibi vs. PDO“ a pět praktických tipů ze života dibaře
Tomik #28
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ě.
Tomas Lembacher #29
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
rarouš #30
#11 veeno, 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.
Washo #31
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?
David Grudl #32
#29 Tomasi Lembachere, díky za report, ale chyba to není.
#31 Washo, dibi sem o nějaké věděl, tak bych ji už opravil
Pavel Stehule #33
Ahoj.
podporuje to prepared statements? Mám na mysli hlavně Asistenta?
David Grudl #34
#33 Pavle 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)
Michal Till #35
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::fetchValue(„SELECT count(id) FROM …“);
PIF #36
žeru MyDateTime :))
Jan Škrášek #37
#35 Michale Tille,
David Grudl #38
#35 Michale Tille, dibi::fetch($sql), dibi::fetchSingle($sql) a dibi::fetchAll($sql) tam je
#36 PIFe, tak dobrou chuť ;)
Luke #39
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.
David Grudl #40
#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:
Mastodont #41
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:
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.
David Grudl #42
#41 Mastodonte, 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á.
Honza M. #43
Fatal error: Class ‚NClass‘ not found in C:\…\dibi.compact.php on line 326.
Kde vezmu NClass? Bývalo to v souboru NObject.php, ale teď už se asi NClass nevyrábí…
David Grudl #44
#43 Honzo 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)
Honza M. #45
#44 Davide Grudle, 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í 😁 Zatim to vypadá dobře.
Luke #46
#40 Davide Grudle, 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 …
Luke #47
A neviem ci mam niekde chybu, ale nevracia mi insertId posledne idcko, ak je postgre verzia 8.0 …
David Grudl #48
#47 Luke, v postgre se používá
dibi::insertId($sequenceName);
. Každopádně si stáhni poslední verzi, v rev. 99 byl bug.liquid #49
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_callback(
‚/(?=
|\[|\'|"|%)(?:
(.+?)`|\[(.+?)\]|(\‘)((?:\‚\‘|[^\‚]))\‘|(„)((?:""|[^“]))„|%(else|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.
Honza M. #50
Ahoj, jako vždy mám geniální nápad… Co kdyby dibi umělo vybírat více položek podle pole.
Jistě by to bylo prospěšné, teď to řeším jakousi externí funkcí.
David Grudl #51
#50 Honzo M., to lze:
Finwe #52
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 metodadibi::query()
, resp.dibi::fetch()
a ostatní?přidávám si (za určitých podmínek pro testování) handler
a tam by se toto značně hodilo
David Grudl #53
#52 Finwe, zkus analyzovat debug_backtrace.
Finwe #54
#53 Davide Grudle, 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…
Finwe #55
Zatím asi ideální řešení na #52 Finwe je subclassovat dibi. Například takto:
pokud je pak v kódu nastaveno
db::setDebug()
, podb::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í :(miloš #56
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.
David Grudl #57
#56 miloši, leda že jde o nějaký obskurní hosting, na kterém není SPL. Poznáš to z
phpinfo()
Finwe #58
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ístopoužít
?
Jde o soubor
DibiConnection.php:77
rev. 104 (v revizi 110 je to stejně)David Grudl #59
#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…
Finwe #60
#59 Davide Grudle, 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 🙂
Petr #61
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 :(
Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.