Autor Zpráva
midlan
Profil
Ahoj,
potřeboval bych nějaké multiplatformní objektové řešení SQL dotazů. Kdybych náhodou někdy přešel na jinou databázi aby to celé pořád fungovalo :) Db layer už mám vytvořený, jen potřebuji samotné vytváření dotazů. Představuji si to asi takhle:

<?php
Query::$driver = Query::DRIVER_MYSQL;
$db->query(Query::select('jmeno', 'prijmeni')->from('uzivatele')->where(array('id' => 10))->limit(1));

Na tento zápis bych si to už případně upravil, ale potřeboval bych nějaké opravdu odladěné a vyvíjené řešení, abych to nemusel psát celé odznova.
juriad
Profil
Nevyhovovalo by ti dibi a jeho fluent rozhraní?
Joker
Profil
Párkrát jsem přemýšlel, jestli vůbec má smysl takové mezivrstvy dělat.

Zejména pokud nad ní mám nějakou svou vrstvu, která mi vrací objekty aplikace (což bych asi měl mít) a pod ní databázovou vrstvu.
Na jedné straně to je tak obecné, že to zkomplikuje optimalizaci pro konkrétní datové úložiště, na druhé straně to je ale tak konkrétní, že při změně datového úložiště to tahle vrstva často neodfiltruje.

Často jsem narazil na to, že taková mezivrstva je buď moc přizpůsobená konkrétní databázi, nebo prostě alternativní úložiště je natolik odlišné, že se pro něj ten styl vybírání z databáze nehodí. A skončí to tak, že na datovém úložišti je závislá i o jednu vyšší vrstva (repozitář). A jaký smysl pak má taková mezivrstva?

Ono obecně, nestačí mít repozitář, který je závislý na datovém úložišti a který už používá vestavěné objekty pro dotazy na úložiště dat (třeba PDO nebo MySQLi)? V čem je výhodná ještě další mezivrstva?
midlan
Profil
juriad:
Docela se mi líbí, ale nějak nevidím jestli se dá měnit cílová databáze, aby to generovalo dotaz používající výhody dané databáze. Jak by to bylo při vykuchání některých funkcí z toho fluentu s licencí? Nikdy jsem licence nějak nezkoumal, prosil bych o radu někoho kdo se v nich vyzná.

Joker:
Nechci aby vrstva vracela objekty aplikace. Moc nechápu co myslíte pojmem datové úložiště. Pro přiblížení nyní mám vytvořené rozhraní Connection, Result a PreparedStatement a implementovat je budou třídy pro konkrétní připojení. Zatím mám vytvořené jen připojení přes mysqli, ale kdybych časem chtěl přejít na jiné, jen napíšu potřebné třídy, ale rozhraní zůstane stejné, to ale neplatí pro dotazy, protože každá databáze je trochu odlišná.
Medvídek
Profil
midlan:
Já ve všech svých aplikacích řeším přístup k DB přes Active Records.
juriad
Profil
Licence je buď BSD nebo GPL, tobě vyhovuje asi víc ta BSD.
dibi žádné optimalizace neprovádějí, jen se stará o to, že vygenerované SQL bude pro danou databázi pochopitelné, především se stará o escapování.
midlan
Profil
Medvídek:
to není to co hledám, já hledám jen čistý generátor SQL dotazů, přizpůsobující výsledný SQL dotaz zvolené databázi

juriad:
Myslím například jestli umí optimalizaci na víceřádkový insert v mysql, který například v oracle nejde?
Medvídek
Profil
midlan:
Však já také neřeším, pro jakou DB to bude.

Prostě v PHP napíši:

$data = array(
               'title' => $title,
               'name' => $name,
               'date' => $date
            );

$this->db->where('id', $id);
$this->db->update('mytable', $data); 

A je mi jedno, jestli to zapisuju do MySQL nebo MSSQL a jestli to budu dělat pomocí mysql, mysqli, odbc, pdo mssql driveru.

