Blog: Co se nevešlo na Twitter - Tag Doctrine

Kniha: Persistence in PHP with Doctrine ORM

book-doctrine-orm{.left-img.tiny-image}

Před pár měsíci mi www.packtpub.com napsali (jako jednomu z mnoha), jestli bych pro ně nechtěl napsat knihu o Doctrine 2 ORM. Byť o Doctrine něco málo vím, nepřipadal jsem si jako vhodný kandidát, tak jsem to odmítl.

Myslím, že jsem udělal dobře, protože ji nakonec napsal Kévin Dunglas, člověk který přispívá do opensource projektů a ekosystémů jako jsou Symfony, JavaScript a Ubuntu.

Pro koho je kniha

Především je opravdu krátká a dá se přečíst za pár hodin (neunudí). Je psaná v angličtině, takže té se rozhodně nevyhnete.

Ve zkratce se dá říct, že kniha Vás naučí Doctrinu od úplných základů a s minimem dalšího studia můžete v pohodě začít psát vlastní, až středně velké aplikace nad Doctrine.

Pro koho tato kniha není

Kniha je opravdu pro úplně začátečníky, pokud jste pokročilý uživatel Doctriny, tak Vám toho nejspíš kniha moc nedá. Já osobně jsem se nedozvěděl nic nového, což je pro mě trochu zklamání, ale dalo se to čekat :)

Stejně tak Vám toho kniha moc nedá pokud máte kompletně pročtenou dokumentaci Doctriny.

Co se naučím?

Kniha sama o sobě je subset dokumentace. Jenže zatím jsem nepotkal moc lidí, kteří by si poctivě pročetli dokumentaci Doctrine od začátku do konce. Nenavazuje to a bez zkoušení to člověka unudí. Spíše se hodí když si potřebujete dohledat, jak se něco konkrétního dělá.

Celá kniha je jeden dlouhý tutorial, který Vás provede od naprostých základů jako je instalace Composeru a základy jeho používání, což je například instance balíčku doctrine/orm, až po pokročilá témata jako jsou dědičnost entit nebo systém událostí.

Během čtení knihy doporučuji si vše zkoušet, je to lepší než pak hledat zpětně proč mi něco nefunguje a jako bonus si u toho napíšete jednoduchý blog :)

Shut up and take my money!

Knihu je možné koupit na webu www.packtpub.com. Co mě moc potěšilo, tak že si ji můžete stáhnout v PDF a ePUB a ani jedno neobsahuje žádné zjevné DRM. Taky je fajn, že ke knize si můžete stáhnout i všechny ukázky kódu (a funkční).

Pokračovat ve čtení ...

Aop v Nette Frameworku

Znáte termín Aspektově orientované programování Stejně jako u “Kdyby/Events”:/blog/eventy-a-nette-framework, pointou je rozbít systém na menší logické celky, ovšem každý přístup to dělá maličko jinak.

Hranice mezi Eventy a AOP je strašlivě tenká a rozhodnout se který přístup v konkrétním případě použít nemusí být vůbec lehké. A aby to náhodou nebylo moc jednoduché, tak Eventy jsou teoreticky nahraditelné AOPčkem, ale naopak to nejde.

AOP má simulovat skládání různých chování (behaviour) do jednoho objektu bez mnohonásobné dědičnosti z venku, aniž by o tom tento objekt věděl. Kdežto událostí je si sám vědom, protože to on je vyvolává, ale už neví o listenerech, které na ně naslouchají.

Pokračovat ve čtení ...

Eventy a Nette Framework

Vyčleňuji právě svoji integraci Doctrine do Nette Frameworku a jedna její část řeší údálosti.

Doctrine má na události jednoduchý systém - existuje třída EventManager, do které se registrují listenery a když se “něco stane”, vyvoláme nad ní událost a ta se předá příslušným listenerům. Pro detaily si můžete odskočit do podrobné dokumentace.

Nette Framework má také události. Používáte je nejspíše každý den ve formulářích, když nastavujete $form->onSuccess[] = $callback;.

A mě napadlo: co kdybych to sjednotil?

(Pro plné pochopení článku je nutné znát použití obou systémů, tak si to skočte přečíst, já tu počkám)

Pokračovat ve čtení ...

Doctrine a service vrstva aneb takto mi to dává smysl

Webexpo 2011 bylo velice inspirativní. S Patrikem jsme si v sobotu večer otevřeli notebooky a konečně jsme se odhodlali převést myšlenky v realitu. Měl jsem vcelku jasnou vizi, kterou mi Patrik pomohl dopilovat k dokonalosti.

Repozitáře nestačí

Repozitář je, podle definice, jenom taková chytřejší kolekce. Je potřeba entity i ukládat a mazat, nevidím důvod, proč by to nemohl dělat ten stejný objekt. Vznikl tedy Dao, nebo-li Data-Access-Object.

Dao implementuje několik samostatných rozhraní a rozšiřuje repozitář

class Dao extends Doctrine\ORM\EntityRepository
implements IDao, IQueryable, IObjectFactory

V Doctrine\ORM\EntityRepository je základní funkčnost jako findAll(), find(), … vždyť to znáte.

IDao definuje metody save() a delete(), které umí pojmout i pole nebo kolekce, pro snadnější manipulaci s entitami. Vychází z rozhraní IQueryExecutor, ale o tom až za chvíli

IQueryable definuje metody createQueryBuilder() a createQuery(). Ta první již je v repozitáři, ale ta druhá je jenom v EntityManageru. Potřebné jsou ale obě dvě.

A IObjectFactory definuje jednoduchou metodu createNew(), pro vytváření nových instancí entit.

Zatím vcelku jednoduché, že? Pár metod navíc pro repozitář, aby se s ním lépe pracovalo. Tuto třídu Dao nastavuji a vynucuji pomocí listeneru při načítání metadat. Takže všechny entity ji mají v základu místo obyčejného repozitáře.

Zde bych doporučil článek Honzy Tichého Pět vrstev modelu a související diskuzi.

Tolik metod musí stačit

Dao třída nám pěkně nabobtnala a umí toho tak akorát. Kdybych se měl držet myšlenek svého článku v Nette kuchařce ERM, tak bych nyní, pro specifické dotazy, třídu Dao dědil a přidával jí metody pro jednotlivé DQL. Metody jako findBarByBazAndOrderItByFoo() rychle přibývají a objekt těžkne, ztrácí řád a vůbec toho umí nějak moc.

Zde přichází na řadu Aleš Roubíček s článkem Doménové dotazy, který mi připomněl dávno zapomenuté články od Fowlera. V podstatě je to kuchařka na samostatné třídy pro DQL. Možná je to v jiném jazyce, ale je to snadno pochopitelné, takže tuto část do hloubky rozebírat nebudu a poprosím Vás odskočit si na jeho článek pro detaily a chybějící souvislosti.

Definoval jsem si tedy rozhraní IQueryObject a IQueryExecutor, kterému Query objekty předávám a získávám tak výsledek. Když teď chci zapsat dotaz, tak si podědím abstraktní QueryObjectBase, která už rozhraní IQueryObject implementuje a implementuji metodu doCreateQuery(), kterou vyžaduje abstraktní předek.

class RolePermissionsQuery extends QueryObjectBase
{
    /** @var Role */
    private $role;

    /**
     * @param Role $role
     */
    public function __construct(Role $role)
    {
        $this->role = $role;
    }

    /**
     * @param IQueryable $dao
     * @return Doctrine\ORM\QueryBuilder
     */
    protected function doCreateQuery(IQueryable $dao)
    {
        return $dao->createQueryBuilder('perm')->select('perm', 'priv', 'act', 'res')
            ->innerJoin('perm.privilege', 'priv')
            ->innerJoin('perm.role', 'role')
            ->innerJoin('priv.action', 'act')
            ->innerJoin('priv.resource', 'res')
            ->where('role = :role')->setParameter('role', $this->role);
    }
}

A získávám výsledek zjednodušeně takto

$role = $em->getRepository('Role')->find(1);
$result = $em->getRepository('Permission')
    ->fetch(new RolePermissionsQuery($role));

Nemusím tedy znečišťovat Dao dalšími metodami, protože všechno mám rozdělené na třídy.

A ještě bych upozornil, že Doctrine mám obaleno v samostatném DI Containeru (subcontainer), takže na EntityManager se snažím nesahat, volám si přes zkratku v něm jenom jednotlivé Dao.

Kam se poděly service?

Někdo možná špatně pochopil, že ty service, to jsou vlastně třídy, které mají metody save(), delete() a dáváme jim repozitář. Taky jsem to tak chvilku zkoušel, ale to mi prostě nedává smysl.

Dao a Query objekty perfektně obslouží persistenci a načítání entit a service už je všechno ostatní. Validační pravidla, počítaní, nějaké managery, … Zkrátka všechny třídy, které nezajímá, že někde je nějaká databáze a operují s logikou, kterou je naučíte.

Co jsem tím získal?

  • Zvrácenou radost, že skoro vůbec nepotřebuji EntityManager. Pouze na získávání metadat.
  • Nemusím rozšiřovat Dao, abych jim vnucoval metody na složité dotazy.

Pokračovat ve čtení ...