Hledání „Nette-like“ ORM pro PHP

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
dcepelik
Člen | 36
+
0
-

Nemáte někdo povědomí o ORM pro PHP, které by se ke konkurenci mělo asi tak stejně, jako se Nette má k té své ve světě PHP frameworků? To znamená: rychlé, jednoduché, intuitivní a svérázné.

Zkrátka takové „Nette-like“ ORM.

Zvažuji vývoj malého, svižného a modulárního CMS. Jsem plně pohroužen do Fowlera a Evanse, tedy chci rozhodně jít cestou DDD a „pětivrstvého modelu“ (Entity, Repository, Mapper, Service, Storage).

Zřejmou volbou může být Doctrine 2, ta mě však příliš neláká, neboť bych využil jen zlomek jejích funkcí a stavění malého/středního projektu na tak mohutném kusu software mi přijde přinejmenším jako zběsilý útok kanonem na nebohého (byť svižného a modulárního :)) vrabce. Doctrine patří (nebo už to tak ve verzi 2 není?) velkým projektům.

Jak naděje umírá, stále více se přikláním k variantě napsání vlastní jednoduché infrastruktury pro budování modelu.

Pěkný večer všem.

Filip Procházka
Moderator | 4668
+
0
-

Doctrine 2 bych tak rychle nezavrhoval, může se zdát velká, ale je překvapivě rychlá. A hlavně, řeší za tebe persistenci entit a ty se můžeš pak plně soustředit na DDD. Byl jsem k ní také skeptický, načti si reference, ať vidíš co všechno s ní nebudeš muset vynalézat :)

dcepelik
Člen | 36
+
0
-

Ahoj,

díky za odpověď!

Přeci jen tedy dám Doctrine 2 šanci. Vždycky mě trochu děsila její jedničková řada, možná proto ta averze.

Pěkný den

jtousek
Člen | 951
+
0
-

Doctrine 2 má tolik pokročilých funkcí, že kdybys ji chtěl použit až na zastřelení něčeho přiměřeně velkého tak by sis nevystřelil. :-) Je lepší začít od těch vrabců.

Momochodem Doctrine 1 a 2 mají společné v podstatě jen jméno. Dost věcí je v Doctrine překvapivě jednoduchá, naopak časem přijdeš na dost jiných věcí, které jsou překvapivě složité. Rozhodně ale doporučuji ji zkusit.

dcepelik
Člen | 36
+
0
-

Po zhruba měsíci a půl hledání bych rád shrnul jeho výsledky.

Nyní už mohu definitivně říct, že Doctrine 2 se pro mé potřeby nehodí. Tak ohromný balík funkcí (a ještě o něco více kódu) je pro „střední webové prezentace“ – jakkoli špatné označení to je – značný overhead.

Naopak Nette\Database založená na NotORMu se osvědčila. Je to (koncepčně) velice jednoduchý a rychlý nástroj, který má jasně vymezené funkce. Přesto i s Nette\Database narážím na zásadní problém: při jejím používání nevím, kam s doménovou logikou. Model řeším jako Domain Model (M. Fowler, PoEAA) a bohužel jsem nenašel rozumný způsob, jak ActiveRow s doménovou logikou provázat. Vzpomínám si, že dibi disponovala funkcí setRowClass, kterou bylo možné nastavit třídu výsledku.

Zřejmě mi tedy nezbude, než napsat nějakou vlastní nadstavbu nad Nette\Database, mám už pár nápadů. Nejprve bych se ale rád zeptal zkušenějších: používáte-li Nette\Database nebo podobný nástroj, jak stavíte vlastní entity?

(Řešení u Nette\Database by bylo triviální – přepsat Nette\Database\Table\Selection tak, aby vracelo vlastní třídu entity, pokud je k dispozici. Nechci ale zasahovat do stávajícího kódu: jednak by se tím v budoucnu zkomplikovala aktualizace Nette na existujícím projektu, jednak by to znamenalo, že Nette\Database s ničím takovým nepočítá a já používám nástroj nevhodný pro své potřeby.)

gawan
Člen | 110
+
0
-

A prečo nepoužiješ NotORM? Tá má funkciu $db->rowClass = ‚ClassName‘, to je ekvivalentné k setRowClass. A v NotORM sú aj iné vylepšenia, ktoré nie sú v Nette\Database.

dcepelik
Člen | 36
+
0
-

gawan napsal(a):

A prečo nepoužiješ NotORM? Tá má funkciu $db->rowClass = ‚ClassName‘, to je ekvivalentné k setRowClass. A v NotORM sú aj iné vylepšenia, ktoré nie sú v Nette\Database.

Díky za odpověď, o téhle funkci jsem nevěděl. (Není divu, tak nějak jsem předpokládal, že Nette\Database je v podstatě NotORM s upraveným API a přizpůsobené coding-standardu Nette.)

Zkusím tedy samotný NotORM.

Editoval dcepelik (14. 6. 2011 22:02)

gawan
Člen | 110
+
0
-

Jakub pridáva nové vlastnosti a opravy len do NotORM a pre Davida, zdá sa, nie je prioritou backportovať nové vlastnosti z NotORM do Nette\Database.

Odporúčam začni srigiho kuchárkou.

Tharos
Člen | 1030
+
0
-

V NotORM je ale $db->rowClass mám dojem globální pro všechny položené dotazy. To znamená, že se neurčuje pro samotný dotaz, jako je tomu například u dibi. Asi jediná šance, jak toto obejít, je změnit tuto proměnnou před každým dotazem, ale to je takové škrábání se levou rukou. Navíc jak naložit s „related“ entitami? Zkrátka to, aby NotORM při dotazu na tabulku user vracel instanci UserEntity a zároveň při dotazu na tabulku například page vracel instanci PageEntity, myslím momentálně nelze nijak rozumně zařídit. Opravte mě, pokud se mýlím.