Pokaždý se mi vygeneruje SQL pro danou DB v daném driveru
midlan
Profil
Medvídek:
Aha. A jakou vrstvu konrétně používáte v php?
Jan Tvrdík
Profil
midlan:
Kdybych náhodou někdy přešel na jinou databázi aby to celé pořád fungovalo
Moje první rada je něco takového vůbec nechtít, protože to znemožní plně využít konkrétní databázi. Jediná knihovna, která to, pokud vím, řeší skutečně pořádně, je Doctrine (díky DQL). Dibi, stejně jako většina ostatních knihoven, to řeší jen částečně.
Medvídek
Profil
midlan:
Používám mírně upravenou z CodeIgniteru
midlan
Profil
Jan Tvrdík:
Když budu primárně používat MySQL / MariaDB přijdu o něco zásadního?
Joker
Profil
midlan:
Nechci aby vrstva vracela objekty aplikace.
Ale nakonec se stejně vrací, ne? Data se načítají z databáze někam.
Když dám příklad, budu načítat třeba články, tak „někde nahoře“ bude aplikace pracovat s nějakým objektem článku. O patro níž bude něco jako repository, čemu řeknu že chci článek a dostanu objekt, nebo tomu dám objekt a ono to aktualizuje uložená data, a tak podobně.
O další patro níž by byla tahle mezivrstva a ještě o patro níž bude driver pro komunikaci s databází.

Moje úvaha je, že ta mezivrstva vlastně nic moc nepřináší a zároveň znemožní dělat optimalizace pro konkrétní databázi na té vyšší úrovni (repository). Čili jestli by nebylo lepší svázat s konkrétní databází repository (změna databáze znamená změnu repository třídy) a tu mezivrstvu úplně odstranit.
Další bod do úvahy byl, že jednotlivé druhy úložišť se mohou lišit natolik, že je velmi těžké tu mezivrstvu navrhnout tak, aby je pokryla všechny.

Moc nechápu co myslíte pojmem datové úložiště.
Prostě odkud se čtou data. Třeba MySQL databáze. Nebo XML soubor. Nějaký jiný soubor. Kolekce tříd v paměti. Cokoliv.

Zatím mám vytvořené jen připojení přes mysqli, ale kdybych časem chtěl přejít na jiné, jen napíšu potřebné třídy, ale rozhraní zůstane stejné
No, právě.
Mně se právě několikrát stalo, že takováhle „obecná databázová vrstva“ mi právě znemožnila používat konkrétní vlastnosti jedné databáze (s myšlenkou, že to ovšem mám hezky obecné) a když pak došlo na lámání chleba a bylo potřeba opravdu data načítat z jiného typu úložiště, ukázalo se, že tomu novému úložišti návrh celé té vrstvy nevyhovuje.
Jasně, dá se říct, že to bylo špatným návrhem té vrstvy, jenže to je právě v tom, že podle mě nejde udělat tak univerzální návrh, aby to pojalo všechno.
midlan
Profil
Joker:
Ale nakonec se stejně vrací, ne? Data se načítají z databáze někam.
Ne opravdu nikdy nepracuji s objekty. V aplikaci mám jen jeden objekt, který obsahuje data z databáze a to je objekt uživatel. Nikde jinde v tom nevidím smysl, protože čistota práce by nestála za ty nároky na výkon. Celkově hodně zakládám na rychlosti aplikace, běh skriptu je pro mě optimální pod 20ms. Toho bych nikdy nemohl dosáhnout s převáděním dat z databáze na objekty.

Joker:
Další bod do úvahy byl, že jednotlivé druhy úložišť se mohou lišit natolik, že je velmi těžké tu mezivrstvu navrhnout tak, aby je pokryla všechny.
Jako úložiště počítám vždy se serverouvou databází s jazykem SQL, maximálně SQLite, proto je to databázová vrstva.

