Článek v rubrikách:
DbDibiOrm
Rozcestí moderované diskuse pro tvorbu ORM nad dibi. Rozhodl jsem se programovat orm postavené nad dibi, pokud Vás téma zajímá, zapojte se prosím do diskuse. Tento článek slouží jako úložiště odkazů na články, které řeší jednotlivé problémy při tvorbě a vedli mne k vytvoření ORM.
Začalo to potřebou přepracovat mé staré ORM, které trpělo mnoha neduhy. Asi bude více pokusů o vytvoření podobného systému, ale snad tady najdete alespoň pochopení proč se takové ORM chová tak jak se chová.
POZOR MISE ČLÁNKU BYLA ZMĚNĚNA! Chci tady vytvořit prostor pro moderovanou diskusi o tvorbě ORM nad dibi. Tedy vyzývám Vás, aby kdokoli co má k tématu co říci, nechť se zapojí! Tento článek je schromaždiště odkazů na články zabývající se jednotlivými rozcestími při tvorbě takového ORM. Vyberte si téma, ke kterému máte co dodat a pište do komentářů. Případně pište návrhy na témata!
Zdrojový kód se nachází na github, pozor je to pouze koncept! Celá podoba se může naprosto změnit!
- ORM, Zend_Db, Doctrine, DibiTableX a co bych navrhl pro dibi (Jak to začalo a jak to fungovalo.)
- ORM, Row Data Gateway, Table Data Gateway, Active Record, Data Mapper (O čem se vlastně bavíme, pár pojmů ohledně ORM, kde a co číst.)
- DbDibiOrm - DibiConnection - staticky, instančně, přistupovat přímo k dibi factory? (statické získání connection k databázi nebo instanční nebo globální statická factory?)
- MySQL povinné hodnoty, NULL hodnoty, defaultní hodnoty, prázdné hodnoty a jak by se mělo chovat ORM (Jste si jisti, že víte jak k těmto základním problémům přistupuje mysql? Pokud chceme něco automaticky mapovat, musíme alespoň vědět jak fungují základy, co očekáváme od funkcí isset, is_null apod.)
- ORM, dibi, MySQL defaultní hodnoty (pokračování článku)
Brzy po vydání článku oznámil i Roman Sklenář existenci vlastního ORM, jehož uvolnění datuje na první týden ledna 2010. Zatím vypadá velice zajímavě, počkejme tedy co vyjde ven!
podobné články
| 15.12.2009 | DbDibiOrm - DibiConnection - staticky, instančně, přistupovat přímo k dibi factory? | (40%) |
| 07.12.2009 | ORM, dibi, MySQL defaultní hodnoty (pokračování článku) | (40%) |
komentáře
RSS Komentáře
- neřekl bych, že ORM od Honzy Marka je již vytvořené a ani nevím jeslti ho někdo používá, nicméně i na něj se v článcích odkazuje
- nemusí úplně každému vyhovovat, snad by i pomohlo někomu pochopit jak ten mechanismus funguje a proč
- ono je dost těžké do toho zapojit více lidí pokud se vystaví hotová knihovna,
- tady jde spíš o konkrétní problémy nebo vědět jak se s čím vypořádat, nicméně pokud nechcete objevovat ameriku, pak je tady už delší dobu Doctrine
- je to spíš o pohledu na věc a na konrétní časti skládačky, proč vymýšlet Nette, Kohanu, CakePHP a další když je tady Zend?
P.S.: Nejde mi ani tak o to jeslti výsledkem bude Ormion nebo něco jiného, ale jde mi o vyvolání diskuse, např. mě nevyhovuje, že update vždy vyvolá select do dtb. v mnoha případech je to dost nepoužitelné (s položením téhle otázky ale žádná diskuse nevznikne, a souvisí s tím nakládání s defaultními hodnotami, povinnými hodnotami atd.)
P.S.S: Co je neživotné? Možná víc pohledů na věc nikdy neuškodí, jako třeba na slovo neživotné? Můžeš prosím použít v jiné větě? Nějak pořád nevím co přesně to znamená
O to mi šlo, vyvolat diskuzi, proč vymýšlet znova kolo a nevylepšit/modifikovat již existující. U srovnání Nette a Zendu to kulhá, tam David vyvíjel kolo, zatímco frameworková komunita do té doby znala jen mnohoúhelníky ;-)
Ad PS: … které řeší jednotlivé problémy při tvorbě a vedlY mne k vytvoření ORM.
Stručně, jasně: Pokud tady napíšu pojďte se podívat na Ormion (pokud vím jediný publikovaný ORM/Data Gateway nad dibi) tak se nic dít nebude a nikdo se na ten kód ani nepodívá.
Prosím přihoď své nápady a to co se ti nelíbí. Zkusme kód po kouskách, to že nikdo nebude pročítat celou knihovnu je už vyzkoušené.
Slibuji, že pak vše sepíšu, udělám o tom článek a vše pošlu Honzovi, pokud se mu nápady líbit nebudou a nebude to chtít v Ormionu změnit, udělám vlastní implementaci.
Pokud se ti chce, budu vděčný, když mi vady na gramatice budeš posílat na email, slibuji, že je opravím 24 do hodin.
Koukám, že se ORM nad dibi se v poslední době nějak rozrhl pytel, tohle je už asi pátý, který vidím. Nicméně žádný pořád není dokonalý. Pokud máš instanci DibiConnection v každé instanci třídy DbRow, tak už při druhém je to zbytečné, natožpak nějaký result-set o tisíci řádcích. Další bolest skoro všech Orm je duplicita a zanášení definice struktury databázových tabulek někam, kam nepatří (viz. http://github.com/…erConfig.php). V komentářích jsou ještě nějaké zapomenuté anotace @return Ormion, tak bacha na to ;) Btw: jsi si opravdu jist, že metoda __toArray() je v objektovém modelu PHP implementována?
díky za názor, konečně něco konstruktivního,
- Ormion, rád bych ho podpořil, ale nevím o tom, že by Honza nějak komunikoval navenek, pokud vím tak pouze s Nette komunitou na Nette foru, což je podle mne škoda. Navíc neexistuje otevřená diskuse jestli se nemílím.
- Podle mne, ale napsat Ormion je dibiorm a pojďme se podívat na kód, tak nikdo právě nebude komunikovat a to je ten problém, protože většina programátorů dokáže zkousnout jen utržkovité informace na blogu a proto řeším jednotlivé problémy. Jeslti z toho bude doporučení a nebo vlastní implementace Ormionu už pro mne není důležité.
- Tomu, že se inspiruji v Ormionu se netajím, a psal jsem to. Dokonce původně jsem názvy některých proměnných přejmenoval tak, aby byly stejné jako v Ormionu. Zavedl jsem funkce, které jsem do té doby nepoužil, nicméně Ormion je naopak pokračování (pokud se nemýlím) Davidova DibiTableX.
- Existují ještě nějaké další pokusy? Sem s nimi, nevím o tom.
- DibiConnection je něco co jsem neřešil a popravdě ani k životu nijak řešit v každé instanci nepotřebuji, to je podle mne nejmenší bolest, nicméně ona se opravdu nevytváří znovu, ale stále existuje jen jedna, uložená v Db. Mě však opravdu vyhovuje i statické volání, ale někteří by s tebou nesouhlasili a chtějí mít v každé instanci dibiconnection.
- __toArray? je to metoda která se mi hodí, dobře vylepším to, když ji nazvu asArray()? v php se pri (array)$object opravdu nezavolá magická metoda a ani nikdy volat nebude! sory za zmatení nepřítele
- docela fajn by bylo, kdyby každý hodil nějakou tu špínu na různá ORM, z čehož se také dá vyjít, o to mi v podstatě jde.
K věci: A. instance dibiconnection, tvrdíš, že nic takového není potřeba a dblayer vrstva se má volat v každé funkci staticky a objektu nic není potom s jakou instancí dblayeru pracuje? B. result-set o tisící řádcích? tak teď asi nerozumím? můžeš rozvést? C. kam to tedy patří? Jak to myslíš že to sem nepatří? Na tom přece každé ORM v podstatě stojí? To je to co udržuje návrh konzistentní ne?
P.S.: co používáš ty? já ORM v podstatě nikdy nepotřeboval a přitom už před mnoha lety jsem si něco podobného vytvořil, původně mne štvalo neustále vytváření administrovatelných číselníků, takže časem jsem si vytvořil utilitu, která vygenerovala třídy a mysql apod. které měli na práci jen administrační prostředí a práci s daty jako (id, discount, amount), (id, phe, price) apod. později z toho vznikli třídy pro práci s rozsáhlejšími tabulkami a začali se nabalovat různé funkce, je to hrozný paskvil ale umělo to hodně a teď bych rád to předělal do něčeho systémového
- Naopak můžu říct, že Honza komunikuje i mimo fórum, například po IM či na Posledních sobotách, kde věci jako komponenty do Nette i ORM probírá a zajímají ho i názory druhých. Otevřená diskuse… no ono je to složitější, co člověk to jiný názor, nakonec se z toho vyklube flame kdy každý tvrdohlavě zastává svůj postoj a jen se kecá místo toho aby se programovalo. Díky tomu padl i jeden projekt Nette komunity okolo vytvoření CMS – 15 programátorů jen kecalo a řešily se až takové blbosti jak odsazovat switch a k programování se nakonec ani nedostalo :)
- S tím souhlasím, je to tak jak píšeš… navíc když už sepíše člověk nějakou úvahu, tak to lidi stejně nečtou (je i dokázáno, že lidi web jen prohlížejí :-)) a pokud ano tak se u první věci, ve které s autorem nesouhlasí zastaví, skočí na komentáře a jdou si zanadávat…
- Určitě se nedá popřít, že z DibiTable Ormion nevyšel. I já vycházel ve svých modelů právě z API DibiTable, lišila se jen implementace a i já mám v modelech onen šikovný magic fetch, který je v DibiTable
- Vím o pěti: tvé DbDibiOrm, Dorm od Honzy Vlčka (vlki), Ormion od Honzy Marka, nějaký zatím nejspíš neveřejný počin Romana Nováka (Jod) a můj
- Že se najde člověk, který by nesouhlasil, to je dá se říct jasné :-) vždy se někdo najde. Řek bych, že jsou v podstatě 3 základní a známé návrhové vzory a každý to pojímá jinak:
- Table Data Gateway (ekvivalent DibiTable): asi nejjednoduchší a díky dibi i v Nette aplikacích i hojně používané – vrácený objekt reprezentující záznam z tabulky obsahuje jen své hodnoty a je velmi jednoduchý a neimplementuje nad sebou žádné operace (viz DibiRow)
- Data Mapper: ten už vrací objekty, které mají nějaké schopnosti nad sebou samotnými, např třída reprezentující záznam z tabulky už může dejme tomu disponovat validací, nějaký uživatelský data pre/post-processing dat, definovat nějaké dodatečné gettery, settery apod. Neví ale nic o objektu mapperu, který provádí samotné dotazy na db a naopak mapper nic nepotřebuje vědět o objektu (maximálně jak si z něj vytáhnout data pro uložení)
Active Record vnímám jako takovou kombinaci obojího, kde je vše nacpáno do jedné třídy (ikdyž záleží na implementaci), objekt reprezentující záznam se umí uložit, zvalidovat, pomocí finderů naplnit a podobně.
Záleží na člověku co upředňostňuje. Mě se zamlouvá oddělení funkčnosti (záznam si neuchovává v sobě nic co nemusí, příkazy vykonává někdo jiný), které zavádí Data Mapper ale zároveň i komfort, který poskytuje Active Record (záznam se umí uložit a zvalidovat). Proto jsem se vydal cestou, kde se snažím tyto způsoby zkombinovat a zárověň oba vzory (v rámci možností) dodrřet a moc nezprznit. Na to aby to šlo ven je ještě brzo, ale ven to půjde ;) Musí nejdřív vykrystalizovat API a ověřit v reálném nasazení. Tento způsob se mi ověřil i při vývoji DataGridu a brzké vydání je myslím i důvod, proč byl pozastaven vývoj DibiTable (David to pustil ven moc brzo a po čase se mu znelíbilo API, ale už to lidi začali používat, takže by se to muselo řešit nekompatibilitama).
7. Mě se například nelíbí zavádění struktur tabulek do kódu, s tím související duplicita a nepříjemnosti při změnách, všemožné šílené definice v polích a podobně. Každé ORM to má navíc řešeno jinak a liší se i v zápise takže je to takové schizofrenické… V dibi je napsána abstrakce nad databázovou reflexí, která má vše co člověk může potřebovat, byla by škoda toho nevyužít a vymýšlet znovu něco co už je vymyšleno. Horší je to s implementací v jednotlivých driverech, ale nic co by se nedalo dopsat (otázka tak na hodinku až dvě i s testy), jsou to jen 4 základní metody. Databázi navíc mohou navrhovat jiní lidi než programátoři konkrétního jazyka, takže tím že si info o tabulce načtu z ní si akorát ušetřím starosti.
ad A: V podstatě ano, já sám instanci neukládám, ale zároveň mám možnost, jak v recordu získat mapper, pokud by to bylo třeba, i nechávám uživateli možnost změny mapperu.
ad B: Pod result set-em jsem myslel nějakou kolekci záznamů, které ti
vrátí metody find() / finder pokud podmínkám / filtrům vyhoví více
záznamů. V dibi::fetchAll například vrací pole
DibiRow objektů. Aby aplikace nevyhnila v případě velkého
objemu záznamů, tak je třeba aby záznamy byly opravdu pokud možno co
nejhloupější a takové věci jako datové typy sloupců, jejich výchozí
hodnoty, povinnost/nepovinnost a podobné neobsahovaly, ale uměly je nějak
lazy získat. Já tyhle věci například ukládám a načítám z/do keše,
když si o ně poprvé řeknu, mám to zastřešeno nějakými objekty
o určitém rozhraní, takže když se někomu nebude líbít, že získávám
info o tabulce pomocí databázové reflexe, nic nebude bránit podědit a
přepsat onu metodu a objektu podstrčit konfiguraci třeba z konfiguráku nebo
klidně i z toho pole. Takže jsou tam mám i jisté závislosti na částech
Nette, ale nic co se nedá ve finále vyseparovat. Uff myslím, že to bylo
vyčerpávající :-)
- ano, ale komunikuje jen v rámci nettistů, poslední sobota, forum nette, na internetu se přece pohybují i jiní lidé co o tom mají co říct a nette ani neznají ne? (pár sem jich viděl)
- cíl: v jednom příspěvku si řešil XY věcí a to vidím jako problém, kdo to čte? vyseparoval bych z toho jen jednotlivé věci a zaměřil se na ně, až dojdem k uspokojivému výsledku, nebo alespoň řadě názorů, vrhl bych se na další, ale možná tudy cesta taky nevede
- jak se zdá asi by se hodil článek o ORM, o data mapper a table gateway atd., už se mi jeden nabídl, že by ho napsal…tak snad se rozhoupe
- hm zbyde ti tedy holý objekt co nic neumí a nic o sobě neví … no tohle by asi chtělo více prostoru na takové téma
ad.B: vždyt přece config je statický! můžeš mít záznamů tisíc a tahle informace se přece duplikovat nebude,
co se týče té aktualizace a změny těch konfiguračních direktiv, ano máš pravdu, ale není i ke každému objektu načítání configu z cache také zbytečně zatěžující? třeba už jen jak získat tabulku objektu pro vytvoření nějakého sql? Já to třeba dělám takhle Customer::config()->getTable(), a to by znamenalo, že v téhle chvíli to naincluduje nějakou keš s direktivou mysql tabulky a z toho vrátí název table
no… návrh … co na každé takové téma udělat článek … pod tím rozběhnout diskusi … až bude více názorů … udělat závěr … zapsat do článku a jít dál … to byl původní záměr … ono asi nikdy nenajdeme průnik mezi názory všech … ale až někomu bude vadit takové a takové chování mohl by si najít proč tomu tak je a co přináší jiný přístup … případně si může vybrat jiné orm … nebo si ho upravit … to není přece o novém a novém vynalézání kola …
V tom případě ti tam asi chybí u deklarace proměnné
static a ten kód by neměl fungovat:
<?php
abstract class DbRow {
/** @var DbConnection (DibiConnection) */
private $db;
* Returns the DbConnection (DibiConnection).
* @return DibiConnection
*/
public static function db() {
if (!self::$db) {
self::$db = Db::getConnection();
}
return self::$db;
}
...
}
V mém případě je rozhodně načítání z keše rychlejší než generování struktury těch objektů při každém requestu :) jinak mám ale v cache vrstvu v Nette důvěru, protože ji používá i samotné jádro frameworku
OK, navrhuji, že udělám serii článků, každý bude řešit jednu otázku, v každém pak udělám nějaký závěr, např.
- Jak přistupovat k dblayer vrstvě? Vyhovuje Vám staticky, tzn. v každé funkci dibi::query nebo chcete mít možnost nastavit konkrétnímu objektu instanci dblayer vrstvy se kterou má pracovat? Asi ten dblayer omezme jen na dibi. – myslím, že by měla být možnost nastavit objektu různé vrstvy, mě se to hodí v případě, kdy třeba synchronizuji dvě databáze, každá vrstvá má svou connection, je to nepříjemné, že každému objektu musím nastavit se kterou vrstvou má pracovat, ale jak jinak? Navíc snad mohu předávat jen referenci, takže nedojde k duplikacím.
- Jak udržovat informace o databázovém objektu? Všechnu direktivu zapsat do externího objektu (config), ten generovat přímo z databáze nebo ručně ji vytvořit, dělá to tak např. Doctrine. Nebo kešovat nějaká data v externím souboru a objekt config si je nacte a zparsuje až bude potřebovat, výhoda je, že se snadno dá externí soubor aktualizovat a generovat z databáze pouhým smazáním cache.
co říkáš pokračovat tímto stylem a každou otázku řešit v článku, protože jinak to budeme řešit jen my dva a tato diskuse se hrozně nafoukne
ahoj
- lepší než __toArray nebo asArray by možna bylo implementovat IteratorAggredate: http://www.php.net/…ggregate.php
Možná bychom sem mohli přesunout diskuzi z http://www.webfaq.cz/…-Data-Mapper#… : Jako řešení bych viděl instanční implementaci (stejně by na omezené tabulky byla potřeba) + statickou obálku pro ty, kdo ji chtějí.



Možná by se v článku hodilo hodnocení, proč a v čem nevyhovují již vytvořená ORM, zvláště pak relativně nové http://github.com/…arek/dibiorm .
PS: Odkazy na články jsou neživotné ;)