Doctrine hydrate array nebo object?
- Jiří Nápravník
- Člen | 710
Jakým způsobem získáváte data v Doctrine, resp. jakou hydraci, pokud mi jde o to data jen vypsat na stránce a nebudu s nimi dále pracovat, např. vykreslení článku.
Co jsem koukal, tak většina lidí doporučuje (a dokonce i v dokumentaci Doctrine to je), využít v tomhle případě Array hydration, kvůli lepší výkonnosti. Jaká je praxe u vás? Nepřijde se pak přeci jen o ten pěkný objektový přístup?
- Michal Vyšinský
- Člen | 608
- myslím, že ti to smažou
- většinou na výpis použiji hydrate array a abych nepřišel o objektový přístup, tak jej dám do ArrayHash – nijak jsem to ale neměřil tak nevím, zda to nakonec nevyjde nastejno
- mkoubik
- Člen | 728
Já si pro dané view vytvářím hlopý data transfer object který obaluje
entitu a vytahuje si z ní co potřebuje. Případné problémy s výkonem
řeším cacheováním buď toho DTO nebo přímo kusu HTML z něj
vygenerovaného v závislosti na id a názvu entity.
Je to sice trochu psaní navíc, ale pak máš jasně definovaná data co jsou
do šablony a je ti jedno jestli je vezmeš z entity, z pole, z cache nebo si
je vycucáš z prstu při prototypování.
Navíc, i když je to lákavé, doctrine entita jako objekt z persistenční
vrstvy rozhodně nemá co pohledávat v šabloně (jo, vím že to tak dělají
všichni a jsem ochotný se o tom kdykoliv pohádat u piva :-).
- Jiří Nápravník
- Člen | 710
- No v popisu kategorie je pímo napsáné Doctrine 2 a viděl jsem tu dost příspěvků, čistě na Doctrinu, tak uvidíme
- To s tím arrayhash mě nenapadlo, pěkné, díky
- Jiří Nápravník
- Člen | 710
@mkoubik: můžeš ukázat konkrétněji, co myslíš data transfer objectem? Jinak cachování HTML vygenerovaného je naprd ne? Protože o úroveň výše se musím dotazovat stejně databáze a vezme si to pod správu entitymanager. Nebo mi něco uniká?
- mkoubik
- Člen | 728
Něco jako:
/**
* @method getName
* @method getAddress
*/
class CustomerDTO extends \Nette\Object
{
private $name;
private $address;
public __construct(Customer $customer)
{
$this->name = $customer->getName();
$this->address = new AddressDTO($customer->getCurrentAddress());
}
}
Když pak kodér potřebuje třeba počet objednávek daného zákazníka tak
si tam dopíše public $ordersCount = 666;
a založí isuue aby tam
někdo ten údaj rozumným způsobem dostal, místo toho aby psal hrůzy typu
{= count($customer->orders)}
.
Edit: základní ukázka je tady (bez toho cacheování a nad NDB, ale pro představu to snad stačí).
Editoval mkoubik (21. 1. 2014 14:17)
- mkoubik
- Člen | 728
To cacheování funguje tak, že pokud se nespustí daná část šablony tak
se do db ani nikam jinam pro
ta data nesahá – používám na to LazyAccessor
a
LazyIterator
. Do cache se to ukládá s tagem typu
aggregate/customer/123
a při updatu dané entity se vyvolá
událost která to invaliduje.
- Jiří Nápravník
- Člen | 710
@mkoubik: díky za reakci. Je to pěkné, ale není tohle v podstatě duplikát entity a mám tak zbytečně zduplikovaná data v systému? Možná se to hodí u nějakých komplikovaných entit se spoustou vazeb, ale v případě nerozsáhlých entit, to bude ve výsledku skoro 1:1 entita ne?
To, že to count($this->collection), je celkem divočina v šablone, souhlas, nicméně nic mi nebrání dát getter na count přímo do entity samotné. Nicméně v obou případech musíme hydratovat jako object, což asi nebude tedy úplně výkonově ideální.
Edit: ještě reakce na cachování
můžeš mě nejak více nasměrovat? Pokud beru klasický přístup:
presenter získá z modelu něco a pošle to do view. Tak ve view, pokud chci cachovat, tak už mám stejně pozdě, jelikož už v presenteru se mi zavolal model a tedy i databáze etc. Samozřejmě řeší to cachování už výstupu z modelu, ale jak to cachovat přímo v šabloně?
Editoval Jiří Nápravník (21. 1. 2014 14:44)
- mkoubik
- Člen | 728
Jiří Nápravník napsal(a):
Možná se to hodí u nějakých komplikovaných entit se spoustou vazeb.
To je jedna z výhod. Představ si třeba zboží v eshopu. Taková entita může být poměrně dost složitá, ale ve výpisu kategorie tě zajímá v podstatě jen název, cena a nějaký obrázek, v detailu zboží tě toho zajímá trochu víc, při objednávce tě zajímají zase jiné atributy a vazby, v administraci chceš vidět počet objednávek za poslední měsíc, pak můžeš mít třeba skladový modul kde potřebuješ úplně jiná data atd. Tahat pokaždé celý agregát s milionem joinů by bylo neefektivní.
Fór je právě v té cache, díky ní si vytáhneš jednoduchý malý objekt přesně s těmi daty co potřebuješ.
V podstatě je to takové CQRS akorát místo read modelu v nějaké nosql db máš tu cache, která je v nette hodně mocná (a konec konců může být třeba v redisu).
Další výhoda je to jasně definované rozhraní mezi presenterem a šablonou – kodér kóduje a programátor programuje. Navíc může klidně kodér kódovat nad namockovanými daty, zatímco programátor teprve přemýšlí jakou db vrstvu použije.
Navíc představa že šablona může ovlivnit pokládané SQL dotazy
o 2 – 3 úrovně abstrakce pod sebou něčím jako
{$author->related('book.author_id') as $book}
nebo
{foreach $author->getBooks() as $book}
by mi asi
nedávala spát.
- Jiří Nápravník
- Člen | 710
ad. LazyAccessor aha, to je pěkné. je něco takového implementováno (přímo v nette, či jako rošíření) nebo to si mám udělat sám?
A když máš na mysli tedy vždy jiný pohled na entity, tak máš několik DTO? Nebo máš jedno DTO, v cachi uloženo ucelou entitu, včetně všech těch joinů a vytahuješ si na požádání z té cache co potřebuješ? Nebo ještě úplně jinak?
- mkoubik
- Člen | 728
To DTO je pro konkrétní šablonu, komponentu, skupinu podobných šablon apod. Prostě jsou to data co šablona potřebuje z „modelu“, může to být slepenec víc entit, výsledek nějakého výpočtu apod. Ta vazba DTO ↔ entita je dost volná. Klidně tam ani žádná doctrine nemusí být – můžeš to načítat ze souboru nebo přes síť.
Editoval mkoubik (21. 1. 2014 17:07)
- Jiří Nápravník
- Člen | 710
Aha, tak to už trochu mění situaci a odpadá to, jak jsem říkal, že to je dupliakce entity. Ta to tím pádem není. Pokud to tedy chápou dobře, tak jak jsi uvedl příklad Produkt v přehledu kaegorie, produkt v detailu a produkt v objednávace, tak to jsou tři DTO. Chápu srávně?
A ještě pokud vezmu klasický přístup presenter si vytáhne data z modelu a pošle do view. Tak ty DTO plníš kde. Předpokládám, že to je práce pro presenter…
- Filip Procházka
- Moderator | 4668
DTO jsem si nikdy nedokázal dost dobře ospravedlnit a ještě složitější je někomu vysvětlit výhody.
Btw, když už, tak bych se asi zbavil i nepotřebných getterů
- Jiří Nápravník
- Člen | 710
Filip Procházka: U Tebe by mě celkem zajímalo, jak řešíš předání dat do view vrstvy z Doctrine. Celou entitu jako objekt, nebo array kvůli výkonnosti. Mluvím o případu kdy bude z ní v tom daném requestu jen číst.
Editoval Jiří Nápravník (22. 1. 2014 0:49)
- Filip Procházka
- Moderator | 4668
Normálně předávám klidně entity do šablon, naši kodéři nejsou cvičené opice abychom to po nich museli opravovat :) Imho tenhle argument je sám o sobě většinou neplatný. Problém to může být jedině když hodně outsourcuješ a často narážíš na blbce.
Dává mi to ovšem smysl jako „kontrakt“ jaký data potřebuješ, protože můžeš mít různý DTO pro front, api, crony, … a nemusíš mít všechny operace v entitě
Pole většinou moc nepoužívám, buďto entity, nebo hydratuju list idček pro jinou query která vytahuje entity.
- Jiří Nápravník
- Člen | 710
Díky za reakci, mě nejde ani o ty kodéry tolik, protože já stejně dostanu čistou šablonu a dodělat tam to napojení apod stejně musím já:-) Jde mi spíše o tu výkonostní stránku, jelikož entita prý sežere hodně zdrojů kvůli tomu, že si jí bere pod správu EntityManager apod.
Ono to pole sice tohle řeší, ale zase mi vypadnou gettery entit, které řeší nějakou logiku…
- Filip Procházka
- Moderator | 4668
No hele, rozdil je jenom v čase (reflexe vs přejmenování pár klíčů do výsledného pole). Když mapuješ na entity tak je to i paměťově efektivnější, protože php od 5.4 lépe pracuje s objekty co mají definované properties (tedy například entity) než s poli, které jsou úplně dynamické.
A pokud budeš přemapovávat entity na DTO tak neušetříš vůbec nic, spíše naopak.
- Jiří Nápravník
- Člen | 710
Ok, tak já zkusím zatím čistě entity (resp. partial v některých případech) a optimalizaci budu řešit, až nastanou nějaké problémy.
DTO jsem prozatím vyloučil… Spíše jsem myslel, array z doctrine a hodit přes ArrayHash jak navrhoval někdo výše, ale to je asi výkonově podobné jako DTO…
- Filip Procházka
- Moderator | 4668
ArrayHash je jenom syntakticky cukr, bude to stejně pomalé a možná o drobeček pomalejší než raw pole.
- Jiří Nápravník
- Člen | 710
JJ, chápu, ale nechtěl jsem přijít o objektový přístup v šabloně, pokud bych hydratoval pole