Mně se právě několikrát stalo, že takováhle ‚obecná databázová vrstva‘ mi právě znemožnila používat konkrétní vlastnosti jedné databáze (s myšlenkou, že to ovšem mám hezky obecné) a když pak došlo na lámání chleba a bylo potřeba opravdu data načítat z jiného typu úložiště, ukázalo se, že tomu novému úložišti návrh celé té vrstvy nevyhovuje.
Hodně jsem při návrhu vycházel z PDO, ale udělal jsem jinak to co mi vadilo (například stejný objekt pro prepared statemnty a result; nemožnost použít dvakrát fetchAll v mysql atd.). PDO podporuje hned několik úložišť a nezdá se mi, že by to bylo omezením.
Joker
Profil
midlan:
Ne opravdu nikdy nepracuji s objekty. V aplikaci mám jen jeden objekt, který obsahuje data z databáze a to je objekt uživatel. Nikde jinde v tom nevidím smysl, protože čistota práce by nestála za ty nároky na výkon. Celkově hodně zakládám na rychlosti aplikace, běh skriptu je pro mě optimální pod 20ms. Toho bych nikdy nemohl dosáhnout s převáděním dat z databáze na objekty.
Hm.
V tom případě by ta mezivrstva dávala jisté výhody, ale zase mi vrtá hlavou, proč jste se rozhodl pro návrh komunikační vrstvy s databází použít úplně jiný přístup, než k návrhu zbytku aplikace.
Není ale moc dobré kombinovat v aplikaci různá paradigmata. A pokud nepoužívání objektů vnímáte jako výkonovou optimalizaci (řekněme na úkor obecnosti), je zvláštní rozhodnutí použít to „méně výkonné paradigma“ zrovna na dejme tomu servisní vrstvu, která se bude volat poměrně často a na jejím výkonu bude záležet víc, než na výkonu těch vyšších vrstev.

běh skriptu je pro mě optimální pod 20ms. Toho bych nikdy nemohl dosáhnout s převáděním dat z databáze na objekty.
Proč ne?
Samozřejmě záleží na tom konkrétním skriptu, ale ohledně objektové režie PHP jsem narazil na číslo 13%, v takovém případě by u časů kolem 20 ms byl rozdíl asi 2-3 ms.
V každém případě mám za to, že podstatně víc času zaberou ty samotné databázové dotazy.

PDO podporuje hned několik úložišť a nezdá se mi, že by to bylo omezením.
Tak jistě, pokud chcete podporovat třeba dvě databáze které znáte předem, tak to fungovat bude.
Horší je to napsat tak, aby to do budoucna bylo rozšiřitelné o nějaký typ úložiště, který v době návrhu neuvažujete.
U té repository je to snadné, protože tam vlastně jde o to jen z toho úložiště ty informace nějak získat. U téhle nižší vrstvy to úložiště zároveň musí umět způsob dotazování, na který je ta vrstva navržená.
midlan
Profil
Joker:
ale zase mi vrtá hlavou, proč jste se rozhodl pro návrh komunikační vrstvy s databází použít úplně jiný přístup, než k návrhu zbytku aplikace.
Prostě mi přijde zbytečné vytvářet třídy a jejich objekty mít jen pro uskladňování dat. Nevidím nic špatného na používání standartních PHP polí.

zrovna na dejme tomu servisní vrstvu, která se bude volat poměrně často a na jejím výkonu bude záležet víc, než na výkonu těch vyšších vrstev.
Ano jsem si vědom toho že tahle moje vrstva může snížit výkon, ale opakování kódu na více místech v aplikaci mě už začalo docela štvát, proto jsem to chtěl dát na jedno místo, tam kam to patří.

Jednou z motivací pro vytvoření vrstvy bylo např. toto

Joker:
U téhle nižší vrstvy to úložiště zároveň musí umět způsob dotazování, na který je ta vrstva navržená.
Nemusí, dotazování nechci řešit přímo ve vrstvě ale nějak externě jako jsem ukázal v prvním příspěvku, není to tam úplně správně, ten generátor SQL dotazů by měl být spíš objekt ale to byl jen příklad. Jedná se mi o znovupoužitelnost, abych mohl vzít generátor dotazů a použít ho někde jinde s jinou db vrstvou. Už jen třeba protože bude automatizovat escapovaní a podobně.

EDIT: A vlastně diskuse se dost zvrtla k návrhu aplikace, ten měnit nechci. Chci opravdu jen generátor SQL, který podporuje více databází.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: