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

Translate to English… Ins Deutsche übersetzen…

dibi - pokrokový databázový layer

Uplynulo sedm měsíců od doby, kdy jsem tu poprvé psal o databázovém layeru dibi. Nechtěl jsem předvádět hotové řešení, spíš otevřít diskusi. Ale místo podnětů mi přišlo několik desítek žádostí o zdrojové kódy ;)

Konečně mohu všechny žadatele potěšit. Náhledová verze je k dispozici:

Download dibi-0.9.zip (rev. 100) 70kB

Upozornění: Knihovna dibi se neustále vyvíjí. Její popis v tomto článku postupně aktualizuji, takže některé komentáře pod ním mohou být již nesouvisející. Aktuální informace najdete na webu dibiphp.com.

Řešení, které jsem navrhoval v původním článku, dnes považuji z více důvodů za překonané. Co se však nezměnilo, to jsou cíle tohoto layeru:

  • maximálně ulehčit práci programátorům. Jak?
    • zjednodušit zápis SQL příkazů, co to jen půjde
    • snadný přístup k metodám, i bez globálních proměnných
    • funkce pro několik rutinních úkonů
  • eliminovat výskyt chyby. Jak?
    • přehledný zápis SQL příkazů
  • přenositelnost mezi databázovými systémy
    • automatická podpora konvencí (escapování/slasho­vání, uvozování identifikátorů)
    • automatické formátování spec. typů, např. datum, řetězec
    • sjednocení základních fcí (připojení k db, vykonání příkazu, získání výsledku)
  • a především KISS (Keep It Simple, Stupid)
    • zachovat maximální jednoduchost
    • raději jeden geniální nápad, než 10.000 hloupých řádků kódu

A naopak záležitosti, o které mi vůbec nejde:

  • zajištění kompatibility SQL příkazů
  • emulace funkcí chybějících některým databázím
  • vytvoření bohatých knihoven plných funkcí
  • nechci konkurovat ActiveRecords apod., jde mi jen o čisté SQL

A také neřeším následující věci (a vysvětlím proč):

  • funkce pro zkoumání struktury databáze a tabulek
  • prepared SQL statements

Pokud neprogramujete aplikaci typu phpMyAdmin, tak žádné funkce na zkoumání databázové struktury nepotřebujete. Vlastně bych řekl, že jejich potřeba vypovídá o špatně navržené aplikaci. Dokud tuto funkčnost nebudu potřebovat, nebo ji nenaprogramuje někdo jiný, tak v dibi nebude ;-)

Prepared SQL statements jsem taktéž shledal zbytečnými. Proč? Především se mi nikdy nestalo, že bych v jednom skriptu volal tolikrát tentýž SQL příkaz lišící se jen v hodnotách parametrů. Za druhé se podle mých měření zrychlení dosažené pomocí prepare pohybuje v řádu procent. V reálném nasazení je tedy naprosto zanedbatelné. Oproti tomu takový vícenásobný INSERT, který dibi podporuje, umí zrychlit vkládání až tisícinásobně. A nakonec – výhody, které prepared statements přináší z programátorského hlediska, tedy pohodlné vkládání proměnných, řeší dibi výrazně lépe.

Takže pojďme se podívat, jak to celé funguje.

Připojení k databázi

Každé spojení je reprezentováno objektem DibiConnection. To komunikuje s databází přes ovladač (třída implementující IDibiDriver). Který ovladač použít zvolíme při vytváření objektu:

$options = array(
    'driver'   => 'mysql',
    'host'     => 'localhost',
    'username' => 'root',
    'password' => '***',
    'database' => 'table',
);

// v případě chyby vyhodí DibiException
$connection = new DibiConnection($options);
$connection->query('TRUNCATE `table`');

Ale na tento způsob můžete klidně zapomenout :-) Je tu totiž statický registr dibi. Ten má za úkol udržovat v globálně dostupném úložišti objekt (či objekty) spojení a nad nimi volat potřebné funkce:

dibi::connect(array(
    'driver'   => 'mysql',
    'host'     => 'localhost',
    'username' => 'root',
    'password' => '***',
    'database' => 'test',
    'charset'  => 'utf8',
));

Statická třída dibijednu báječnou výhodu – kdekoliv je po ruce. Nemusíte získávat instanci připojení, prostě napíšete dibi:: a máte vystaráno.

Není to sice obvyklé, ale může se stát, že budete v aplikaci používat více připojení, třeba k různým databázím. Pak si každé připojení pojmenujete při připojování

dibi::connect($options1, 'prvni pripojeni');
dibi::connect($options2, 'druhe pripojeni');

a kdykoliv si je buď vytáhnete z registru…

$connection = dibi::getConnection('druhe pripojeni');
$connection->query(...);

…nebo jej tzv. aktivujete a voláte přes třídu dibi:

dibi::activate('prvni pripojeni');
dibi::query(...);

Poznámka: připojování ve stylu DSN, kdy popis připojení je uložen v řetězci připomínajícím URI, se v praxi ukázalo jako nepraktické. Používám raději pole, přípustný je však i řetězec, a to ve standardizovaném formátu HTTP query.

SQL příkazy – tak to je bomba!

Přiznám se, že způsob zápisu SQL příkazů jsem hledal šíleně dlouho. Nakonec jsem dospěl k technice, která je nesmírně prostá, intuitivní a doslova návyková:

dibi::query('SELECT * FROM [table] WHERE [id] = %i', $id);

$arr = array(
    'pole' => 'hodnota',
    'bit'  => TRUE,
);
dibi::query('INSERT INTO [table]', $arr);

dibi::query('UPDATE `table` SET ', $arr, 'WHERE `id`=%i', $x);

Jak vidíte, SQL příkaz se zapisuje jako série parametrů a před vložením proměnné uvedeme modifikátor (např. %i). Pokud ho neuvedeme, zjistí se typ automaticky (samozřejmě nelze zjistit typy jako je datum apod).

Upozornění: modifikátor se musí nacházet zcela na konci řetězce.

Proměnná na naformátuje do výsledného SQL podle pravidel aktivní databáze. Tak třeba TRUE bude v MS SQL jako –1, jinde jako ‚1‘. Stejně tak se zformátují řetězce, časové údaje, atd.

Modifikátory jsou následující:

%s string
%sn string, ale '' se přeloží jako NULL
%b boolean
%i %u integer
%f float
%d datum (očekává string nebo integer)
%t datum & čas (také string či integer)
%n identifikátor (tedy název tabulky či sloupce)
%sql SQL – řetězec ponechá beze změny
%lmt speciální – určuje limit
%ofs speciální – určuje offset
%ex speciální – expanduje pole

Pokud za modifikátorem následuje NULL, vloží se do databáze NULL. Pokud následuje pole, tak se modifikátor aplikuje na všechny jeho prvky. Ty se pak vloží do SQL oddělené čárkama.

Vždy používejte modifikátor %s před proměnnou s řetězcem. Dibi by pak nemohlo rozlišit, co je SQL příkaz (tzv. embedded SQL) a co řetězec. V tomto příkladu je funkce dibi::query volána s dvěma argumenty, první je řetězec představující (embedded) SQL, druhý je řetězec představující řetězec. Modifikátor %s to odliší:

$text = "I'm fine";
dibi::query('UPDATE `table` SET `text`=%s', $text);
// MySQL: UPDATE `table` SET `text`='I\'m fine'
// ODBC:  UPDATE [table] SET [text]='I''m fine'

Proč používám termín embedded SQL? Protože jak vidno, i toto SQL prochází zpracováním, aby vyhovovalo konvencím dané databáze. Identifikátory (jména tabulek a sloupců) uvozuji do hranatých závorek nebo zpětných uvozovek (je to jedno), dále řetězce značím jednoduchými či dvojitými uvozovkami, ale na výstup se dostane vždy to, co databáze žádá. Příklad