Samozřejmě by nad to všechno šla udělat nějaká obálka, ale proč to dělat… Jakub myslím sám uvedl, že stavět ORM nad NotORM považuje za samoúčelné.

Tharos
Člen | 1030
+
0
-

@dcepelik: Pokud vydržíš ještě tak týden, připravuji screencast o budování modelu rozděleného do vrstev s entitami, repositáři a mappery, kde bude ukázkový mapper napsaný v dibi. Jsem časově ve skluzu, protože mám kašel a namlouvat v mém současném zdravotním stavu screencast by vyvolávalo u diváků napětí, zda-li se aktér dožije konce ;). Ale kódy už mám hotové, a tak kdybys chtěl nahlídnout…

Btw. u té mé koncepce není nejmenším problémem dopsat další mapper založený nad Nette\Database a jelikož se dibi už pravděpodobně nebude v budoucnu nijak rozvíjet, asi na ten mapper nad Nette\Database sám přejdu. Jedinou nevýhodou by bylo to, že by se tak zahodily ty jeho „related fíčurky“ a to jeho spojování tabulek, protože vazby mezi tabulkami osobně řeším až v repository vrstvě (u 1:N provazuji entity dokonce až v ještě vyšších vrstvách, inspirován NotORMem pomocí IN operátoru) a Nette\Database by samozřejmě figurovalo pouze v mapperu. V podstatě by tam pak Nette\Database sloužilo jen jako obálka nad PDO, ale zato kvalitní. Láká mě na tom to, že by to výkonem mohlo být i lepší než mapper využívající dibi a hlavně by to využívalo nativní součást Nette.

Z Tvých komentářů mám dojem, že jsem prošel úplně stejným rozčarováním, jako Ty. Doctrine 2 mě opravdu odradilo svou robustností a musím říct, že jsem mu dával šanci několikrát. Prostě mi k Nette nějak vůbec neladí… K Zendu asi super, ale Nette osobně pořád považuji za light-weight a nějak mi ty knihovny nejdou k sobě (totálně subjektivní pocit, tímto zcestným názorem se rozhodně nikdo neřiďte!).

NotORM je fajn a taky jsem ho chvíli používal, ale já jsem nepřekousl to, že se snažím psát vcelku hezký a čistý kód, a najednou se v něm dějí podobné čachry se všemi těmi __get(), __set(), __call(), ArrayAccessy a podobně. V mých očích je NotORM geniální, ale nějak neladí k mému kódu… Já chci v presenterech pracovat s konzistentními Entitami a ne s nějakými NotORM_Row a podobně. No a tak jsem si napsal ty jednoduché vrstvy, o kterých tvrdím, že jsou totálně nedokonalé, ale vyhovují mi určitě nejlépe.

Editoval Tharos (15. 6. 2011 0:45)

dcepelik
Člen | 36
+
0
-

@gawan: Ano, „kuchařku“ znám. Navrhovaný model je vlastně Active Record a proto mi není příliš blízký. To samozřejmě nesnižuje význam dobrého článku, děkuji za tip.

Co se týče neportování změn do Nette\Database: nedivím se. Udržovat ten kód neustále aktuální by bylo neúnosné.

@Tharos: Zdá se, že jsme vskutku filosoficky spřízněni! Doctrine vedle Nette působí neohrabaně, stejně tak u NotORMu mi vadí místy nadměrné užívání magie – přesně tak, jak popisuješ. Právě magie se David v Nette\Database elegantně zbavil, proto jsem se o ní tolik zajímal.

Také jsem se pokoušel něco málo napsat, ale nezaznamenal jsem velký úspěch. Měl jsem problém uvést do provozu některé pokročilé Fowlerovy vzory z PoEAA, mj. právě „pětivrstvý model“, o kterém hovoříš. Základní implementaci jsem sice zvládl, ale výsledek vlastní práce mě nijak nenadchl, a tak jsem se vydal do druhého kola.

Samotná myšlenka doménového modelu založeného na entitách, mapperech a repozitářích je mi nicméně velice sympatická. Stejně jako Ty jsem se snažil tvořit vrstvy tak, aby byly nezávislé na konkrétní knihovně (resp. delegovaly relevantní úlohy na příslušné mappery).

Pokud bys byl ochoten zpřístupnit svůj kód k nahlédnutí, podívám se velmi rád. Na oplátku, obávám se, mohu ale nabídnout jen teoretickou diskusi.

Editoval dcepelik (15. 6. 2011 0:02)

Tharos
Člen | 1030
+
0
-

@dcepelik: Pošli mi e-mail (přes profil), klidně příklad těch kódů někdy během dneška pošlu. Ber ale určitě na vědomí, že je to jen úplné jádro bez nějakých ozdob a není to v tom kódu, co bych poslal, nijak hezky integrované v podobně služeb. To už mám též realizované (i spolu s několika dalšími myšlenkami), ale nemám „volnou“ ukázku, kterou bych mohl zaslat (rozuměj vše je součástí nějakých projektů, kde bohužel nesmím šířit kódy).

No, jsem docela zvědav na oponenturu, protože ono je to v principu podle mě úplně banální kus kódu a má to celé opravdu pár řádků (cca 400 důležitých). Ale mně se s tím prostě pracuje dobře… A omezenou funkcionalitu mi dostatečně kompenzuje to, že to nepotřebuje 333 includovaných souborů. :)

vrana
Člen | 131
+
0
-

Doporučoval bych nechat doménovou logiku (model) od NotORM zcela oddělenou. NotORM neumožňuje individuální nastavení vracené třídy ani žádné mapování zcela záměrně. Možnost centrálního nastavení vracené třídy existuje jen kvůli možnosti upravit způsob práce s daty, např. kvůli jazykovým verzím. Do šablony je vhodné posílat (nebo si v šabloně z modelu vytáhnout) právě jen NotORM_Row (nebo jeho potomka), který umí zpřístupnit data, umí pracovat s relacemi, ale neumí nic jiného. Prezenter naopak může prostřednictvím modelu vesele pracovat s celými doménovými objekty.

I ta magie má své opodstatnění. Zdá se mi totiž v pořádku v šabloně použít prosté $comment->article['title'], protože šabloně může být jedno, jestli v $comment je NotORM_Row nebo třeba stdClass. Už méně v pořádku mi přijde v šabloně použít $comment->ref('article')->title (a to pominu, že i to ->title je magie).

gawan
Člen | 110
+
0
-

Jakub, že by bolo výborné, keby si si našiel čas urobiť ten videotutoriál alebo článok (to je jedno), ktorý si sľuboval pred nejakým časom, ako robiť modely a doménovú logiku pri použití NotORM, najlepšie v nette na nejakom jednoduchom príklade. Zdá sa, že viacerí nad tým rozmýšľame a hľadáme best-practice riešenie.

srigi
Nette Blogger | 558
+
0
-

gawan – uplne jednoduchu domenovu logiku dosiahnes, tak ze si postavis nejaku service vrstvu napr. nad tym mojim tut. Proste nebudes v Presentri volat $this->getModel(), ale napises si nejaky wrapper (najlepsie ako Nette servicu) $this->context->articleService(), tej mozes pomocou DI predat pole Modelov a tu domenu proste strcit tam.

Moznosti je kopec, staci experimentovat. Napr. tak, ze zacnes robit s tou mojou Diggriolou, a casom ked sa ti nakopi logika v Presentroch, supnes to do service vrstvy.

_Martin_
Generous Backer | 679
+
0
-

@Tharos: Mohl bys mi taky poslat ukázky kódu? Dělám v práci na jednom větším projektu a taky jsem byl dohnán k psaní si vlastního podobného „ORM“ – z podobných důvodů jako ty. Mám v hlavě i nějaké nápady, jak následně takovou modelovou vrstvu přátelsky propojit s Nette (v konečném důsledku by programátor nemusel nikde pracovat s IDčky, ale to je na delší povídání=)).

Ot@s
Backer | 476
+
0
-

Má někdo ze zúčastněných nějakou novinku/novou zkušenost (ohledně tohoto vlákna)?

Tharos: Nechci „uhánět“, ale neměl bys prosím ten zmíněný screencast?

dcepelik
Člen | 36
+
0
-

Ot@s napsal(a):

Má někdo ze zúčastněných nějakou novinku/novou zkušenost (ohledně tohoto vlákna)?

Vyměnili jsme si s Tharosem několik e-mailů k tématu. I díky němu teď pracuji na velmi jednoduché vrstvě, která je schopna rozumným způsobem řešit persistenci entit. Jednalo by se o nadstavbu nad knihovnami jako NotORM, Nette\Database či dibi.

Jakmile bude věc publikovatelná, uveřejním zde.

Editoval dcepelik (23. 6. 2011 15:16)

Ot@s
Backer | 476
+
0
-

Připomínám toto vlákno a společně s ním i další podobné, dnes již uzavřené. Řeším toto téma už měsíce, ale stále nic defintivního, resp. uspokojujícího. Ach, ta vnitřní nespokojenost :-(

Tharos
Člen | 1030
+
0
-

Když už jsem se do tohoto vlákna před nějakým časem zapojil, doplním své myšlenkové pochody od mého posledního příspěvku. :)

Od dalšího vývoje té své vlastní vrstvy jsem opustil, protože jsem si na vlastní kůži vyzkoušel jednu věc. Napsat hezký základ vrstevnatého modelu je práce na dva večery (viz třeba HosipLanův článek v kuchařce na toto téma), nicméně komplexnost problému exponenciálně roste, jakmile se začnou řešit vztahy mezi entitami a podobně. Prostě jsem prozřel, že podchytit vše, co už je vyřešeno například v Doctrine 2 či NotORMu, by pro mě osobně byla práce na XYZ hodin a stejně bych to nenapsal lépe, než už to ve zmíněných knihovnách je. Takže tudy cesta nevedla.

Na tomto dojel i můj záměr natočit o vývoji screencast – postupem času mi totiž došlo, že bych prezentoval vývoj něčeho, co v podstatě ale nemá vyvíjet smysl… a to se mi nechtělo.

Mám drobné zkušenosti s Doctrine 2. Doctrine 2 mě v podstatě od začátku nijak extra nepřitahovala (asi ze stejného důvodu, jako například Zend), ale dal jsem jí párkrát šanci, abych si vždy zase znovu uvědomil, že to prostě není nic pro mě. Co mi na ní namátkou opravdu vadilo:

  • Programování v anotacích. Anotace jsou super, ale u tříd, kde je více myšlenek realizováno v komentářích než v kódu samotném, jsem trochu na vážkách. Děsně mě štve, že v anotacích mi nenapovídá IDE, nezvýrazňuje mi syntaxi, zkrátka je to totální magnet na chyby a překlepy. Já ale chápu, že to v PHP prostě lépe vyřešit momentálně nelze, ale tak pokud chci vyvíjet tímto způsobem, použiji jiný jazyk (třeba jazyk, který má podporu pro anotace na úrovni jazyka).
  • Řada věcí mně přišla děsně neohrabaných a zdržujících při vývoji. Třeba takové DQL, které se skutečně u složitějších struktur musí používat skoro všude – chápu, že oproti SQL je to velký krok kupředu, ale oproti NotORM-like API je to totální brzda.

Čím dál tím více ve svých projektech tedy používám NotORM (který tedy tak nějak „zbyl“) a musím říct, že po nějakém čase jej mám rád čím dál více. Trochu času mi zabralo zvyknout si na ten lehce odlišný styl přemýšlení a také na to svérázné API, ale vše má (jak u Jakuba bývá zvykem) velmi jasně danou logiku, která se mi po nějakém čase skutečně zaryla pod kůži.

Mám pocit, že NotORMu se často vytýká to, že nijak neřeší doménovou logiku a nezabrání tomu, aby se model nedostal do nekonzistentního stavu (na což má Doctrine 2 robustní ochrany). Pokud nepotřebujete měnit databázový systém on-fly a můžete využít možností jednoho vybraného, u většiny systémů tento argument padá (minimálně u novějších verzí MySQL). Nejednou jsem si vyzkoušel, že za pomocí triggerů a vlastních chybových zpráv lze vytvořit takovou databázi, ve které se vám ani omylem nepodaří udělat změnu, která by způsobila narušení doménové logiky (a nesetkal jsem se v praxi s ničím, co by se nedalo v uložených procedurách zvalidovat). A pak je to hračka, protože invalidní akce s NotORMem prostě skončí výjimkou. Ve spojení s důsledným používáním cizích klíčů a striktním módem MySQL mi to skutečně přijde robustnější, než celá Doctrine 2. Co vůbec udělá Doctrine 2, když jí někdo do databáze nějakým jiným kanálem vloží nevalidní data? To se může stát velice snadno (například při nějakém importu dat). Nevšiml jsem si, že by Doctrine 2 generovala ochranu i do databázové vrstvy (kromě cizích klíčů).

Prostě mám pocit, že když jako programátor budu chtít, konzistenci modelu založeného na Doctrine 2 prostě naruším, zatímco konzistenci modelu, který má business pravidla na úrovni databáze nikoliv (samozřejmě databázový uživatel nesmí mít práva volat DROP TRIGGER a podobně…).

Vývoj s NotORMem je to nejrychlejší, co jsem kdy zažil a díky malému množství kódu je málo náchylný k chybám a minimálně u mých aplikací tak klesla i chybovost (a opravdu nejsem placen za to, že bych mu dělal reklamu, jsou to jen mé zkušenosti). Takže pro mě je tím Nette-like ORM momentálně NotORM. :)

Gratuluji všem, co se dočetli až sem :).

na1k
Člen | 288
+
0
-

Tharos, pěkné promo :))

Na jak dlouho bys odhadl dobu přechodu od dibi k NotORM? Za předpokladu, že jsem ó-er-emkem netknutý.

Filip Procházka
Moderator | 4668
+
0
-

Tharos napsal(a):

Toš já ti k tomu přihodím pár poznámek :)

  • Programování v anotacích. Anotace jsou super, ale u tříd, kde je více myšlenek realizováno v komentářích než v kódu samotném, jsem trochu na vážkách. Děsně mě štve, že v anotacích mi nenapovídá IDE, nezvýrazňuje mi syntaxi, zkrátka je to totální magnet na chyby a překlepy. Já ale chápu, že to v PHP prostě lépe vyřešit momentálně nelze, ale tak pokud chci vyvíjet tímto způsobem, použiji jiný jazyk (třeba jazyk, který má podporu pro anotace na úrovni jazyka).

Komentáře – uvažuju o annotacích jako o metadatech. Když je reader čte, kontroluje ti syntaxi, takže ten jazyk má pevně dané hranice a mně osobně to velice vyhovuje. Pokud s tím máš ovšem základní filosofický problém, vždycky tu máš ještě možnost PHP mappování a externí XML/YAML.

Napovídání – v Netbeans si můžeš napsat code-templates. Není to sice plnohodnotné napovídání, ale na jednoduché šablonky annotací to stačí. Používám to i u PHPUnit, kde se expectedException, dataProvider a další opravdu hodí :)

Netbeans umí annotace i ztučnit. Doctrine konzole umí annotace validovat a schéma si můžeš verzovat Migracemi a zběžně kontrolovat v databázi.

  • Řada věcí mně přišla děsně neohrabaných a zdržujících při vývoji. Třeba takové DQL, které se skutečně u složitějších struktur musí používat skoro všude – chápu, že oproti SQL je to velký krok kupředu, ale oproti NotORM-like API je to totální brzda.

DQL je místy otravné. Ale odkojený na dibi, jsem si na to rychle zvykl :) Dobré je, že člověk si může ty custom DQLka psát do repozitářů.

Mám pocit, že NotORMu se často vytýká to, že nijak neřeší doménovou logiku a nezabrání tomu, … Co vůbec udělá Doctrine … Nevšiml jsem si, že by Doctrine …

To ani není účelem. Doctrine totiž svou podstatou degraduje databázi na pouhé relační úložiště. Dalo by se spekulovat, jestli je to správně, ale tu doménovou logiku prostě není technicky možné přenášet i do databáze, když může být kdekoliv v kódu.

Prostě mám pocit, že když jako programátor budu chtít, konzistenci modelu založeného na Doctrine 2 prostě naruším…

To není pocit, ale fakt. Otázkou je, jak moc velký je to problém.

Takže pro mě je tím Nette-like ORM momentálně NotORM. :)

Ať slouží ;)

