Architektura Doctrine 2
Pozor, článek je notně zastaralý a prozatím jsem nenašel čas ho zrevidovat. Berte prosím zde prezentované informace s rezervou. Pokud byste se rádi dozvěděli více informací o Doctrine 2, přečtěte si seriál Doctrine 2 od Jana Tichého.
Rád bych ukázal základní stavební kameny PHP ORM nástroje Doctrine 2 a srovnal je s 5-ti vrstevným modelem, který představil Honza Tichý. Nebudu se zde věnovat databázové vrstvě (DBAL), kterou Doctrine používá a budu se snažit zaměřit více na vrstvy, které jsou blíže modelu. Stejně tak se nebudu snažit představit práci s Doctrine 2, která by vydala na několik samostatných článků. Použiji pouze to nejnutnější, pokud to bude potřeba.
Základní stavební kameny
V ORM Doctrine 2 nalezneme tyto základní členy:
- Entity
- Entity manager
- Identit map
- Unit of Work
- Repository
- Persister
Entity – entita doménového objektu
Entita v Doctrine 2 představuje libovolný doménový objekt. V případě klasického CMS to tedy může být například entita Article. Doctrine 2 nám absolutně nic nediktuje, což je její největší výhoda. Abychom naší třídu Article připravili na spolupráci s Doctrine, oanotujeme ji za pomocí konstrukce”@Entity”. Vypadá to takto:
/**
* @Entity
*/
class Article
{
/** ... */
private $id;
/** ... */
private $title;
/** ... */
private $text;
// Setters and getters
...
}
Entita má několik atributů, které odpovídají určitým sloupcům v určité tabulce. Z pohledu architektury je to ale nezajímavá věc, takže si to dovolím přeskočit. Zajímavější je možná to, že entita spolupracující s Doctrine 2 se může v aplikaci nacházet v různých stavech.
- nová (new)
- řízená (managed)
- neřízená (detached)
- odstraněná (removed)
Nová entita
Nová entita je taková entita, kterou jsme vytvořili a neřekli entity manageru, aby ji uložil. Pokud novou entitu nepředáme entity manageru pro uložení, změny v entitě provedené se nám neuchovají.
Řízená entita
Řízená entita je entita, která byla předána entity manager pro uložení do repozitáře, nebo již uložená entita, která byla z repozitáře načtena. Změny v této entitě se nám uloží.
Neřízená entita
Neřízená entita je taková entita, která je uložena v repozitáři, ale my jsme ji od něho odpojili. Změny, které v entitě provedeme, se nám neuloží a v příštím načtení dostaneme entitu ve stejném stavu, jak jsme ji dostali při aktuálním načtení.
Odstraněná entita
Odstraněná entita je entita, která byla řízená, ale my jsme se jí rozhodli odstranit z repositáře. Entita se vymaže.
Entity manager
Entity manager je ústřední část ORM. Je pouze jeden a obhospodařuje práci se všemi entitami přes jejich repozitáře. Samotný Entity manager se v Doctrine 2 skládá ze dvou částí.
Unit of Work
Tato část entity manageru má na starosti řízení SQL dotazů. Zajišťuje, že se příkazy nevykonávají hned, ale co nejpozději, což zajišťuje větší efektivitu v práci s databází. Jedná se o typickou implementaci vzoru Unit of Work.
Identity map
Implementace vzoru Identity map. Tato část zajišťuje to, že máme v entity manageru vždy pouze jednu instanci entity, což má hned několik výhod. Například to, že ne zbytečně neptáme vícekrát na jedno a to samé, nebo že si omylem nepřepisujeme data v případě, že bychom omylem vytvořili více instancí jedné entity. V reálu to tedy vypadá následovně:
$article = new Article();
$article->title = 'Foo';
$article->text = 'Big white bra.'
$em->persist($article); // Entity manager instance
...
...
...
$theSameArticle1 = $em->find('Article', $article->id);
$theSameArticle2 = $em->find('Article', $article->id);
Entity $theSameArticle1 a $theSameArticle2 jsou úplně to samé jako entita $article. Zde je dokonce pravděpodobné (v závislosti na tom, co ve ve vynechaném kódu), že vůbec neproběhla žádná komunikace s databází. Na začátku jsme sice $article uložili, ale jak jsme psal výše, Unit of Work nechává komunikaci s databází na co nejpozději, takže pokud mu to nikdo ještě neřekl pomocí metody flush, drží si data pouze v sobě a do databáze je odešle někde dál.
Repository – zdroj entit
Možná jste si všimli, že jsem několikrát psal o tom, že se entity načítají z repozitáře, ale já jsem entitu hledal v entity manageru. Pravdou je, že volání
$em->find('Article', $article->id);
je pouhou zkratkou k repozitáři, který si entity manager načítá. Opravdové volání by vypadalo nějak takto
$em->getRepository('Article')->find($article->id);
A co je to ten repozitář? Repozitář je zdroj entit. Můžeme si ho buď napsat sami, nebo můžeme využít výchozí repozitář, který nám Doctrine 2 nabízí. Ten se jmenuje EntityRepository. Pro většinu entit nám tento výchozí repozitář bude pravděpodobně stačit, ale občas je dobré napsat si vlastní repozitář pro nějakou entitu. V tomto nám Doctrine 2 nechává otevřená vrátka.
Persister – mapovač entit
Persister je o úvroveň nižší vrstva než repozitář, která slouží k namapování (přes anotace, XML, nabo YAML) dat na atributy entity. Persistory jsou jádrem ORM a ve většině případů se s nimi nesetkáme. Je ale dobré vědět, jaká část ORM přebírá mapovací konfiguraci a pracuje s ní.
Zhodnocení architektury Doctrine 2 s ohledem na HoTův 5-ti vrstesný model
Možná znáte článek Honzy Tichého, ve kterém píše o 5-ti vrstevném modelu. S dovolením si vypůjčím jeho obrázek. Model je rozvrstvený takto:
Model podle Doctrine 2 je rozvrstvený takto:

Ze schémat můžeme vidět, že se modely nijak výrazně neliší, právě naopak. Pět vrstev modelu nám zůstalo zachováno a navíc jsme dostali vylepšenou komunikaci s databází (přes Unit of Work a Identity map), která částečně vynahradí fakt, že ORM SQL dotazy generuje, což se často negativně podepisuje na výkonu.
Externí odkazy
Tags: doctrine 2, model, orm
Posted in Uncategorized | Comments Off