dibi::query("UPDATE `table` SET [text]='I''m fine'");

// MySQL: UPDATE `table` SET `text`='I\'m fine'
// ODBC:  UPDATE [table] SET [text]='I''m fine'

Ještě doplním, že uvozovka se uvnitř řetězce v embedded SQL zapisuje zdvojením. Lomítko má totiž v PHP řetězci zvláštní význam, muselo by se tedy použít dvojité, což leda komplikuje život a cílem dibi je opak.

Formátování polí

Jak jsem už psal, modifikátor je možné aplikovat také na všechny prvky pole, které se pak oddělené čárkami vloží do SQL. Ovšem můžeme využít také dvou speciálních modifikátorů %a nebo %v.

%a assoc [key]=val, [key2]="val2", ...
%v values ([key], [key2], ...) VALUES (val, "val2", ...)
jiný list val, val2, ...

Také si můžeme dovolit luxus žádný modifikátor před polem neuvést. V tom případě dibi použije tuto dedukci: jde-li o příkaz INSERT či REPLACE, zvol %v, jinak %a (platí pro asociativní pole).

Takže příklad:

$arr = array(
    'a' => 'hello',
    'b'  => TRUE,
);
dibi::query('INSERT INTO [table]', $arr);
// INSERT INTO `table` (`a`, `b`) VALUES ('hello', 1)

dibi::query('UPDATE `table` SET ', $arr);
// UPDATE `table` SET `a`='hello', `b`=1

Speciální typy – objekty

Parametrem může být také objekt. Musí implementovat rozhraní IDibiVariable s metodou toSql(). Té se předá cílový ovladač a případný modifikátor a ona vrátí SQL řetězec. Jako příklad jsou v dibi takto řešeny objekty, které nesou datum a čas.

Standardní implementací IDibiVariable je třída DibiVariable. Konstruktoru předáme hodnotu a modifikátor:

dibi::query('UPDATE `table` SET ', array(
    'time' => new DibiVariable(time(), 'd'),
    'number' => new DibiVariable('RAND()', 'sql'),// %sql means SQL ;)
));
// UPDATE `table` SET ('2008-01-01', RAND())

Můžete použít také šikovější továrny na tyto objekty: dibi::date() a dibi::datetime(). Jako parametr akceptují kromě číselné hodnoty timestamp i řetězce.

Postupné skládání dotazu

Dibi disponuje také podporou pro postupné skládání SQL dotazu:

$query[] = 'SELECT * FROM [table]';
if ($where){
    array_push($query, 'WHERE [id]=%d', $where);
}

// a nyní předáme pole
$result = dibi::query($query);

Nebo lze použít expanzi pole přes speciální modifikátor %ex.

Podmíněné SQL příkazy

Podmíněné SQL příkazy jsou velmi silným nástrojem. Ovládají se pomocí tří klíčových slov %if, %else a %end. První z nich %if se musí, obdobně jako modifikátor, nacházet zcela na konci řetězce představující­ho SQL:

$user = ???

dibi::query('
SELECT *
FROM [table]
%if', isset($user), 'WHERE [user]=%s', $user
);

Závěrečné %end je možno vynechat (nebo bude lepší na něm trvat?).

Podmínku lze rozšířit o část %else:

dibi::query('
SELECT *
FROM %if', $cond, '[one_table] %else [second_table]'
);

Podmínky můžete zanořovat do libovolné hloubky!

Prefixy & substituce

Názvy tabulek a sloupců mohou obsahovat proměnné části. Ty si nejprve nadefinujeme:

// create new substitution :blog:  ==>  wp_
dibi::addSubst('blog', 'wp_');

a poté použijeme v SQL. Všimněte si, že v SQL jsou uvozeny dvojtečkama:

dibi::test("UPDATE [:blog:items] SET [text]='Hello World'");
// UPDATE `wp_items` SET `text`='Hello World'

Testování query()

Abyste si mohli trošku s dibi hrát, je tu připravena funkce dibi::test(), které předáte parametry stejně jako dibi::query(), ovšem místo provedení SQL příkazu se tento barevně vypíše na obrazovku.

Možná by vás zajímalo, co celé to parsování a skládání dotazu stojí. Napsal jsem tyto funkce co nejoptimálněji a situace je taková, že zaberou jen zlomek času, který si ukousne samotné vykonání SQL příkazu. Můžete si ověřit.

Získávání výsledků

Nejjednodušší cesta vede přes klasickou iteraci

$result = dibi::query('SELECT * FROM table');

foreach ($result as $n => $row) {
    print_r($row);
}

unset($result);

Všimněte si, že zdroje se uvolní automaticky při zrušení objektu.

Je možné také nastavit offset a eventuálně i limit

$result = dibi::query('SELECT * FROM table');

$offset = 10;
$limit = 3;

foreach ($result->getIterator($offset, $limit)
          as $n => $row) {
    print_r($row);
}

Můžeme získat jen první políčko výsledku

$value = $result->fetchSingle();

Nebo celou tabulku do indexovaného pole:

$all = $result->fetchAll();

A pak tu máme k dispozici jednu mocnou funkci:

$assoc = $result->fetchAssoc('id');

Získá celou tabulku do asociativního a klíčem je políčko ‚id‘. Největší síla funkce se projeví tehdy, pokud provedete asociaci podle více políček. Takto lze nesmírně elegantně získávat data z dotazů, ve kterých spojujeme více tabulek. Příklad si nechám na příště.

Užitečná je také funkce pro získávání dat v podobě asociativního pole klíč ⇒ hodnota

$pairs = $result->fetchPairs('customerID', 'name');

Počet řádků zjistíme voláním:

$rows = count($result);

// přesun kurzoru:
$result->seek($row);

Datové typy

Stále to není všechno, jedeme dále. Při získávání záznamů můžeme specifikovat datový typ jednotlivých sloupců a dibi je bude automaticky převádět.

$result->setType('id', Dibi::FIELD_INTEGER);
$record = $res->fetch();

if (is_int($record['id']))
    echo 'yes, it is integer';

A ještě maličkost. Dibi vrací záznamy pouze jako asociativní pole ‚název sloupce‘ ⇒ hodnota. Nelze přepnout na jinou metodu, protože jiné metody jsou špatné. Máte-li jiný názor, tak blahopřeji, ale nic se tím nezmění.

Výjimky, logování chyb a profiler

Jakákoliv chyba vzniklá během operace s databázovým serverem vyhodí výjimku DibiException nebo potomka DibiDriverExcep­tion. Pokud dojde k chybě během vykonávání SQL příkazu, je i tento předán jako výjimce.

Užitečnou vlastností je logování provozu:

dibi::startLogger('log.txt', TRUE);

Druhý parametr určuje, zda se budou zaznamenávat pouze chyby (hodnota FALSE) nebo vše (TRUE). Což se hodí při ladění. Tehdy se uplatní i velmi jednoduchý profiler:

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

Dibi disponuje rozhraním pro připojení vlastního profileru nebo logovací knihovny. API uveřejním později.

Co dál?

Zatím jde o vývojovou verzi dibi. Sice by neměla obsahovat žádné chyby (běží na ní už několik ostrých webů), ale stále se mohu měnit některé vlastnosti.

Nicméně testujte, zkoumejte, experimentujte.

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

avatar

#1 rADo http://radekhulan.cz/ nový

Vypadá to zajímavě. Ale máme zde PDO, a to je prostě zkompilované v základní instalaci, všudypřítomné, a snad i rychlejší: http://cz2.php.net/pdo

Posláno 26. 5. 2006 v 10.36 | Odpovědět
Na komentář reagoval [4] David Grudl
avatar

#2 jow jirka.dvorak@gmail.com nový