edke
Člen | 198
+
0
-

Po precitani prispevku @Tharos pridam svojich 5 centov. Priblizne rok som pouzival Doctrine2 a postavil som na nom asi 4–5 projektov. Za ten rok som si upravil vsetko, aby Doctrine co najlepsie vyuzivalo. Uvod je rychly a praca s entitami je naozaj prijemna. Velmi mi vyhovovalo, ze som mal konecne verziovanu schemu a lahko v production bolo aplikovat zmeny.

Postupne som ale sa dostaval do situacii, kedy som si nad relativne trivialnymi ulohami v DQL musel lamat hlavu a efektivita vyvoja sla prudko dole vodou. A co je este horsie, s pribudajucou komplexnostou rastla aj narocnost na renderovanie jednej stranky. Pri chybnom DQL su exceptions nocnou morou, prist nato, co je problem je niekedy neuveritelna robota.

Takze znovu spat k hladaniu lepsej cesty. Preto aj som mal subscribnute toto vlakno. Prestudoval som vsetko co som nasiel o NotORM, Nette\Database a este kopu dalsich informacii o PHP a ORM.

Nakoniec som nasiel riesenie, ktore sa mi ukazuje ako najlepsie, ake som kedy mal moznost pouzit (a pritom tu vzdy bolo, len som bol lenivy sa naucit asi nieco ine a pripustit ze nie vsetko treba riesit v PHP) a to presunut maximum logiky do databazy. Uz roky pouzivam PostgreSQL a po poslednych releasoch (8.4, 9.0) je naozaj malo, co by absentovalo. Prave som ukoncil presun strednej aplikacie napisanej v Doctrine do Postgre a som nadseny. Render time vyrazne klesol, mam totalnu kontrolu nad queries, mozem optimalizovat podla potreby, ako maly bonus: pri PDO exceptions mam vdaka Nette\Database v ladenke problemove query, atd. Takmer vsetko co som potreboval som presunul do procedur, triggerov a views. Postgre v projekte konecne robi to, naco je urcene a nie je to len hlupe ulozite dat pre nejake ORM. Ako db layer som pouzil Nette\Database, pretoze mi proste vyhovuje sposob, akym David navrhne API, je to citatelne, mam k tomu skvelu dokumentaciu a robi to (takmer) vsetko co potrebujem.

Precital som si kopu prispevkov na tomto fore, co vsetko Nette\Database nevie a co vsetko NotORM vie. Po 3 tyzdnoch prepisovania aplikacie viem, ze nenastane situacia, na ktoru mi Nette\Database nebude stacit. Pride mi uplne nezmyselne znovu objavovat koleso a snazit sa porozumiet miestami neprehladnemu zapisu v NotORM, ked si proste v databaze vyskladam VIEW, kde si najoinujem co potrebujem, ako potrebujem, a ak to bude pomale, prepisem si query podla potreby optimalnejsie. Ak je potreba viac queries (jedno monster velke query bude prilis velke, pomale a neprehladne) na vyskladanie idealnej otazky, pouzijem namiesto VIEW proceduru, ktorej aj predam potrebne parametre a nemusim uz skladat podmienky. Potom pouzijem trivialny zapis v Nette\Database (patch):

$context->database->table(new SqlLiteral("task_default($project, $developer)"));

Na database development-e mi vzdy vadilo, ze nie je trivialne verziovat schemu, pripadne data. Podla vzoru Doctrine Migrations som si za par hodin napisal cli nastroj na generovanie patchov a ich aplikovanie. Ako nastroj na vygenerovanie up/down patchov sluzi apgdiff, ktory na zakladne sql patche sluzi velmi dobre, podla potreby je tak ci tak potrebne vzdy este rucne takyto patch doladit (napriklad pridanie not null stlpca do tabulky, nutne pridat ako null, naplnit potrebnymi hodnotami, napr. v zavislosti od ostatnych stlpcov a nasledne zmenit na not null). apgdiff pracuje so schemami, na tie posluzil skvelo pg_dump. Pre vygenerovanie up patch-u staci porovnat dev schemu s ostatnou (ulozenou v git-e), pre vygenerovanie down patch-u staci schemy vymenit.

Verziujem teda vzdy aktualnu schemu databazy a potom vsetky patche, od uvodneho patchu 0001 (uvodna schema) az po aktualny. V database (v samostatnej scheme) je ulozena aktualne aplikovana schema.

Potom uz len staci vhodny nastroj (pouzivam pgAdmin, ktory mi uplne postacuje, pripadne Adminer, ten vsak este postrada moznost spravovat funkcie, nahlasene) a Database development sa moze zacat :-)

Prestal som teda snazit sa robit v PHP a v Nette vsetko a nechal som ho robit len to, naco je PHP (a Nette) dobre (napr. routrovanie, presentery, sablony). Postgres nech sa postara o logiku, data a ich pripravu (views, functions) na lub. sposob, tak ako ich dany presenter/sablona potrebuje.

Ako dobry podklad na studium o tematike napr. blog Kenneth-a Downs-a, postaci tento clanok Why I Do Not Use ORM, z neho je potom dalej mnozstvo linkov na dalsie jeho clanky ako aj na clanky a prispevky v diskusii ako reakcie, napriklad zaujimavy clanok o triggeroch Database triggers are evil.

A teraz idem slavnostne zo spominaneho projektu dropnut vsetko, co nejako suvisi s Doctrine :)

Tharos
Člen | 1030
+
0
-

@na1k: Já myslím, že přechod může být velmi rychlý, protože na oficiálním webu je v podstatě vše pokrývající dokumentace. K ní můžu dodat jen to, že ač se to nezdá, je v ní opravdu vše (i složitější konstrukce, které jsou zde na fóru všemožně roztroušené, zní lze vydedukovat), akorát „hustota informací“ je tam místy krapet větší, a tak já osobně jsem některé věci plně vstřebal až po pár experimentech.

Co se u mě osobně o něco déle formovalo byla právě ta integrace do Nette. Koukal jsem, že existuje třeba jakási obálka od Srigiho, a já sám jsem při prvních experimentech měl tendenci NotORM nějak „obalovat“, než jsem pochopil, že to je vlastně úplně zbytečné. Je to jako kdybys u Doctrine 2 ještě nějak obaloval EntityManager. Jen je dobré zažít si nějakou štábní kulturu, aby se do šablon dostávaly už jen instance NotORM_Row či NotORM_Result (jako je tomu například u examples Nette\Database) a pak už to jde samo. Zrovna tak například handlerům formulářů, které upravují nějaký záznam předávám pouze potřebné NotORM_Row (vysvětlím ty handlery – já dost striktně odděluji obsluhu formulářů od jejich definic a píši na vše třídy, nemám rád, když se tímto za..dělávají presentery).

Tharos
Člen | 1030
+
0
-

@edke: Díky za tenhle post, to jsem přečetl na jeden dech :). Když ještě nebyl venku NotORM a já řešil modelové dilema, byl jsem rozhodnut jít přesnou touto cestou. Dodnes jsem přesvědčen, že se to v podstatě blíží ideálnímu řešení, ale tak nějak jsem si teď navykl na ten NotORM. :)

Ještě poznámka k tomu NotORM API – ono není tak magické, jak se zdá. Spíš se jen opravdu nepodobá ničemu jinému (snad možná jen SimpleXML má podobné API) a vůbec NotORM vyžaduje lehce specifický styl myšlení. Má zkušenost ale je, že rychle „vleze pod kůži“ a pak je vývoj nesmírně rychlý. Samozřejmě to ale nemusí tak být u každého.

Tharos
Člen | 1030
+
0
-

HosipLan napsal(a):
Komentáře – uvažuju o annotacích jako o metadatech. Když je reader čte, kontroluje ti syntaxi, takže ten jazyk má pevně dané hranice a mně osobně to velice vyhovuje. Pokud s tím máš ovšem základní filosofický problém, vždycky tu máš ještě možnost PHP mappování a externí XML/YAML.
Napovídání – v Netbeans si můžeš napsat code-templates. Není to sice plnohodnotné napovídání, ale na jednoduché šablonky annotací to stačí. Používám to i u PHPUnit, kde se expectedException, dataProvider a další opravdu hodí :)

Netbeans umí annotace i ztučnit. Doctrine konzole umí annotace validovat a schéma si můžeš verzovat Migracemi a zběžně kontrolovat v databázi.

Samozřejmě, všechno to lze vyladit. Filosofický problém s anotacemi už jsem překousl :), ale ten praktický mi nějak zůstal. Anotace považuji za vynikající pro označení persistentního parametru, provideru u PHPUnitu, zkrátka všude, kde se pracuje vesměs s jedním slovem, ve kterém snad překlep neudělám, a s jednoduchou logikou, kterou nezkazím. To u Doctrine 2 s anotacemi přes několik řádků a s návaznostmi anotací napříč entitami (vlastníci versus inverzní strany) není splněno. Na můj vkus se tam toho prostě musí psát do komentářů neúměrně moc – zde bych velmi uvítal nějakou konvenci před konfigurací.

To, co jsi psal o těch code-templates v NetBeansech, zvýrazňování… to samozřejmě všechno lze vyladit. Ale mně osobně to přijde neúměrně pracné a zdržující. Navíc v tom nejsou žádné vyšlapané cestičky, a tak si člověk se vším musí pohrát sám. Já hledám nástroj, který mi bude sloužit, a ne něco, kvůli čemu budu ladit IDE, aby se to dalo alespoň nějak pohodlně používat. :)

To ani není účelem. Doctrine totiž svou podstatou degraduje databázi na pouhé relační úložiště.

A to mi právě přijde, že v případě 99,9% aplikací není nejlepší přístup (tím 0,1% jsou aplikace, které mají běžet na různých DBS a zároveň jim nestačí jen nějaká jednoduchá DBAL). Viz příspěvek od Edkeho. Dnešní databáze jsou mocné a je zbytečné suplovat jejich možnosti tak trochu neohrabaným způsobem někde jinde.

To není pocit, ale fakt. Otázkou je, jak moc velký je to problém.

No, je to problém takový filosofický, protože mi přijde, že něco, co si Doctrine 2 klade za úkol a mimo jiné i kvůli tomu je takový moloch, vlastně pořádně neřeší. :) Tak trochu patovka a já z toho cítím takový „neutěšený stav“.

Ať slouží ;)

Díky, uvidíme, jak dlouho vydrží :). V záloze mám kdyžtak právě tu celou business logiku v databázi, chci si to někdy minimálně vyzkoušet :).

Editoval Tharos (16. 8. 2011 22:45)

jtousek
Člen | 951
+
0
-

Tharos: Moc zajímavé příspěvky. ;-) Mohl bych se zeptat na tvůj názor na Nette\Database vs. NotORM? Co ti v Nette\Database chybí, vadí atd., prostě proč jsi zůstal u NotORM a nepřešels k Nette\Database?

Tharos
Člen | 1030
+
0
-

@jtousek: Když bylo vydáno Nette\Database, už jsem měl něco málo napsáno v NotORMu, takže jiné API Nette\Database pro mě bylo spíš nezvykem :). Nicméně když přišlo Nette\Database, měl jsem přirozeně tendenci přemigrovat, ale nakonec jsem si to hlavně ze dvou následujících důvodů rozmyslel (a ani dnes bych se nerozhodl jinak):

  1. NotORM obsahuje možnost nadefinování vlastních vazebních konvencí. To jsem k mému vlastnímu překvapení v praxi už několikrát použil. Naposledy minulý týden :), kdy jsem databázi „dostal darem“ (doprogramovával jsem jenom jeden e-learning na subdoméně a část dat jsem tahal z již existující databáze). Jelikož ta databáze obsahovala výjimky oproti standardní konvenci (například sloupec parent namísto table_id a pár podobných), vážně se mi ta možnost hodila. Nevím, jestli by tohle v současné době v Nette\Database vůbec nějak šlo vyřešit.
  2. Tohle je dost subjektivní, nicméně… NotORM má IMHO slušnou podporu (Jakub reaguje na dotazy de facto v řádech minut až hodin) a aktivně se vyvíjí. Nette\Database fandím, ale poslední vyloženě Davidovo (tj. autorovo) commity mají nějaký červnový datum a podpora je taková, že Ti zde na fóru na případné dotazy napíše Jakub, abys zkusil namísto jej použít NotORM, protože tam je problém XYZ už vyřešen. :)

Plus hlavně z poslední doby má NotORM pár užitečných nových vymožeností, u kterých si nejsem jist, jestli už je někdo portoval do Nette (ale tipuji, že nikoliv).

EDIT: Když si tu tak po sobě čtu, tak mám znovu tendenci upozornit na to, že nejsem zaměstnancem „NotORM foundation“ a jde skutečně pouze o slova spokojeného uživatele :).

Editoval Tharos (16. 8. 2011 21:19)

jtousek
Člen | 951
+
0
-

Kruci tak teď už zase váhám jestli to NotORM přeci jen nezkusit. :D:D Díky, Tharos. ;)

edke
Člen | 198
+
0
-

Tharos wrote:

@edke: Díky za tenhle post, to jsem přečetl na jeden dech :). Když ještě nebyl venku NotORM a já řešil modelové dilema, byl jsem rozhodnut jít přesnou touto cestou. Dodnes jsem přesvědčen, že se to v podstatě blíží ideálnímu řešení, ale tak nějak jsem si teď navykl na ten NotORM. :)

Ještě poznámka k tomu NotORM API – ono není tak magické, jak se zdá. Spíš se jen opravdu nepodobá ničemu jinému (snad možná jen SimpleXML má podobné API) a vůbec NotORM vyžaduje lehce specifický styl myšlení. Má zkušenost ale je, že rychle „vleze pod kůži“ a pak je vývoj nesmírně rychlý. Samozřejmě to ale nemusí tak být u každého.

V jednom vacsom projekte riesim ale situacie, kde mi NotORM nepomoze. Tu mi pomahalo Doctrine a jeho entita a teda pri hladani nahrady som musel na tento problem mysliet.

V spominanom projekte je databaza uloziste ako pre webove UI pre uzivatelov, tak pre zariadenia, ktore komunikuju s databazou cez socketovy server (zhodnou okolnosti tiez mnou po X-ty krat prepisany a napisany v PHP, nakoniec krasne funkcny a stabilny vdaka prestudovaniu zdrojovych kodov apache web servra a implementacii Semaphores in PHP).

Niektore properties ukladane do databazy je potrebne pre socketovy server prekladat do ciselnych interpretacii ale pre potreby Web UI zas do vyznamovych textovych. Napriklad power, ON a OFF ale pre potreby socketoveho servra 0×30 a 0×31. Toto samozrejme krasne v Doctrine mi riesila entita a konkretny getter a setter pre danu property. Ale aj tam boli situacie, ze danu property som obcas potreboval v jednej aj druhej podobe.

Samotny postgre mi tuto situaciu riesi elegantne. Pre interne ulozenie dat zvolim vlastny datatyp ako enum a potom podla potreby napisem cast functions, alebo rovno VIEWS spolu s castingom.

CREATE TYPE power AS ENUM
   ('on',
    'off');

CREATE TABLE device
(
  id serial NOT NULL,
  power power NOT NULL,
  CONSTRAINT device_pkey PRIMARY KEY (id)
);

CREATE OR REPLACE FUNCTION int4("value" power)
  RETURNS integer AS
$BODY$
  begin
    IF ( value = 'on'::power) THEN RETURN 48;
    ELSIF (value = 'off'::power) THEN RETURN 49;
    ELSIF (value = null) THEN RETURN null::integer;
    ELSE
    raise exception 'Unable to cast % to integer.', value;
    END IF;
  end;
$BODY$
  LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION power("value" integer)
  RETURNS power AS
$BODY$
  begin
    IF ( value = 48) THEN RETURN 'on'::power;
    ELSIF (value = 49) THEN RETURN 'off'::power;
    ELSIF (value = null) THEN RETURN null::power;
    ELSE
    raise exception 'Unable to cast % to power.', value;
    END IF;
  end;
$BODY$
  LANGUAGE plpgsql;

CREATE CAST (integer AS power)
  WITH FUNCTION power(integer)
  AS ASSIGNMENT;

CREATE CAST (power AS integer)
  WITH FUNCTION int4(power)
  AS ASSIGNMENT;

INSERT INTO device (power) VALUES ('on'), ('off');
INSERT INTO device (power) VALUES (48), (49);

CREATE VIEW device_for_sockets AS
 SELECT device.id, device.power::integer AS power
   FROM device;

select * from device;
 id | power
----+-------
  1 | on
  3 | on
  4 | off
  2 | off

