Komentáře k článku

ORM frameworky pro PHP5: Obecný úvod

ORM (Object Relational Mapping), tedy metoda mapování relační databáze na objekty, má podporu ve všech moderních programovacích jazycích. S příchodem PHP5 a ustálením koncepce objektového programování začal také vývoj ORM frameworků pro PHP. V tomto třídílném miniseriálu se seznámíme se dvěma zástupci návrhového vzoru Active Record a ukážeme si přínosy jejich nasazení v reálných situacích.

Zpět na článek

33 komentářů k článku ORM frameworky pro PHP5: Obecný úvod:

  1. Jiří Knesl

    Nesouhlasím s první větou

    „ORM (Object Relational Mapping), tedy metoda mapování relační databáze na objekty“

    Tak to přeci není. ORM není mapování relace → objekty, ale mapování objekty → relace. Může to znít jako triviální hloupost, ale v reálu je to propastný rozdíl. Už v tom, že mapovat relace na objekty je v objektovém programování naprosto k ničemu.

    1. Jiří Knesl

      Re: Nesouhlasím s první větou

      A když už jsem se tak rozjel. Active Record právě není ORM.

      V objektové analýze udělám class diagram (a nekoukám na relační schéma), v analýze databáze udělám relační schéma (a nekoukám na class diagram) a ORM je pak něco, co to navzájem spojí. Něčeho takového není Active Record nikdy schopen (jedině by to shodou náhod byly tyto modely skutečně 1:1, což se mi ještě nikdy nestalo).

      1. Mastodont

        Re: Nesouhlasím s první větou

        Nechci se hádat, protože definic je víc, ale Fowler výslovně uvádí AR jako jeden ze vzorů ORM …

        1. frantisek.troster

          Re: Nesouhlasím s první větou

          Dobrý den,

          děkuji za Váš názor. Souhlasím s Vámi, že ta věta je nepřesná a možná i zavádějící. Jak už to u vět, které zjednodušují něco komplexního, zákonitě bývá. To se ostatně ukazuje i na Vaší větě, kterou mi oponujete. ORM je něco nesměrového a měl jsem správně napsat, že se jedná o techniku propojení relačních databází a objektů. Pokud postupuji od ER modelu, ze kterého vygeneruji objekty (přístup zmiňovaných ORM frameworků), pak mapuji relační databázi na objekty. Pokud naopak vytvořím class diagram, na základě něho pak objekty a z těch vygeneruji databázi, pak mapuji objekty na relační databázi.

          Mapování relací (možná jste chybně zaregistroval, že nepíšu o relacích ale relačních databázích) na objekty pochopitelně smysl má a je to jedna z velkých výhod ORM. Relace se objektově zapisuje jako agregace. Tedy v ER zapíšu, že kontakt má n telefonních adres, 1:N relace. Objektově to pak zapíšu, že objekt kontakt obsahuje kolekci telefonních čísel.

          Active Record samozřejmě je jeden z možných přístupů k ORM. Active Record je velice obecný návrhový vzor a opět velice zjednodušeně (tudíž opět nepřesně) říká, že řádek tabulky se „stará“ sám o sebe (obsahuje metody pro uložení do DB apod.). Nikde se nepíše, že Active Record musí/nemusí být 1:1 s relační databází. Oba mnou uváděné frameworky generují třídy, které jsou přesným obrazem relační databáze a tudíž je obecně zaměnitelné zda hovoříme o class diagramu (pokud ignoruji provázanost s dalšími objekty aplikace) těchto tříd nebo o ER modelu.

          1. Jiří Knesl

            Re: Nesouhlasím s první větou

            Děkuji za odpověď.

            ORM je skutečně propojení. Jde ale o tu logiku, já mám nějaký class diagram (který ale při převedení 1:1 do relací třeba poruší 3.NF, nebo způsobí velké zpomalení db) a ORM mi má umožnit programovat objektově a nevnímat, že existuje nějaká databáze (a že v té databázi je to z důvodů výkonu, čistoty nebo jiných uspořádáno úplně jinak).

            „Pokud postupuji od ER modelu“ – to je právě to, co právě v prvních komentářích kritizuji (a od čeho třeba své studenty odrazuji, jak to jen jde). Objektová analýza a použití objektů se přeci nesmí přizpůsobovat tomu, že existuje ER diagram, že jsem použil relační, nebo stromovou nebo jinou databázi.

            AR lze vytvořit z libovolného řádku SQL resultu (a tento může být opravdu z více tabulek/views), pokud je možné potom tento řádek upravit a znovu uložit (ze „select concat(jmeno, prijmeni) from users“ tedy například AR vytvořit nelze). Doctrine i Propel jsou ukázkami knihoven (nejsou to frameworky, framework je například Zend, Nette, CakePHP, Struts nebo .NET), které šly daleko za možnosti Active Recordu (různé pluginy jako versionable, localisable, blameable…).

            „tudíž je obecně zaměnitelné zda hovoříme o class diagramu (pokud ignoruji provázanost s dalšími objekty aplikace) těchto tříd nebo o ER modelu“ – to je právě něco, za co by studenta každé slušné VŠ vyhodili od zkoušky. :)

            1. frantisek.troster

              Re: Nesouhlasím s první větou

              Je přeci jedno, zda začnu projekt Class Diagramem neb ER modelem. Pokud pracuji čistě s AR je jedno zaměnitelné s druhým a mění se pouze notace. Nikde není psáno, že vývoj musí začínat objektovou analýzou. Ve vývoji software existuje tolik možných přístupů a nikdo nemůže říct, že jeho přístup je jediný správný. Zastávám názor, že na modelování má být použit nástroj, který je pro mě v dané situaci nejrychlejší a nejpřehlednější. Nemusím to obhajovat u zkoušky, protože měřítko správnosti mého názoru je to, zda projekt dovedu do konce nebo ne. Proto se prosím nebavme o tom, co má být správně podle příruček. Příručky znám, školou jsem si prošel a považuji ji za velice dobrý základ do praxe.

              Nemyslím si, že správně navržený class diagram bude odporovat normálním formám, protože to jsou natolik obecná pravidla, která jsou dodržována automaticky „selským rozumem“.

              Kam byste začlenil ORM frameworky/knihovny (nechápu rozdíl) Propel a Doctrine? Vycházejí z návrhového vzoru Active Record a jak píšu v článku, dotahují ho do velice komplexního řešení. To jestli mají pluginy je irelevantní.

          2. jos

            Re: Nesouhlasím s první větou

            je to jen muj pocit, nebo používáte slovo relace ve smyslu „vztah mezi tabulkama“? z toho se mi dycky ježí chlupy.

          3. Jan Tichý

            Re: Nesouhlasím s první větou

            „Tedy v ER zapíšu, že kontakt má n telefonních adres, 1:N relace.“
            Asi by bylo dobré si nejdřív ujasnit terminologii, pod pojmem „relace“ se v relační algebře a potažmo pak i v relačních databázích rozhodně nemyslí vazby mezi tabulkami. „Relace“ je označení pro právě jednu tabulku.

        2. Jiří Knesl

          Re: Nesouhlasím s první větou

          A kde? Já v Patterns of enterprise application architecture od Martina Fowlera nikde zmínku o tom, že by AR byl ORM, nenašel. Spíš právě naopak, tvrdí, že AR je dobrý jen pro velmi jednoduché projekty, sám AR kritizuje, že AR vyžaduje shodný objektový a relační model a že u větších projektů AR ztěžuje možnost refaktoringu.

          Nerad bych vypadal, jako že mi AR nějak zvlášť vadí. U blogísku s 1 formulářem (nebo ultrajednoduché CMS) ho použiju taky. Tam mi zjevné porušení naprosto samozřejmé věci, tedy že class diagram a databázové schéma nemají NIC společného (a že mapovat je 1:1 je chyba) až tak nevadí.

          U takových projektů platí „worse is better“ a čistota je obětována produktivitě. Ale prostě nemá smysl tvrdit, že AR je ukázkou ORM. AR je ukázkou, jak psát rychle a produktivně. :)

          1. frantisek.troster

            Re: Nesouhlasím s první větou

            V knize Patterns of enterprise application architecture o Active Record hovoří a také tam uvádí, že má-li Active Record pattern fungovat správně, pak musí být 1:1 s Active Record objekty. Nezaregistroval jsem zmínku o tom, že by byl Active Record špatný, je naopak uvedeno několik případů, kdy je vhodnější než jiné přístupy. Nezaznamenal jsem možnost ztížení refaktoringu, refaktorizuju neustále a s Doctrine a unit testy velice bezpečně.

            Možná jste s Active Record nepřišel více do styku a vycházíte pouze ze zkušenosti s napsáním nějaké jednodušší aplikace. Článek vychází z mých praktických zkušeností, ne z nějakého načítání dokumentace. Mohl jsem napsat o tom, že Active Record pattern je mrtvý a nepoužitelný. Ale není to pravda, Doctrine i Propel jsou hlavní ORM frameworky pro PHP, které jsou používané od Cake PHP přes Symfony až po Zend.

            1. Jiří Knesl

              Re: Nesouhlasím s první větou

              Active Record jsem používal a používám už několik let (v Ruby on Rails ActiveRecord, CakePHP AppModel, Zend_Db_Table, generované třídy pro .NET, proprietární řešení) a právě fungoval dobře u malých projektů.

              Pro ty větší (více lidí, několik měsíců/let práce a intenzivního refaktoringu a údržby) se vždy vyplatilo použít místo AR DataMapper nebo alespoň řešení za hranicí AR (a třeba Doctrine i Propel jsou velmi daleko za ActiveRecordem, jsou tedy pro obhajobu AR nevhodné).

              Ad ty Patterns… – přečtěte si kapitolu „When to use it“, já mám za to, že Fowler tvrdí naprosto totéž, co já.

              1. frantisek.troster

                Re: Nesouhlasím s první větou

                Active Record implementace, které uvádíte, mají odlišný přístup od Doctrine a Propel. Nemám s nimi žádné větší praktické zkušenosti, proto se k nim nemůžu vyjadřovat. Viz. příspěvek výše, nevím na základě čeho odmítáte, že Doctrine i Propel jsou zástupci AR. Dotahují celý koncept do velice komplexní podoby a umožňují efektivní propojení MVC a ORM frameworku.

                Nemyslím si, že někde v článku píšu o Active Record jako o ideálním návrhovém vzoru. Pouze konstatuji, že Doctrine i Propel jsou zástupci tohoto návrhového vzoru a že většina PHP ORM frameworků z tohoto návrhového vzoru vychází. Až vyjde stabilní verze Doctrine 2 a bude tam použit perzistentní manažer, budu používat tuto knihovnu, protože vykazuje lepší parametry. Nemyslím si, že by ale byl AR v podání Doctrine 1 o moc horší, někdy se používá lépe, někdy hůře. Možnosti refaktorizace zůstávají stejné, přínos vidím v menší paměťové náročnosti mapovaných objektů.

  2. smilelover

    CRUD na objektu?

    Me hrozne nesedi to, ze jsou CRUD metody primo na danych domenovych tridach. Z objektoveho pohledu je to IMHO prasarna, protoze struktura domeny ma reprezentovat modelovanou realitu a zodpovednost domenovych objektu typu Book, Person ci cokoliv jineho v zadnem pripade nema byt operace nad perzistenci (viz. napr JPA)… Teoreticky by ty tridy nemely vubec vedet, ze jsou pouzivany s ORM (to je ovsem v realu dost tezke, i to JPA tam ma alespon ty anotace).

    Z tech dvou zminenych mam zkusenost s Propelem na relativne velkem projektu a v ramci moznosti jsem s nim celkem spokojen…

    1. frantisek.troster

      Re: CRUD na objektu?

      Doctrine 2 již nebude založena na návrhovém vzoru Active Record, ale naopak zavádí EntityManager, který zajišťuje persistenci objektů. ORM objekty budou tedy klasické objekty s anotacemi jako má např. Hibernate. Celé ORM se tím velice urychlí a především mnohonásobně zmenší paměťová náročnost, protože objekty zabírají méně paměti a garbage collector si s nimi snadno poradí (což u stávajících různě cyklicky provázaných objektů není možné).

      Propel jsem používal několik let, ale vadila mi větší paměťová náročnost než u Doctrine a nemožnost efektivně optimalizovat komplexní dotazy (vždy se musel udělat krok stranou a použít čisté SQL a zbavit se výhod ORM). Při dalším projektu bych se být Vámi podíval i na Doctrine (resp. Doctrine 2, která bude během několika měsíců stabilní), možná Vás osloví.

      1. smilelover

        Re: CRUD na objektu?

        V tom pripade zni Doctrine 2 dost zajimave. Ja ale doufam, ze pri dalsim projektu uz nebudu nucen pouzivat PHP vubec ;)

        Jinak co se tyka optimalizace SQL, tak to je fakt, ze tam jsem musel Propel dost priohybat. V podstate jsem si napsal vlastni mini-knihovnu pro cteni dotazu ulozenych v XML, ktera pak ty dotazy (a prip. dotazy na ne dale zavesene jako callbacky) spousti pres Propel a pres Propel je taky mapuje na objekty. Propel ale tu logiku mapovani schovava, takze jsem musel par jeho trid trochu „vyrabovat“… ;)

    2. Petr Novotny

      Re: CRUD na objektu?

      Mě osobně taky úplně nesedí CRUD na doménových třídách. Na druhou stranu, co se týče praxe tak je daleko pohodlnější volat např. $book->save(), než si sahat pro nějakou implementaci DataMapperu a předávat jí objekty na uložení. Tudíž mi připadá ideální mít v ORM možnost používat DataMapper zvlášť, ale zároveň mít volitelnou možnost poskytnout daným doménovým třídám API ActiveRecordu. Nevím ale jestli v současnosti nějaké ORM toto nabízí…

      1. František Kučera

        Re: CRUD na objektu?

        A to je takový problém použít EntityManager zavolat:

        em.persist(kniha);

        místo:

        kniha.save();

        ?

        V jednoduché aplikaci to vypadá jako ekvivalentní, ale pokud je aplikace distribuovaná nebo vícevrstvá, může (a zpravidla tomu tak je) objekt putovat do částí systému, které s databází nemají nic společného – a pak je nežádoucí, aby si s sebou objekt nesl tyhle metody a vazbu na databázi.

  3. ToM

    Re: ORM frameworky pro PHP5: Obecný úvod

    Ja si teda vzdycky myslel, ze ORM je mapovani objektu domenove modelu do relacni databaze. Tzn. veta

    „Možnost zapouzdřit související funkce přímo do objektu reprezentujícího řádek tabulky“

    je blbost. Ty objekty, co se mapuji, by prece nemely vedet o tom jak se ukladaji. To pak vznika zavislost, ktera neni uplne zadouci.

    1. frantisek.troster

      Re: ORM frameworky pro PHP5: Obecný úvod

      Ano, ale to jsou rozdílné přístupy mezi ActiveRecord návrhovým vzorem a nebo Repository návrhovým vzorem. U prvního přístupu je žádoucí a nezbytné, aby objekt věděl vše o své perzistenci v databázi. U druhého přístupu je situace opačná a přesně jak říkaté je zcela žádoucí, aby doménový model byl mapován pro něj neznámím správcem perzistence.

      1. ToM

        Re: ORM frameworky pro PHP5: Obecný úvod

        Souhlasim s tim, ze jsou to jine pristupy. Ale sypat ActiveRecord do stejne pytle jako vzor Repository, no nevim. Proste ActiveRecord je zrcadlo databaze v objektovem havu a s ORM nema nic spolecneho. Na urovni ActiveRecord je DataMapper, ten ovsem funguje opacne a mapuje domenovy model na relacni. A to je zaklad ORM.

  4. none_

    Lazy loading?

    Chtěl jsem se zeptat, jestli tyto frameworky podporují lazy loading jako například hibernate v Java? Předpokládám, že ano, protože jestli ne, tak se stávají nepoužitelné…

    Jednoduchý příklad: tabulky v DB Adresa – Autor – Clanek
    Chci k článku vypsat adresu autora: $Clanek->autor->adresa

    1. frantisek.troster

      Re: Lazy loading?

      Ano, jak Doctrine tak i Propel ve výchozím nastavení použijí lazy loading. Nebo je možné vynutit načtení souvisejících záznamů, pomocí SQL joinu v jednom dotazu. Ve druhém článku (vyjde příští středu) je podrobněji rozepsán framework Doctrine a to i včetně možných variant načítání záznamu tabulky do proměnných.

  5. Srigi

    Nette + Doctrine

    Nedavno som zacal pisat projekt v Nette a nad modelovou vrstvou (M z MVP) som dlho rozmyslal. Kcel som pouzit Zend_DB ale toto bolo moc low-level, clovek si musi doprogramovat Data Mapper a to sa mi ako spravnemu lenivcovi nekcelo. Tak som sa prekonal a zvolil som Doctrine a musim konstatovat, ze lepsiu volbu som urobit nemohol.

    Inak je zvlastne ako sa komunita okolo Nette drzi Db layeru Dibi.

    1. Matej

      Re: Nette + Doctrine

      > Inak je zvlastne ako sa komunita okolo Nette drzi Db layeru Dibi.

      Dibi znam a libi se mi jeho jednoduchost a rychlost zapisu sql. To je zkratka navykove… i kdyz hur prenositelne. Ale, priznejme si, kdo dela v Dibi velke projekty, ze ano ;-)

    2. Ped

      Re: Nette + Doctrine

      Taky zkousim Nette+Doctrine 1 a zatim jsem docela spokojeny.

      Doctrine 2 se mi moc nelibi, podle mne je to z pohledu OOP a abstrakce krok zpatky, i kdyz samozrejme pokud nekomu chybi ten vykon navic a nebo naopak mu vadi ze domenovy model toho vi o ulozeni v DB vse, tak je Doctrine2 asi dobra volba.

      Ja osobne se snazim o TDD a po serii experimentu jsem dospel k zaveru ze:
      – nechci pracovat primo s DB, chci mit moznost kdykoli zmenit DB lusknutim prstu. Z toho mi vyslo ze chci definovat objekty jako PHP class a nechat kod at vygeneruje DB strukturu + stara se o komunikaci s DB (Doctrine1 zatim splnuje na jednicku, prepnuti unit testu ze sqlite:memory na MySQL je otazkou prepsani jedneho radku s definici pripojeni, to same teoreticky i pro jine DB, ale to jsem zatim netestoval)
      – nechci v ramci unit testu „mockovat“ skoro vsechny tridy, proto bych chtel poustet testy nad opravdovou DB, ale klasicke „skutecne“ DB vykonove naprosto nevyhovuji. Sqlite:memory mne trochu zklamala, ale je to jeste pouzitelne (V prumeru 10 testu zvladne za 0.3s proti 5s nad MySQL).
      – porad hledam rozumny kompromis jak testovat samotny vystup webove aplikace, vypada to ve spojeni s Nette docela slibne, v podstate mi staci korektne vyvolat dany presenter a otestovat na vystupu co pripravil sablone, pripadne klicove data dohledat v samotnem html vystupu (ale tohle mi prijde uz relativne nezajimave, jsem spokojenej jiz kdyz vim ze sablona dostava spravne data, mozna u opravdu komplexnich stranek kde muze dojit k nejake zamene udaju v ramci sablony nebo nejake copy/paste chybe budu testovat i vystup)

      Kdyby sem nechtel odstrelit definovani struktury DB, tak bych zustal u dibi.

      Premyslim ze nekdy napisu nejaky „how to“ co se tyce kombinace TDD + Nette + Doctrine 1, jen se jeste na to necitim pripraven, chci ziskat trochu vic praxe s testovanim presenteru a celkove aplikace, ted jsem velmi spokojeny jenom s testovanim modelu. A jeste jsem nezkousel migrace mezi ruznymi verzemi modelu, kdyz uz budou v DB nejake zive data, Doctrine by to melo pomoct resit, ale musim si to jeste vyzkouset.
      Pokud by takovy clanek nekoho zajimal, dejte mi to tady vedet, at vim ze to ma smysl. :)

      1. Tom

        Re: Nette + Doctrine

        ad „Pokud by takovy clanek nekoho zajimal, dejte mi to tady vedet, at vim ze to ma smysl. :)“

        +1 v počtu zájemců o takový článek :)

      2. frosty22

        Re: Nette + Doctrine

        „chci mit moznost kdykoli zmenit DB lusknutim prstu“

        Docela nechápu, proč se mezi stěžejní výhody ORM stále řadí možnost změn databází. Samozřejmě výhoda to je, ale převážně pouze u univerzálních systémů. Beru to tedy prakticky, ale u menších webových aplikací, tak stejně budete hosting hledat tak, aby splňoval požadavky aplikace, u větších aplikací, tak si necháte udělat server na míru a nebudete používat chvíli MySQL, chvíli MSSQL, apod.

        Osobně jsem se v praxi setkal již z mnoha projekty, od malých po veliké, čili toto samozřejmě je hezká vlastnost na jednu stranu, na druhou stranu člověk pak nemůže využít ony DB plně, pokud to nepodporujou všechny drivery apod.

        Nebo ve finále může chtít udělat kompilér, který by zvládat konverze PHP, Java, C++ :)

        Není to výtka, jen podotýkám, že se na tuto vlastnost všude apeluje, ale praktické využití je minimální.

  6. backup

    neni to vsechno nejak moc komplikovane ?

    kdyz to ctu, tk mam pocit, ze bych musel nejdriv vystudovat 2 vysoke skoly, nez bych napsal nejakou trivialni spravu adres. Uz jenom , abych vedel jestli je spravne mapovat to na ono nebo ono na to.

    1. frantisek.troster

      Re: neni to vsechno nejak moc komplikovane ?

      Dobrý den,

      není to tak hrozné. Triviální správu adres napíšete bez znalosti vnitřních struktur. V okamžiku kdy budete potřebovat optimalizovat, což znamená, že se již nebude jednat o triviální správu adres, načtete další kus dokumentace týkající se této oblasti.

      Jinak řečeno, dokud děláte na triviální aplikaci, nepotřebujete ORM, nepřinese Vám nic navíc. Když se ale aplikace rozroste, budete řešit, jestli psát nějaké vlastní řešení (zpočátku primitivní a postupně nabalované o stále více a více kódu) nebo použijete nějaké hotové a otestované. A pak ten čas, který byste strávil vývojem a testováním vlastního frameworku, věnujete načítání dokumentace. A podle mé zkušenosti to načtení dokumentace zabere desetinu a méně času než vývoj vlastního řešení.

  7. analytik

    Kam zmizela ta diskuze o Propelu?

    Jeste pocas dne jsem tady videl vlakno „Propel vs Doctrine“ s par zajimavyma zkusenostema.

    Rad bych dodal k clanku, ze aktualni verze Propelu, 1.5, ma query jazyk ne nepodobny Doctrine. Dulezite je ale zminit, ze Doctrine pouziva runtime introspection a je delany podle Hybernate, kdezto Propel si bere za vzor Apache Torque a modely kompiluje (generuje prazdne classy jednotlivych modelu + jejich base, Peer, Critera a Query classy) s pomoci Phing.

    Benchmarky z blogu Propelu i Doctrine ukazuji, ze Propel je temer vzdy rychlejsi, teda aspon v porovnani se soucasnou stable Doctrine (1.x). Doctrine 2.0 alpha vsak ukazuje velke zlepseni vykonu.

    V cem ma Doctrine 2.0 taky navrch je pro me podpora namespace, ktere v Propelu jsou zatim v nedohlednu (neobjevi se teda v nejblizsi verzi, 1.6).

    Ale, vzhledem k benchmarkum a zkusenostem pritomnych uzivatelu bych se rad zeptal autora clanku co myslel vetou „Hlavní nevýhoda Propelu je v zastaralém jádru knihovny“ – je to skoro jedine, co o Propelu pise, na zaklade ceho usoudil, ze Propel je vhodny jenom na legacy projekty, coz se mi zda trochu mimo realitu.

    1. analytik

      Re: Kam zmizela ta diskuze o Propelu?

      Ups, omlouvam se, thread ‚Propel vs Doctrine‘ je na tretim dilu.

      Citat o ‚zastaralem‘ jadru propelu je z druheho dilu.

Napsat komentář

Tato diskuse je již příliš stará, pravděpodobně již vám nikdo neodpoví. Pokud se chcete na něco zeptat, použijte diskusní server Devel.cz

Zdroj: https://www.zdrojak.cz/?p=3160