Na zacatku, kdy ses poprve zminil o dibi jsem se trochu bal, aby to nebylo dalsi monstrum, kterych uz na db existuje hodne a ktere by se od ostatnich odlisovalo jenom hezci syntaxi samotnych sql prikazu. Kdyz se na to tedka divam, tak se mi to zacina libit a myslim si ze se dibi muze stat peknou alternativou nekterych monster a ze by mohlo dokonale vyhovovat nejakym mensim projektum. Jeste nakonec otazka :). Budes na eventuelnim vyvoji dibi pracovat sam nebo uz si nekde rozchodil subversion a traca a vrhnes se na cestu open source projektu se sirsi vyvojarskou zakladnou :D (a to nejen u dibi ale i u tveho zatim pro me zahadneho frameworku)? …

Posláno 26. 5. 2006 v 10.37 | Odpovědět
Na komentář reagoval [4] David Grudl
avatar

#3 jow jirka.dvorak@gmail.com nový

S timhle se da celkem polemizovat. Podle me je dobry, ze se obejvila dalsi (jak znam texy i ciste napsana) alternativa, ktera se od zacatku tvari celkem ohebne a o rychlost bych se fakt nebal ;)…

Posláno 26. 5. 2006 v 10.38 | Odpovědět
avatar

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

#1 rADo: PDO je velmi těžkopádné. Neřeší nic z toho, co dibi. Navíc je stále málo dostupné (obvykle jen s sqlite driverem). Nicméně počítám s tím, že udělám do dibi driver pro PDO ;-) Tedy zkombinuji výhody obou.

p.s. od tlustého chlapce mi v poslední době nejvíc frčí hodinové sety

#2 jow: dibi je v podstatě hotový produkt, zbývá dodělat pár věcí, vytvořit stránky, vybrat licenci. Nechci aby to bobtnalo, dibi = db + mini. Prioritou je Nette a některé další projekty.

Posláno 26. 5. 2006 v 10.52 | Odpovědět
Na komentář reagoval [19] Adam Hošek

#5 Aleš Dostál nový

Chtěl jsem se zeptat jak je na tom podpora stored procedure?
V mysqli je potreba pouzit zapis multi_query, jinak se po volaní stored procedure uzavře spojení s DB.

Posláno 26. 5. 2006 v 11.06 | Odpovědět

#6 Borek http://borber.com/blog/ nový

Dobrá práce, líbí se mi hlavně detekce typů. Ještě lepší by bylo, kdyby se nemuselo explicitně volat setType().

Posláno 26. 5. 2006 v 11.16 | Odpovědět

#7 who nový

chtel jsem se zeptat jak je to s sablonama, abyse do html napsalo neco jako <li>{jmeno}

PS: od tlusteho chlapce mam giga setu, ale tak nak apex twin mi pride the best of

Posláno 26. 5. 2006 v 11.27 | Odpovědět
avatar

#8 Jakub Podhorský jakub.podhorsky@centrum.cz nový

nepoužíváš vracení vyjímek pomocí return aby to bylo zpětně kompatibilní s PHP4? kde pro PHP4 si uděláš navíc třídu Exception?

imho to už není používání vyjímek tak jak se mají :)

Posláno 26. 5. 2006 ve 14.25 | Odpovědět
Na komentář reagoval [9] raver

#9 raver http://lccdc.sk nový

#8 Jakub Podhorský: trúfam si povedať že to nebude ten správny dôvod

if (version_compare(PHP_VERSION , '5.0.3', '<'))
    die('dibi needs PHP 5.0.3 or newer');
Posláno 26. 5. 2006 v 15.19 | Odpovědět
Na komentář reagoval [12] Jakub Podhorský
avatar

#10 medden michal.sustr@gmail.com nový

Napadla ma jedna vec, ktorá by sa do dibi mohla dosť hodiť – automatické pridávanie prefixov do názvov tabuliek. Aj keď neviem, či by to nebolo príliš náročné (časovo) zisťovať, či toto sa má prefixovať a toto nie. Čo vy na to? Trebárs by sa meno tabuľky, ktorá sa má prefixovať, uzavrelo do {}.

Posláno 26. 5. 2006 v 15.22 | Odpovědět

#11 lego nový

Nesuhlasim s tym ze prepared statements nemaju vyznam.
hlavne v pripade ORACLE kde parsovanie SQL, overovanie pristupovych prav zabera pri kratkych query cca 70–80% casu.
okrem toho ORACLE si kazdy uz raz vykonany query ulozi do cache pre buduce pouzitie… bez bind premenych su to 1000 querov roznych iba napr. v ID.
Momentalna MySQL implementacia je taka ze prepared stmt to cele zpomaluju ale je mozne ze sa aj oni raz dopracuju k tomu aby sa dali nazyvat databaza:-)

Posláno 26. 5. 2006 v 16.14 | Odpovědět
avatar

#12 Jakub Podhorský jakub.podhorsky@centrum.cz nový

#9 raver: aha no já jsem si zdrojáky neprohlížel takže nevím :) ale jenom jsem tak tipoval podle tohodle článku

Posláno 26. 5. 2006 v 16.30 | Odpovědět

#13 tomashv http://www.chickenator.cz nový

Vypada to vazne hezky, ale prepared statements by urcite nemely chybet…

Posláno 26. 5. 2006 ve 21.30 | Odpovědět
avatar

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

Je to přesně to, co jsem od dibi očekával → velké ulehčení a hlavně zpřehlednění zdrojáků.

Škoda jen, že teď dokončuji jeden projekt, kde by se možná i dibi docela hodilo.. :-)

No možná se dokopu a nějak jej tam ještě před dokončením vecpu… ;-)

Jinak určitě Ti, dgx, patří moje velké díky. Napsal jsem si sice svého času vlastní db layer, který fungoval a funguje spolehlivě, ale tohle je něco úplně jiného. :-D

Díky…

Posláno 27. 5. 2006 v 0.05 | Odpovědět
avatar

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

Je to pekné, ale ostávam zatiaľ pri prepared statements a Finder/Gateway triedach podľa Fowlera.

A prepared statements by som takto nezavrhával. Podľa mňa sa to cachuje skôr na strane DB servera, takže tam to môže hrať väčšiu rolu ako pri znovupoužití toho istého statementu v jednom behu skriptu. To sa mne zatiaľ podarilo tiež len raz.

Posláno 29. 5. 2006 v 10.26 | Odpovědět
avatar

#16 pb http://brouzdi.unas.cz nový

public function applyLimit(&$sql, $offset, $limit)

… tohle asi bude potřeba vymyslet jinak, protože to určitě není takhle snadno implementovatelné. Teda obecně. Protože to je u každé db jinak:

  • MySQL – LIMIT od X do Y
  • MS SQL – TOP X aplikovaný na dvou vnořených selectech s opačným řazením
  • Oracle 9 – opět dva vnořené selecty, ve vnitřním navíc seznam položek rozšířen o číslo řádku, ve vnějším IDROW BETWEEN x AND y
  • Oracle 8 – tři vnořené selecty

atd.

Posláno 31. 5. 2006 v 11.07 | Odpovědět
avatar

#17 Pavel Zbytovský zbytovsky@gmail.com nový

Ahoj,
potřeboval bych prosím pomoc. Tohle mi z nějakého důvodu nefunguje, nic se nevypíše:

$result = dibi::query('SELECT * FROM table');

foreach ($result as $row => $fields) {
    print_r($fields);
}

Nevím jak ty jsou řádky výsledku uložené, ale pokud jsou stejně jako v manuálu, tak by to fungovat mělo.

Ještě doplním, že používám PHP 5.0.4 a že místo $result mi funguje $result->fetchAll(), které ovšem není tak elegantní.

Posláno 31. 5. 2006 v 18.43 | Odpovědět
Na komentář reagoval [18] David Grudl
avatar

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

#17 Pavel Zbytovský: je to opraveno

Posláno 1. 6. 2006 v 9.19 | Odpovědět
avatar