select * from device_for_sockets;
 id | power
----+-------
  1 |    48
  3 |    48
  4 |    49
  2 |    49

Pekne, nie ? :)

Da sa ist dalej. Aby sa neduplikoval kod a samozrejme ze casto ciselnik je potrebne mat pristupny v aplikacii, pomoze funkcia, ktora vrati zoznam enum typu ako query result:

CREATE OR REPLACE FUNCTION get_power()
  RETURNS SETOF character varying AS
$BODY$
  declare
    value power;
  begin
    for value in select unnest(enum_range(null::power))
      loop
        value :=  cast(value as character varying);
        return next value as "name";
      end loop;
    return;
  end;
$BODY$
  LANGUAGE plpgsql;

select * from get_power();
 get_power
-----------
 on
 off

$options = $context->database->table(new SqlLiteral('get_power()'))
	->fetchPairs('get_power', 'get_power');
$form->addSelect('power', 'Power', $options);

V pripade multilingualnej aplikacie sa da pekne extraktovat takyto retazec (ak mame schemu verziovanu), ja pouzivam forknutu verziu gettext-extractor-a od autorov Karla Klimu a Ondřeje Vodáčeka, ktora sa da krasne rozsirovat podla potreby. Napriklad, aby parsoval .sql subory a hladal create types.

Milo
Nette Core | 1283
+
0
-

@edke: Rád vidím, když PostgreSQL někdo využívá víc, než pro SELECT/INSERT/UPDATE/DELETE. Začal jsem s ní dělat ve verzi 7.1 a dodnes jsem neměl důvod přejít na jinou databázi. A přesně jak píšeš. Spousta logiky se dá přesunout přímo do databáze. Když si člověk nastuduje uložené procedury, triggery, rules, domény, typy otevře se mu najednou tolik možností, až radostí poskočí na židli :) Třeba že INSERT/UPDATE/DELETE se dá dělat i na VIEW.

Mimo PL/pgSQL a PL/Perl(u) jsem koketoval i s PL/PHP (psaní uložených procedur v PHP). Sice se moc neosvědčil, ale zajímavá zkušenost.

Od verze (asi) 8.3 zpracování vyjímek v procedurách, velká pecka.

apgdiff je rozhodně dobrý nástroj, také jsem ho nějaký čas používal. Ale díky tomu, že Postgres využívám tak komplexně, po čase mi přestal stačit. Verzování řeším v podstatě jako ty. Diffy a celé schema pg_dumpem. Místo pgAdmin mám ale koupený EMS SQL Manager for PostgreSQL. Je velmi intuitivní a za ten peníz to rozhodně stálo. Doporučuji zkusit trial verzi. Jednou z výhod je, že před jakoukoliv změnou schématu zobrazí odesílaný SQL dotaz. A ten si kopíruji do diffu. Když má člověk rozmyšleno, jak má tabulka vypadat, vytvořit jí i s cizíma klíčema a popiskem je otázka pár minut.

Také mám rozepsaný vlastní diff nástroj, který porovná jak schema tak data z dumpů anebo oproti živé DB, ale chybí mi motivace dokončit ho.

Promiňte mi tuhle ódu, nemohl jsem si pomoct :)

edke
Člen | 198
+
0
-

Milo wrote:

Třeba že INSERT/UPDATE/DELETE se dá dělat i na VIEW.

Hm, nad tymto som presne uvazoval, ze toto by sa zislo, uz som si zacal studovat RULES.

Mimo PL/pgSQL a PL/Perl(u) jsem koketoval i s PL/PHP (psaní uložených procedur v PHP). Sice se moc neosvědčil, ale zajímavá zkušenost.

Aj ja som nad tym uvazoval, ale myslim ze nie je dovod, PLPGSQL je dostatocujuce a hlavne PHP je vzdy interpretovane, rychlejsie urcite nie je.

Od verze (asi) 8.3 zpracování vyjímek v procedurách, velká pecka.

apgdiff je rozhodně dobrý nástroj, také jsem ho nějaký čas používal. Ale díky tomu, že Postgres využívám tak komplexně, po čase mi přestal stačit. Verzování řeším v podstatě jako ty. Diffy a celé schema pg_dumpem.

Ja som uz prisiel nato, ze napriklad TYPES apgdiff nepozna. Urcite to nebude kompletny nastroj, ale aspon pomoze s tymi jednoduchymi trivialnymi rozdielmi a zbytok rucne.

Místo pgAdmin mám ale koupený EMS SQL Manager for PostgreSQL. Je velmi intuitivní a za ten peníz to rozhodně stálo. Doporučuji zkusit trial verzi. Jednou z výhod je, že před jakoukoliv změnou schématu zobrazí odesílaný SQL dotaz.

Ja som ale na linuxe a nemam rad ani wine, ani virtualizaciu, nativne ak sa da. A pgAdmin mi staci. EMS SQL poznam, urcite ta pridana hodnota ako za komercny produkt sa prida. Ak by som bol na Win, isto by som si nejaky nastroj kupil. Zatial ale pgAdmin staci.

A ten si kopíruji do diffu.

Musim vyspekulovat, nejaky sql history log by sa pridal, isto by to pomohlo rychlejsie vyskladat diff patch.

Tharos
Člen | 1030
+
0
-

Pánové, jenom vám chci říct, že se mi takového využití možností PostreSQL vážně líbí. :) Zrovna na tomto použití je vidět, o kolik je PostgreSQL napřed oproti MySQL. Třeba jenom ty výjimky v procedurách jsou úžasné, v MySQL lze posílat vlastní chybové zprávy asi až od verze 5.5 (klauzule SIGNAL).