Rozuzlení ORM v Nelle
V předešlém článku jsem sepsal své strasti při hledání vhodného ORM pro Nellu . Popsal jsem v něm hrubé požadavky, které by měl kandidát splňovat. Popsal jsem, proč jsem nezvolil Ormion, dibi-ActiveRecord, Propel, Doctrine 1.2 a ani Doctrine 2.0.
Nedávno se na scéně objevila nová vlaštovka od Jakuba Vrány . „ORM“ „NeORM“ jménem NotORM je super a inspirující nicméně také není dokonalé. NotORM spoléha na načtení struktury databáze z databáze. Což je pro Nellu nevyhovující z důvodu že Nellu plánuji vydat s podporou více databází. A bude obsahovat instalačního průvodce, který databázi vygeneruje. No a generovat databázi z prázdné databáze jaksi nejde. Navíc NotORM se mě zdá zase až příliš jednoduché.
Finální volba
Najít vhodné ORM, které by nebylo ani velké ani malé. Nebylo by ošklivé, snadno se používalo a zároveň bylo postavené nad dibi. Je nemožné. Proto jsem zvolil snad nejhorší možnou variantu „udělej si sám“. Naplněn informacemi z průzkumu již hotových řešení. Jsem začal přemýšlet a zkoumat jak to teda vlastně udělat aby to nebylo přeplácané a zároveň aby to umělo vše co potřebuji. No a tak vzniká ActiveMapper. Další a určitě né poslední ORM postavené nad dibi .
Ukázkový příklad
Mějme asi takovouto strukturu databáze:
Pokud vám při prvním pohledu nejsou
jasené relace tak jsou následující: Authors 1:1 Profiles , Authors 1:N
Articles , Articles N:M Tags
Struktura dat
<?php
namespace App\Models;
/**
* @OneToMany(App\Models\Article)
* @OneToOne(App\Models\Profile)
*/
class Author extends \ActiveMapper\Entity
{
/**
* @column(Int)
* @autoincrement
* @primary
*/
protected $id;
/**
* @column(String, 100)
* @unique
*/
protected $name;
}
/**
* @OneToOne(App\Models\Author, mapped = FALSE)
*/
class Profile extends \ActiveMapper\Entity
{
/**
* @column(String, 255)
*/
private $web;
}
/**
* @ManyToOne(App\Models\Author)
* @ManyToMany(App\Models\Tag)
*/
class Article extends \ActiveMapper\Entity
{
/**
* @column(Int)
* @autoincrement
* @primary
*/
private $id;
/**
* @column(String, 255)
*/
private $title;
/**
* @column(Text)
*/
private $content;
/**
* @column(Date)
* @default NOW()
*/
private $create;
/**
* @column(Float)
* @null
*/
private $price;
/**
* @column(Bool)
* @default false
*/
private $public;
}
/**
* @ManyToMany(App\Models\Article, mapped = FALSE)
*/
class Tag extends \ActiveMapper\Entity
{
/**
* @column(Int)
* @autoincrement
* @primary
*/
private $id;
/**
* @column(String, 255)
*/
private $name;
}
Jak je z ukázky patrné mapuje se pomocí „Entit“, které hojně využívají anotací. Pokud se ptáte co je dalšího potřeba? Tak říkám že nic! Můžete to začít používat.
PHP 5.3
Další věc která je z ukázky patrná je že se používají namespace tudíž je nutné PHP 5.3. Máte-li vůči PHP 5.3 averzi a nehodláte to překousnou dále snad ani nečtěte. A nebo se podívejte že nutnost PHP 5.3 je čím dál více potřeba. Stačí se podívat na budoucí Doctrine 2.0, Zend Framework 2.0, Symfony 2.0 a spoustu dalších knihoven a frameworků. Zkrátka čím dříve začleníte PHP 5.3 do svého života tím lépe pro vás. PS: Zatím každý koho znám a zkusil PHP 5.3 u něj taky zůstal!
Získávání dat
Jak definovat strukturu dat jsme si už ukázaly. Ale jak data získat? Jednoduše takto:
$article = \ActiveMapper\Repository::find('App\Models\Article', 1); //načti článek s ID 2
echo $article->title; //vypíše titulek článku
echo $article->author()->name; //vypíše jméno autora
foreach ($article->tags() as $tag)
{
echo $tag->name; //vypíše název štítku
}
echo $article->author()->profile()->web; //vypíše web autora
To musím pokaždé psát
ActiveMapper\Repository::find('App\Models\Article',...)? Ne!
Stačí při definování struktury dat dědit od
ActiveMapper\ServiceEntity místo ActiveMapper\Entity
a můžete používat App\Models\Article::find(2).
Pět vrstev ActiveMapperu
Pokud jste četli Pět vrstev modelu od
Honzy Tichého . Ptáte se asi jestli
něco takového ActiveMapper má. Ano má a aktuálně to je
asi takto: 
Pokud se ptáte kde je UnitOfWork a podobné části zabývající se zápisem tak ty si ukážeme příště, až budu ActiveMapper uvolňovat pro širokou veřejnost.

7 komentářů
enoice
nový
Tož, líbí se mi, že někdo zpracovává Honzovu ideu :) těším se na pokračování.
Václav Novotný
nový
K tomu vygenerování databáze v instalátoru: Proč databázi nevygeneruješ z SQL skriptu, který strukturu drží? I pokud používáš ORM, tak je dobré mít strukturu v SQL skriptu.
Jinak… Hele, ty sis napsal svojí vlastní Doctrine 2 :) Jak koukám na ty zdrojáky s annotacemi, tak vidím, že to je víceméně to samé. Má tvůj přístup něco lepšího, co Doctrine 2 nemá? S tím, že Doctrine 2 není jen mapování samozřejmě, takže je samozřejmě větší.
Honza Marek
nový
Jsem zvědav, co bude umět ten tvůj repository. Jestli to bude jen hloupé skladiště manipulačních funkcí nebo něco víc.
Václav Novotný
nový
Napsal jsem něco málo o architektuře Doctrine 2, aby to čtenář případně mohl porovnat, pokud se k Doctrine 2 ještě nedostal.
http://vaclavnovotny.eu/…a-doctrine-2
Jakub Vrána
nový
Z čeho usuzuješ, že NotORM spoléhá na načtení struktury z databáze? Nic takového potřeba není, do databáze se prostě pošle to, co napíšeš do kódu.
Patrik Votoček (Vrtak-CZ)
nový
Abych pravdu řek tak ani nevím. Takže chápu to dobře že NotORM nemá o struktuře DB ani ponětí?
Jakub Vrána
nový
Jediné, co NotORM zajímá, jsou primární a cizí klíče. Ty si dokáže načíst ze struktury databáze nebo používá libovolnou konvenci. Ostatní sloupce ho nezajímají – co přijde z databáze, to pošle do programu, co přijde z programu, to pošle do databáze.