#19 Adam Hošek http://chlupatejslon.info nový

#4 David Grudl: Prioritou je Nette a některé další projekty.

Takže na Nette se stále usilovně pracuje? Už se mi zdálo, že to nějak vyšumělo… pár úvodních článků a pak nic? To přece nedává smysl :-).

Mimochodem mimo téma: jaký smysl má ten rozmmázlý rozsypaný čaj tady dole? ;-)

Posláno 1. 6. 2006 ve 14.16 | Odpovědět
avatar

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

Nová verze 0.6b

Změny se týkají přehodnocení zkratek modifikátorů, především ve vztahu k polím. Doporučuji se podívat na příslušnou pasáž v článku, aktualizoval jsem ho.

Mění se tedy modifikátory data (nyní %d), času (nyní %t), nově přidán modifikátor %p. Odstraněny třídy pro datum a čas – očekává se buď integer (unix timestamp) nebo řetězec (pro strtotime).

Pro pole nyní existují jen dva speciální modifikátory %a a %v. Lze však použít celou škálu výše zmíněných modifikátorů. Dále lze přiřadit modifikátor i konkrétnímu prvku v poli. Popsáno v článku.

Posláno 7. 6. 2006 v 18.01 | Odpovědět
avatar

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

Jo, a ještě jsem přidal, namísto queryStart() a queryAdd(), podmíněné SQL. Zdá se, že by to mohl být velmi silný nástroj:

dibi::query('
SELECT *
FROM %if', $cond, '[one_table] %else [second_table]'
);
Posláno 7. 6. 2006 ve 23.34 | Odpovědět
Na komentář reagoval [22] medden
avatar

#22 medden michal.sustr@gmail.com nový

#21 David Grudl: A nemal by si to jednoduchšie takto?

dibi::query('SELECT * FROM '.(($cond) ? '[one_table]' : '[second_table]'));

(alebo cez to query add)
A asi by to bolo aj trochu rýchlejšie a imho prehľadnejšie.
Myslím si že postupným pridávaním takýchto vecí sa z dibi stane zbytočne veľký moloch, čo by bola škoda…

Posláno 9. 6. 2006 v 15.16 | Odpovědět
Na komentář reagoval [23] David Grudl
avatar

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

#22 medden: máš samozřejmě pravdu.

Dibi jsem pustil ven jako vedlejší produkt jiné činnosti, která mě teď žrala veškerý čas a proto jsem nestíhal vytvořit smysluplné příklady a demonstrovat tak skutečné možnosti. Připravím nový článek, ze kterého bude všechno lépe patrné.

Posláno 10. 6. 2006 v 0.18 | Odpovědět
avatar

#24 Pavel Zbytovský zbytovsky@gmail.com nový

Také bych prosil další článek, pořád na to čekám :-)

Můžeš alespoň naznačit, kdy ten článek vyjde? nebo vy nesmíte ani naznačovat? :-D (Posel z liptákova)

Posláno 11. 6. 2006 v 0.10 | Odpovědět
avatar

#25 MiSHAK http://mishak.net nový

DiBi rulezz http://MiSHAK.net DiBi +-Texy! + Froggy (můj blog system 0.2b). Asi první nasazení DiBi 0.6b v akci :) nebo mě někdo předběhl? Jen jsem musel přepisovat na %if else :(.

A komentáře lze psát jak je libo (html/text/Te­xy!(výchozí).

BTW: komentáře nejdou → zítra uploadnu novou verzi :)

Díky ti!

Posláno 29. 6. 2006 v 18.58 | Odpovědět
avatar

#26 SneakerXZ SneakerXZ@gmail.com nový

No super :) uplně stejná věc už existuje a je přistupná v systémech Invision (IPB, ICB, IG, IPD). Proč ji dělat znovu?

Posláno 30. 6. 2006 v 9.46 | Odpovědět
Na komentář reagoval [29] David Grudl

#27 Pong nový

Skoda, ze dibi nepocita s vice parametrama u WHERE :-/

Posláno 8. 7. 2006 v 16.24 | Odpovědět
Na komentář reagoval [29] David Grudl
avatar

#28 medden michal.sustr@gmail.com nový

Neskúšal som dibi síce, ale % sa v SQL zapíše ako %%? Lebo niekedy znak % je dosti potrebný… aj v SQL

Posláno 8. 7. 2006 v 17.26 | Odpovědět
Na komentář reagoval [29] David Grudl
avatar

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

#26 SneakerXZ: hledal jsem ta klíčová slova a nic smysluplného nenašel. Můžete být konkrétnější?

#27 Pong: Proč by ne? Žádné omezení neexistuje.

#28 medden: Znak % má speciální význam jen tehdy, je-li následován platným modifikátorem a poté hned ukončen řetězec. Takže % může být v pohodě součástí SQL

Posláno 9. 7. 2006 ve 14.11 | Odpovědět
Na komentář reagoval [30] Pong

#30 Pong nový

#29 David Grudl: Vubec se mi nedarilo udelat dotaz ve stylu

SELECT * FROM user WHERE username = 'uzivatel' AND password = 'heslo'

Vkladal jsem tenhle prikaz SQL pro dibi

SELECT * FROM [user] WHERE [username] = %s AND [password] = %s

Ukazkovy PHP kod

$login['username'] = $_GET['username'];
$login['password'] = sha1 ($_GET['password']);

dibi::query ('SELECT * FROM [user] WHERE [username] = %s AND [password] = %s', $login);

A tenhle vysledny SQL prikaz jsem ziskal

SELECT * FROM `user` WHERE `username` = %s AND `password` = 'username', 'password'

Bralo pouze posledni %s. Mel jsem dibi 0.6b. Snad nebyla chyba u me mezi stolem a zidli.

Jeste k tomu formatovani poli bych pridal tvar pro generovani retezku pro WHERE. U WHERE musi mit jednotlive sloupce mezi sebou rozdelene AND. Je tomu tak teda u MySQL. U jinych SQL nejsem si jist. Mohlo to byt treba %w. Nylo by to podobne %a, jen s tim rozdilem, ze by bylo pouzito AND misto „,“ (carky).

Posláno 9. 7. 2006 v 17.02 | Odpovědět
Na komentář reagoval [31] David Grudl
avatar

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

#30 Pong: jo, to je chyba mezi židlí a klávesnicí ;)

dibi::query ('
  SELECT * FROM [user]
  WHERE [username] = %s', $user, ' AND [password] = %s', $pass);

Parametry se vkládají ihned na místo určení, proto není nutné si dopředu vytvářet pole.

Posláno 9. 7. 2006 v 19.19 | Odpovědět

#32 Pong nový

[35] Dekuji, bylo tim. Spatne precteno cast clanku. Omlouvam se za pozdni podekovani. Vim, neni to zdvorile ;o)

Posláno 18. 7. 2006 v 0.30 | Odpovědět
avatar

#33 Teki teki@atlas.cz nový

Nejsem si jistý, do jaké míry je to záměr, ale jedna věc může být zavádějící. Když mám složitější podmínku WHERE, nesmím zapomenout na to, že musím vkládat parametr ihned za místo určení.
Pokud jsem zvyklý závorkovat, může to být matoucí. Malý příklad:
špatně:

$par1 = 'a';
$par2 = 'b';

$res = dibi::test('SELECT cosi FROM [cosi_tbl] WHERE (([par1] = %s)', $par1,' OR ([par2] = %s))', $par2,' AND (c=1)');

správně:

$par1 = 'a';
$par2 = 'b';

$res = dibi::test('SELECT cosi FROM [cosi_tbl] WHERE (([par1] = %s', $par1,') OR ([par2] = %s', $par2,')) AND (c=1)');

Možná by stálo za to zdůraznit, že to funguje právě takto. Někdo si tím může ušetřit trochu koumání (jako já).

Kdy se můžeme těšit na další článek o dibi?

Posláno 12. 11. 2006 v 19.38 | Odpovědět
Na komentář reagoval [34] David Grudl
avatar

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

Další testovací verze je venku.

  • obsahuje driver pro PostgreSql (netestován)
  • chyba při připojování k DB vyhodí výjimku (throw new DibiException)
  • podpora pro prefixy (viz příklad table-prefix.php)
  • parametry připojení lze zadat formou řetězce (viz příklad connect.php)
  • lze postupně skládat dotaz (viz aktualizovaný text v tomto článku)

Logování, zpracování chyb a výjimek je ve fázi vývoje.


#33 Teki: ano, modifikátor se musí nacházet zcela na konci řetězce. V článku jsem to tedy raději zdůraznil.

Posláno 13. 11. 2006 v 7.56 | Odpovědět
avatar

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

Tak venku je verze 0.7. Stále testovací, ale jde o horkého kandidáta na finální :-)

  • zásadní změna se týká vkládání proměnných do SQL. Pokud je (PHP) proměnná NULL, bude do databáze vloženo NULL, nezávisle na použitém modifikátoru. Dříve se NULL přetypovalo podle modifikátoru. Nové chování je logičtější, ale dejte pozor na případné problémy s upgradem.
  • přibyl nový modifikátor %sn (popsáno v článku), %p je nyní %sql
  • získávání dat: celou tabulku vrátí fetchAll(), asociovanou podle jednoho čí více polí fetchAssoc($field, ...) (dříve obojí řešilo fetchAll, nyní rozděleno mezi dvě funkce)
  • logování a zpracování chyb – viz aktualizovaný text článku. Výsledná podoba logu a chybových hlášek je zatím „předmětem výzkumu“ :-)
Posláno 29. 1. 2007 ve 2.15 | Odpovědět

#36 mat nový

Skvelé dgx. Idem hneď otestovať. Trošku zabrdnem. A čo Nette? :-)

Posláno 29. 1. 2007 ve 12.27 | Odpovědět
Na komentář reagoval [37] tark
avatar

#37 tark http://fotoblog.blacksuns.net nový

#36 mat: To by se ukrutně hodilo. Tak co? Kdy bude? :)

Posláno 29. 1. 2007 ve 14.16 | Odpovědět
avatar

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

Na základě tipu Tomáše Bartoně jsem ještě změnil volání SET CHARACTER SET na SET NAMES (já vím, ideální není ani jedno) a opravil drobný bug ⇒ dibi 0.7b

Posláno 30. 1. 2007 ve 22.57 | Odpovědět
avatar

#39 MiSHAK http://www.mishak.net nový

Pracuju nad tím :-)

Chtělo by to ještě pár věcí: Trošku rozepsat popis fetchSingle() (je nepřesný). Pro příkazy s polem by chtělo doplnit nějak podporu Time, Date a DateTime. Objekt TDateTime se má nebo nemá používat?

Posláno 2. 2. 2007 v 16.50 | Odpovědět
avatar

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

Verze 0.7d:

Podpora pro výchozí parametry připojení, které lze definovat např. v souboru PHP.INI. Tedy jde o direktivy mysql.default_user a podobně (viz dokumentace PHP).

Pak lze dibi připojit k databázi skutečně velmi jednoduše:

dibi::connect('driver=mysql');
Posláno 14. 2. 2007 v 19.33 | Odpovědět
avatar

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

Verze 0.8:

  • podpora pro „lazy connections“, k připojení k databázi dojde až v okamžiku, kdy je potřeba. Mezi parametry připojení přidejte 'lazy' => TRUE.
  • opravena řada chyb, refactoring kódu
Posláno 25. 4. 2007 v 8.27 | Odpovědět
avatar

#42 MiSHAK http://www.mishak.net/blog/ nový

Bude někdy i changelog.txt BTW todo.txt je stále stejný :)

Posláno 25. 4. 2007 ve 21.55 | Odpovědět

#43 yed_ nový

Pomoci si od tohoto…

$res = dibi::query("SELECT foo FROM [table] WHERE whatever...");
$value = $res->fetchSingle();

…něčím takovýmto…

$value = dibi::select("fetchSingle", "SELECT foo FROM [table] WHERE whatever...");

…je mimo cíle dibi?

Posláno 2. 5. 2007 ve 12.07 | Odpovědět
Na komentář reagoval [44] David Grudl
avatar

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

#43 yed_: zkus

$value = dibi::query("SELECT foo FROM [table]
WHERE whatever...")->fetchSingle();
Posláno 2. 5. 2007 ve 13.17 | Odpovědět
Na komentář reagoval [45] yed_

#45 yed_ nový

#44 David Grudl: Ach, já nedůvtipa .)

Posláno 2. 5. 2007 ve 22.30 | Odpovědět

#46 Whitek http://www.clevis.cz nový

skoda, ten minuly titulek se me libil vice a radeji jsem se sem i vracel(tento je prilis suchy). Holt kazdy chce byt ‚seo‘.
Ale diky za novou verzi!

Posláno 8. 5. 2007 ve 20.11 | Odpovědět
avatar

#47 MiSHAK http://www.mishak.net/blog/ nový

Zajimavé, žě v RSS se titulek neměni… Lazy RSS nuklea asi

Posláno 9. 5. 2007 ve 13.33 | Odpovědět

#48 Non_E http://radekdvorak.eu nový

Ahoj, narazil jsem na problém s postupným skládáním dotazu. Když to hodně zjednoduším:

<?php
//připojeno k db

$query[] = "SELECT %sql";
$query[] = "NOW()";

dibi::test($query);
$arr_res = dibi::query($query)->fetchAll();
?>

mi vypíše toto:

SELECT NOW()

( ! ) Warning: dibi: [1064] You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near SELECT %sql', 'NOW() at line 1 in /var/www/projec­t/htdocs/ext-libs/dibi/lib­s/driver.php on line 136
Pokud nepoužiju pole, tak se chyba neprojeví. Je dost dobře možné, že je chyba mezi židlí a klávesnicí, ale po hodině mě už nic nenapadá.

Dík

Posláno 11. 5. 2007 ve 13.57 | Odpovědět
Na komentář reagoval [49] David Grudl
avatar

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

#48 Non_E: Díky za bugfix a patch co jsi mi poslal emailem! Opravenou verzi (0.8b) hnedle uploadnu.

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

#50 silebis silebis@gmail.com nový

Skvely, zrovna tohle potrebuji, akorat mi chybi podpora pro ms sql.
Kdy planujes vypustit novou verzi s podporou microsoftiho sqlka?

Posláno 13. 5. 2007 v 19.35 | Odpovědět
Na komentář reagoval [51] David Grudl
avatar

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

#50 silebis: myslíš driver pro funkce mssql_***? Což o to, základ bych měl, ale nemám ho jak otestovat a netuším, jakou funkcí zjistit chybový kód serveru. Zhostíš se toho?

Posláno 13. 5. 2007 ve 20.36 | Odpovědět
Na komentář reagoval [52] silebis

#52 silebis nový

#51 David Grudl:
Zkusim, sam tedka zacinam v mssql :-)
Zkus si nainstalova MS SQL 2005 Express. Pro zkouseni idealni a kupodivu zadara.

Posláno 14. 5. 2007 v 8.32 | Odpovědět

#53 silebis nový

ehm, no spatna chyba, predeslou chybu neberte vazne, spravna je:

Warning: dibi: in \plugins\dibi\lib­s\driver.php on line 137

Fatal error: Call to a member function fetchAll() on a non-object in \test.php on line 19

Posláno 16. 5. 2007 v 16.30 | Odpovědět
Na komentář reagoval [54] silebis

#54 silebis nový

#53 silebis: jak jsem si tedka vsiml, hlavni zprava nedorazila, tak znovu.

Pri vicenasobnem pripojeni na jednom typu databaze vse jede v pohode, ale kdyz se pripojim na dva typy databazi, uz dibi vyhazuje chybu. Mozna je chyba u me, mozna v dibi.

<?php
dibi::connect(array(
        'driver'   => 'mysql',
        'host'     => $ConfigDBServer,
        'username' => $ConfigDBUser,
        'password' => $ConfigDBPass,
        'database' => $ConfigDBDatabase,
        //'charset'  => 'win1250',
    ),1);

    dibi::connect(array(
        'driver'   => 'mssql',
        'host'     => $ConfigDBMSServer,
        'username' => $ConfigDBMSUser,
        'password' => $ConfigDBMSPass,
        'database' => $ConfigDBMSDatabase,
    ),2);

dibi::getConnection(1);

$res = dibi::query('select krestni, prijmeni, idUzivatele from core_users')->fetchAll();

foreach ($res as $key => $row) {
    echo $row["krestni"]." ".$row["prijmeni"]." - ".$row["idUzivatele"];
    //print_r($fields);
    echo '<hr>';
}
?>
Posláno 16. 5. 2007 v 19.25 | Odpovědět
Na komentář reagoval [55] David Grudl
avatar

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

#54 silebis: $res není objekt, funkce query zřejmě vrátila FALSE.

Jinak getConnection() funguje trošku jinak. Vrací objekt driveru, na kterém lze pak volat funkce přímo, například:

$conn = dibi::getConnection(1);
$res = $conn->query('SELECT ....');

Pro přepínání aktivního připojení pro statický registr dibi volej activate():

dibi::activate(1);
dibi::query('INSERT .... ');
Posláno 16. 5. 2007 ve 23.50 | Odpovědět

#56 silebis nový

Mozna chybka? Jakmile pridam atribut s domenou ntext (v mssql databazi) okamzite mi dibi vyhodi chybu na radku 137 v driver.php
Zeby nepodporovana domena?

Posláno 17. 5. 2007 ve 20.57 | Odpovědět
Na komentář reagoval [57] David Grudl
avatar

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

#56 silebis: fixnul jsem to – stáhni si znovu dibi-0.8c.zip

Posláno 17. 5. 2007 ve 23.04 | Odpovědět

#58 silebis nový

diky
nevis plz jakou hodnotu nastavit v charsetu pro mssql abych dostal vysledky „spravne cesky“?
Dostavam jen same hacky (Ostatnˇ)

Posláno 18. 5. 2007 v 8.41 | Odpovědět

#59 silebis nový

Bohuzel, stale stejna chyba – driver.php on line 137

Posláno 18. 5. 2007 v 8.56 | Odpovědět
Na komentář reagoval [60] David Grudl
avatar

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

#59 silebis: to je User warning, který vyhodí přímo dibi, protože máš nějakou chybu v SQL dotazu. Nevím jak zjistit text nebo kód té chyby. Nicméně MSSQL není tématem, držme se čistě dibi. Pokud vylepšíš driver mssql, pošli mi ho prosím mailem, díky

Posláno 18. 5. 2007 v 9.55 | Odpovědět

#61 Silebis nový

Budu zkouset. Co jen mohu s jistotou rici, ze v dotazu chybu nemam.

Posláno 18. 5. 2007 ve 12.51 | Odpovědět
avatar

#62 Acci http://acci.cz/ nový

Bude dibi v příští verzi podporovat vícenásobný INSERT? Celkem by se mi to (a nejspíše nejen mně) hodilo.

Posláno 29. 5. 2007 ve 22.38 | Odpovědět
Na komentář reagoval [63] David Grudl
avatar

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

#62 Acci: doplněno do verze 0.8d

dibi::query('INSERT INTO [table]', $arr, $arr, $arr, $arr);
Posláno 30. 5. 2007 ve 2.02 | Odpovědět
Na komentář reagoval [64] Acci [72] David Grudl
avatar

#64 Acci http://acci.cz/masbete/ nový

#63 David Grudl: Díky, to je fakt luxus!

Posláno 31. 5. 2007 v 10.22 | Odpovědět
avatar

#65 sefik http://sefikuv.net nový

chtěl bych jenom upozornit, pokud zadáte do dotazu … %i ',$cislo, … a mezi %i a uvozovku dáte mezeru, tak to nebude fungovat

Posláno 19. 6. 2007 v 11.51 | Odpovědět
Na komentář reagoval [66] MiSHAK
avatar

#66 MiSHAK http://www.mishak.net nový

#65 sefik: No to je normální chování, dibi zpracovává jen metaznaky na konci řetězce.

Posláno 19. 6. 2007 ve 14.49 | Odpovědět

#67 LamiCZ http://me-gaming.com nový

Zdravím, narazil jsem na tento blog i utility od DGXho a musím říct, že smekám, seznamuji se pomalu s PHP5 OOP (velmi pomalu :)) na mém systemu (viz link) a Texy! se mi velmi zamlouvá, už jsem ho dal na novinky a knihu návštěv. Nyní testuji dibi a začíná se mi velmi libit, měl jsem použity PDO, ale je to strašně zabugovaná věc nebo já v tom neumím psat, nevím… (Asi spíše to b) je správně…).
Každopádně GW dgx a doufám, že bude dibi používána i vyvíjena ;)

Posláno 22. 6. 2007 v 5.41 | Odpovědět
avatar

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

Verze 0.8e podporuje extra dlouhá a hexadecimální čísla:

dibi::test("SELECT %i", '-123456789123456789123456789');
// -> SELECT -123456789123456789123456789

dibi::test("SELECT %f", '-.12345678912345678912345678e10');
// -> -.12345678912345678912345678e10

dibi::test("SELECT %i", '0x11');
// -> SELECT 17

Za impuls děkuji Tomáši Bartoňovi.

Posláno 28. 8. 2007 v 0.46 | Odpovědět
avatar

#69 zajDee zajdee@centrum.cz nový

Mozna to tu pisu zbytecne, ale pokud by se s tim nekdo setkal, tak muze mit min prace:

Metoda fetchAll vrati pole, ve kterem jsou jednotlive indexy shodne se jmenem sloupce. Az potud OK. Jenze ve chvili, kdy mam SQL dotaz, ktery spojuje dve tabulky, ve kterych je sloupec se stejnym jmenem, vrati dibi jen ten posledni zmineny v SQL dotazu (tedy, tak se to chovalo mne).

Reseni bylo proste, pouzit AS jmenoSloupceVe­Vysledku, tj. napr. SELECT [tabulka1.id] AS [sloupecVTabul­ce1],[tabulka2­.id] AS [sloupecVTabulce2] FROM (…)

Jo a psát česky, to bych rád, ale zapomínám na to :-)

Posláno 31. 8. 2007 v 10.40 | Odpovědět
Na komentář reagoval [72] David Grudl

#70 Milan Svoboda nový

Uvažuješ i o podpoře ORACLE?

Posláno 6. 9. 2007 ve 13.29 | Odpovědět
Na komentář reagoval [72] David Grudl
avatar

#71 Blekii blekii@atlas.cz nový

Hoj vespolek, zajímavá pomůcka a jen tak bez přemýšlení se zeptám…a co podpora pro vícenásobný UPDATE a INSERT..(v MYSQL).. existuje v DIBI?

Posláno 14. 9. 2007 ve 22.55 | Odpovědět
Na komentář reagoval [72] David Grudl
avatar

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

#69 zajDee: to není záležitost dibi, ale databázového ovladače. Jinak se chová MySQL a jinak třeba SQLite.

#70 Milan Svoboda: neuvažuju, ORACLE nemám

#71 Blekii: ano, viz #63 David Grudl:

Posláno 15. 9. 2007 ve 3.08 | Odpovědět
avatar

#73 Blekii blekii@atlas.cz nový

Je to fakt bomba. Vícenásobný insert mi sice nejede, ale to jen tázka správného pochopení. Ale chceš vybírat-udělá to DIBI, chceš vkládat udělá to dibi, chceš na záchod, já sedím ale DIBI jde…

Posláno 15. 9. 2007 ve 12.43 | Odpovědět
avatar

#74 Josef Průša http://josef-prusa.eu nový

Ahoj, jak používat v DIBI + PostgreSQL schémata?

dibi::query(‚SELECT * FROM [schema.table] WHERE [id] = %i‘, $id);

Nebo to jde nějak elegantněji?

Posláno 20. 9. 2007 v 0.03 | Odpovědět
avatar

#75 sairon http://sairon.cz nový

Tak jsem se stal taky závislým na dibi. Po pochopení základních principů je práce s ním intuitivní a odpadá plno starostí, prostě perfektní. Kompaktní verze navíc není zbytečně velká a poskytuje stejný (a v mnoha případech větší) komfort, jako ostatní DB layery; licence také není nijak omezující. Smekám :)

Posláno 23. 9. 2007 v 19.33 | Odpovědět

#76 miniak nový

dibi je uplne krasny kus kodu, velmi sa mi paci. pochvala DGXovi.
v praci som musel pouzivat ADOdb, ktore mi pripada uchylne. oproti tomu je dibi uplna krasa. jednoduche, male, rychle

akurat pri praci so substituciami som narazil na drobnosti, ktory by ulahcili zivot:

  1. funkcia dibi::addSubst() by mohla brat nielen nazov a hodnotu, ale aj pole, aby som ju nemusel opakovane volat pre viacero poloziek.
  2. podobne u dibi::remove­Subst(), a tam by nebolo zle, keby to zrusilo vsetky substitucie pri zavolani bez parametra
Posláno 24. 9. 2007 v 17.37 | Odpovědět
Na komentář reagoval [77] David Grudl
avatar

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

díky za pochvaly!

#76 miniak: doplním volání removeSubst(TRUE), ktere zruší všechny substitutky.

Posláno 24. 9. 2007 ve 21.06 | Odpovědět
avatar

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

Jak nejjednodušeji zjistím počet vrácených výsledků, smazaných řádků apod.? mysql_num_rows() a mysql_affected_row­s().

Nemohlo by existovat něco jako $result->length() ?

Třeba by se mi to hodilo, když nevim jestli vypsat seznam výsledků nebo napsat, že nic neexistuje.

Posláno 26. 9. 2007 v 17.48 | Odpovědět
Na komentář reagoval [80] David Grudl
avatar

#79 MiSHAK http://www.mishak.net nový

count($result) podkud se nepletu. :)

Posláno 26. 9. 2007 ve 20.10 | Odpovědět
avatar

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

#78 Honza M.:

  • počet řádků: $result->rowCount() nebo count($result)
  • ovlivněné řádky: dibi::affected­Rows() nebo $driver->affectedRows()
  • insert id: dibi::insertId() nebo $driver->insertId()

v případě PostgreSql lze volat dibi::insertId(‚na­zev sekvence‘)

Posláno 26. 9. 2007 ve 21.40 | Odpovědět
avatar

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

Verze 0.9a má zcela přepracovaný systém logování a profilování – základy najdete v příkladech logger.php a profiler.php. Bude možné nastavit vlastní profiler nebo logger, ale API se ještě změní, takže ho zatím nebudu zveřejňovat.

Zrušil jsem vlastnost dibi::$throwEx­ceptions – dibi nyní vyhazuje výjimky vždy. Jen tak je možné bezpečně volat třeba:

dibi::query(...)->fetchAll();

Když by totiž query vypsalo chybu a vrátilo FALSE, tak volání fetchAll() by způsobilo Fatal error: Call to a member function fetchAll() on a non-object. Naopak výjimky lze zachytit a zpracovat.

Plán: dibi už je pomalu hotové, v plánu mám ještě dořešit logování & profiler.

Posláno 29. 9. 2007 v 10.42 | Odpovědět
Na komentář reagoval [83] MiSHAK
avatar

#82 sairon http://sairon.cz nový

Původně vracelo volání dibi::query(„INSERT INTO …“) při úspěchu true, teď vrací null. Je to tak záměrně?

Posláno 30. 9. 2007 ve 14.30 | Odpovědět
Na komentář reagoval [84] David Grudl
avatar

#83 MiSHAK http://www.mishak.net nový

#81 David Grudl: Má tedy cenu přecházet na 0.9 nebo si „chvilku“ počkat?

Posláno 30. 9. 2007 v 17.40 | Odpovědět
avatar

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

#82 sairon: hmmm, to by mohlo být problematické kvůli zpětné kompatibilitě. Opravil jsem, nyní vrací v případě úspěchu opět TRUE.

Posláno 1. 10. 2007 v 7.38 | Odpovědět
avatar

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

Existuje nějaký elegantnější způsob, jak získat rovnou první řádek do asociativního pole než

$res = dibi::query("......")->fetchAll();
$res = $res[ 0];

?

Posláno 6. 10. 2007 v 17.40 | Odpovědět
Na komentář reagoval [86] David Grudl
avatar

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

#85 Honza M.:

$row = dibi::query("......")->fetch();
Posláno 7. 10. 2007 v 11.11 | Odpovědět
avatar

#87 Pavel Černý pavelcerny68@seznam.cz nový

Ahoj, rád bych použil DIBI u mnou vyvíjené aplikace (placené)…
Jak se domluvíme?

Blekii

Posláno 11. 10. 2007 v 15.41 | Odpovědět
Na komentář reagoval [88] David Grudl
avatar

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

#87 Pavel Černý: dodrž licenci

Posláno 11. 10. 2007 v 16.11 | Odpovědět
Na komentář reagoval [89] zirafka
avatar

#89 zirafka http://blog.zirafka.cz nový

#88 David Grudl: dodrz licenci, posilis mir!

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

#90 Pavel Černý pavelcerny68@seznam.cz nový

Moc té licenci nerozumím…(myslím tím podstatu).
Řekni mi to jako malému dítěti…

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

#91 hvge http://hvge.sk nový

Pavel Černý: pebéébe pebéébe ;]

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

#92 Pavel Černý pavelcerny68@seznam.cz nový

LOL

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

#93 Josef Průša http://josef-prusa.eu nový

DGX se docela divil když jsem mu chtěl poslat příspěvek na dibi :) myslím, že stojí mnohem víc za podporu než Texy ;)

Posláno 14. 10. 2007 v 0.07 | Odpovědět
avatar

#94 Hrach http://hrach.netuje.cz nový

Je možné nějak aby Dibi volalo po každém dotazu mou funkci – zřejmě nějak pomocí handleru a eventu, ale zatím sem vůbec nepřišel jak.. :(
chtělo by to dokumentaci ;)

Posláno 7. 11. 2007 v 16.25 | Odpovědět
Na komentář reagoval [95] Hrach
avatar

#95 Hrach http://hrach.netuje.cz nový

#94 Hrach: tak, už jsem na to přišel, ale nějak nemůžu dosáhnout funkčnosti v tomto případě:

dibi::addHandler(array($this, 'afterQuery'));

daří se mi volat pouze funkci, ale ne metodu třídy

Posláno 7. 11. 2007 v 17.44 | Odpovědět
Na komentář reagoval [96] David Grudl
avatar

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

#95 Hrach: toto je API, které se bude ještě určitě měnit. Proto není zdokumentované.

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

#97 veena nový

Prošel sem si zdrojáky dibi a měl bych tu pár návrhů na zlepšení:

  1. chtělo by to zdokumentovat, jaké všechny parametry mohou být v poli cpaném do dibi::connect()
  2. kupodivu jsem tam nenašel metodu close() na uzavření spojení. Opravdu tam není? To by asi měla. (nejlépe s možností se u fetch metod rozhodnout, zda ho zavřít)
  3. nemělo by být v mysql/i driverech kormě SET NAMES voláno i SET CHARACTER SET pro správné řazení?

viz http://www.alberton.info/…plained.html

  1. kontrolu spojení if (!$this->connection) { jsem používal také. Než se mi stalo, že v dlouho běžícím skriptu (z příkazové řádky) jsem si neuzavřel spojení k db. Ono vypršelo po timetoutu, který má nastavena mysql. No jo, ale v phpku resource v proměnné $this->connection stále zůstane, i když je už vzdálený zdroj odpojen.

Já sem nakonec vyřešil metodu connect takto:

function connect()
{
    if (false === $this->resource = mysql_connect($this->host, $this->user, $this->password, $this->newConn)) {
        return false;
    }
    if ($this->newConn and !empty($this->chset)) {
        mysql_query('SET CHARACTER SET '.$this->chset, $this->resource);
        mysql_query('SET NAMES '.$this->chset, $this->resource);
    }
    $this->newConn = false;
    return true;
}
  1. přidal bych podporu mysql_unbuffe­red_query(). Šetří to paměť hlavně u velkých dotazů a umožňuje to procházet jejich výsledky hned bez čekání na všechna data.

Více inspirace viz na
http://mini-framework.php5.cz/…mysql41.phps

Posláno 9. 11. 2007 v 16.26 | Odpovědět
Na komentář reagoval [98] David Grudl [99] David Grudl
avatar

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

#97 veena: díky za připomínky.

ad 1) ano, dokumentace chybí, zdaleka nejen u této metody.

ad 2) pro klid duší to tam dám :-)

ad 3) SET NAMES a SET CHARACTER SET fungují částečně protichůdně, takže volat by se mělo jedno nebo druhé (a když obojí, tak ve správném pořadí). Praktičtější se mi zdá SET NAMES, které se nespoléhá na nastavení databáze.

ad 4) jestli to dobře chápu, tak ty před každým query oveříš a případně obnovíš spojení přes mysql_connect(…, FALSE)? To není špatný nápad.

ad 5) to je taky dobrá připomínka, jen zatím neslučitelná s filosofií „nikdy nepřídávej funkčnost, která by se mohla někdy hodit, ale jen to, co skutečně potřebuješ“

Posláno 10. 11. 2007 v 1.24 | Odpovědět
Na komentář reagoval [100] veena
avatar

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

Verze 0.9 rev. 77

  • drivery mají metodu disconnect()
  • navazování spojení (viz #97 veena: bod 4) jsem nakonec neimplementoval. Mohlo by to způsobit průšvih, když bych v průběhu spojení změnil databázi, ono by se to tiše rekonektlo na původní a pak bych nic netuše pracoval s jinou.
  • driver SQlite při chybě vrací její podrobnější popis

Minimální požadovaná verze PHP je 5.1.0. Dále prosím netestujte návratovou hodnotu způsobem if (dibi::query(...)), v případě chyby dibi vrací výjimku.

Posláno 10. 11. 2007 v 8.07 | Odpovědět
Na komentář reagoval [100] veena

#100 veena nový

#98 David Grudl: #99 David Grudl:
ad 1) 2) ok
ad 3) popravdě se v tom zas tolik nevyznám, ale dal sem to tam poté, co jsem v jedné diskuzi četl, že to někomu pomohlo s řazením.

ad 4) jo obnovuju pokaždé. Nevim, jestli to trvá déle. Nekoukal sem do zdrojáků mysql_connect() jak funguje, ale snad pokaždé neposílá login do databáze ale zjistí si jinak, jestli je resource funkční.

Ještě by to šlo udělat přes volání mysql_ping()

S tou změnou databáze to je samozřejmě u singletonu problém!
Musel bys vždy volat mysql_select() po connectu. To by asi zase chtělo nějaký benchmark.

Obecně bych u singletonu to přepínání databází nepoužíval. Vázat ten singleton k objektu databáze a ne ke spojení.
Když někdo potřebuje více databází (já třeba občas), tak si prostě udělá víc instancí databázovýho objektu.

Ono je to stejně ošemetné když někde v půlce kódu změníš databázi v tom singletonu a pak někde daleko máš práci s tou databází, tak je to nepřehledné. To aby ses furt koukal, který kód se vykonal předtím a kolikrát si tu databázi switchnul. Čo?

ad 5) mysql_unbuffe­red_query() používám defaultně u všech fetch metod který získávaj data do polí, protože sem ji objevil hned na začátku co jsem si db knihovnu vytvářel. Zase, benchmark sem si nedělal. Nicméně mi to nedělalo problém zapojit to do návrhu, takže sem to tam dal jako parametr u těchle fetch metod. Možná u tebe by to znamenalo překopat toho víc a měnit API, takže je to na zvážení. Teda pokud bys to neudělal jako jeden parametr do $option pro mysql a pak by to platilo pro volání všech fetch metod tý instance.

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

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

#100 veena: ten příklad se změnou databáze byl jen ilustrační. Tichý rekonekt může způsobit víc problémů, poškodí otevřenou transakci, vymaže nastavené proměnné (například LAST_INSERT_ID) atd. Jako obecné řešení to chce najít něco jiného. Co třeba MYSQL_CLIENT_IN­TERACTIVE?

ad unbuffered: o změnu API ani tak nejde, jako spíš o odlišnou logiku chování. Tedy že dokud nedočteš jedno query, nemůžeš volat další. Ale jako volba pro celé connection to není špatné řešení. Přidám.

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

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

Verze 0.9 rev. 83

  • implementovány unbuffered query pro MySQL, MySQLi a SQLite drivery. Zapnou se volbou 'unbuffered' => TRUE v parametrech připojení.
  • dopsal jsem dokumentaci jednotlivých parametrů (viz třeba DibiMySqlDriver)
  • v unbuffered režimu vyhazuje DibiResult::seek() nebo DibiDriver::row­Count() výjimku
  • aby bylo chování konzistentní, vyhazuje DibiResult::seek() při chybě výjimku vždy, tedy i v buffered re­žimu
  • DibiDriver::e­rrorInfo je deprecated (chyby vyhazují výjimky)
  • Důkladný refactoring celého kódu. Nemělo by to mít vliv na funkci (rostlináře).
Posláno 12. 11. 2007 ve 2.54 | Odpovědět
avatar

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

Verze 0.9 rev. 94

  • metody dibi::date() a dibi::datetime generují datum a čas ve formátu pro databázi (zabaleno jako DibiVariable objekt)
  • insertId() a affectedRows() v případě chyby generují výjimku
  • špatné pořadí volání begin(), commit(), rollback() generuje výjimku
  • rozšířeny parametry pro připojování k PostgreSQL (viz DibiPostgreDriver
  • opraveno několik chyb
Posláno 24. 11. 2007 v 0.42 | Odpovědět
avatar

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

Verze 0.9 rev. 98

novinka: možnost nechat kvalifikovat název každého sloupce názvem tabulky:

$res = dibi::query('
    SELECT *
    FROM [products] AS aa
    INNER JOIN [products] AS bb ON aa.product_id <> bb.product_id
');

$res->dump();

// srovnej s:
$res->withTables = TRUE;
$res->dump();
  • odstranil jsem některé experimentální vlastnosti jako autodetekce typů přes $result->setType(TRUE);, metody getFields nebo getMetaData
  • metatypy se nyní oficiálně zjišťuji přes $result->getColumnsMeta();
Posláno 30. 11. 2007 v 11.29 | 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, 2009 David Grudlo webu

Jakékoliv užití obsahu, včetně převzetí článků nebo jejich částí, je bez předchozího písemného svolení autora zakázáno.

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

Tipy: Nafukovací čluny, lodě, kajaky, rafty | Spolehlivý obchod | Pevné zdraví, léky, afrodiziaka, fitness, lékárna | Parfémy | Dieta, hubnutí