Korektní využívání MVC a Managerů
- Ripper
- Člen | 56
Dobrý den,
rozšiřuji si obzory v tvorbě aplikací a narazil jsem na pár věcí, které mi nejsou jasné a které bych si rád nechal vysvětlit od někoho zkušeného.
Dejme tomu že vytvářím aplikaci na správu úkolů, použiji Doctrine2 a Kdyby\Events pro různé akce. Budu mít nějakou základní tabulku s daty uživatelů, tedy nějakou UserEntity a s tou UserEntity budu chtít pracovat v různých třídách, třeba v authenticatoru nebo i v presenterech.
Teoreticky bych si tedy mohl prostě předat nebo injectnout DAO, tam kam potřebuji. Ale není tedy teoreticky lepší, udělat si nějaký Manager? V tomto případě tedy UserManager, který si budu předávat tam kam budu potřebovat a bude obsahovat všechny metody, které já budu chtít? Pokud bych použil události v UserManageru, například při změně jména, nebude to špatně?
Možná to jsou pro někoho zbytečné otázky, ale rád mám ve věcech pořádek, takže díky za odpovědi.
- David Matějka
- Moderator | 6445
Ano, muzes si vytvorit nejaky manager/facade/service nebo jak to nazves. Tam si injectnes DAO, pripadne EM. Ale dej si pozor, at ti nevznikne ohromna trida, ktera umi vse
precti si treba http://filip-prochazka.com/…o-dava-smysl
- Ripper
- Člen | 56
Super, díky!
Edit: Pokud by mi začal takový manager kynout, jak se tomu vyhnout? Roztřídit to do více managerů? Například pokud budu mít v UserManager nějakou fci, která mi bude zpracovávaž žádost o nové heslo, tak bude vhodné vytvořit EmailManager?
Editoval Ripper (11. 3. 2014 6:11)
- Ripper
- Člen | 56
Napadla mě ještě jedna věc se kterou si nejsem jistý –
mějme tedy případ kdy registruji uživatele – v presenteru zavolám UserManager a jeho funkci register() a v register funkci budu volat MailManager ze kterého pošlu email a budu informovat o registraci. Je to takhle správně nebo mám volat MailManager v presenteru, pod UserManagerem?
- Tomáš Kolinger
- Člen | 136
Z praktickýho důvodu bych logiku registrace přesunul do presenteru.
Model pro uživatele by měl metodu UserManager->create($username, $password, …). Odesílání na maily např. RegistrationMailManager->send(User $user). A to bych následně volal v render metodě.
Důvod je jednoduchý. Budeš chtít například vygenerovat odkaz do e-mailu (na aktivaci účtu). A k tomu potřebuješ $presenter->link(). Takže by sis musel předat presenter do modelu a to je prostě divný.
- Jiří Nápravník
- Člen | 710
Ripper: Posílání mailu je součástí business logiky, proto má být v modelu, v presenteru dle mě nemá co dělat. Vezmi si jednoduchý příklad, přijde požadavek, na to udělat mobilní verzi webu (jiné presentery), mobilní aplikaci (volání přes api) a budeš muset vždy volat dva managery najednou a zapomeneš na to a duplikujes kod. Proto je lepší mít UserManager->register – který zavolá mailmanager apod.
Pokud potrebuješ odkazy, tak je lepší použít jako service UrlGenerator
- David Matějka
- Moderator | 6445
zvaz taky pouziti kdyby/events
V UserManageru jen pak zavolas $this->onRegister($user)
a
subscriber na tenhle event to zachytne a treba odesle ten mail
- Ripper
- Člen | 56
@Jiří Nápravník: Jasně, díky!
@matej21: Kdyby\Events používám, tedy plánuji to. Jenom jeden dotaz – pokud by subscriber zachytí událost onRegister, mám odesílat email přímo z něj, nebo si opět vytvořit nějaký EmailManager a v něm funkci na odeslání aktivačního e-mailu?
Omlouvám se za hloupé otázky, ale už dlouhou dobu v tom nemám jasno a chci v tom mít tedy pořádek.
- Jiří Nápravník
- Člen | 710
matej21: Můžeš mi prosím nějak laicky vysvětlit, kdy a hlavně proč je kdyby/events výhodné. Dost na něj často narážím, nejvíce je zmiňovaný právě při posílání mailů. Ale osobně tam vidím problém v tom, že když použiju tu klasickou metodu, tak vidím jasně co se děje. Ale pokud použiju Eventy, tak mi přijde, že nevím hned, co se bude dít, protože můžou být navěšeny na ten event všude možně a při spolupráci s více programátory patlali to může být divočina. Uniká mi něco zásadního nebo jsem něco nepochopil?
Článek na Filipově blogu jsem četl, i některý věci ktomu tady na fóru.
- David Matějka
- Moderator | 6445
@Ripper: idealni by to imho bylo RegistrationEmailSender
,
ktery by mel metodu ->send(User $user)
a trida neco jako
RegistrationEmailSenderInvoker
, ktery by naslouchal na event a
zavolal by na RegistrationEmailSender
tu metodu send :) Ja bych asi
sel cestou, ze by RegistrationEmailSender
rovnou naslouchal
na event.
@Jiří Nápravník: Ano, mas pravdu – muzes zkusit doplnek do phpstormu, ktery ti ty subscribery zobrazi
- Ripper
- Člen | 56
Ještě mě tím procházením kódu napadla jedna věc, pokud tedy budu chtít používat userManager, mělo by to být jediné místo kde bude k dispozici user DAO, ale nechce se mi psát všechny ty metody na vybírání dat, ukládání, atd. Jak tohle řešít? Hodit DAO do public proměnné a pak k ní přistupovat ($userManager->dao->find())?
- Filip Procházka
- Moderator | 4668
Ripper napsal(a):
@matej21: Kdyby\Events používám, tedy plánuji to. Jenom jeden dotaz – pokud by subscriber zachytí událost onRegister, mám odesílat email přímo z něj, nebo si opět vytvořit nějaký EmailManager a v něm funkci na odeslání aktivačního e-mailu?
Já bych si udělal classu UserMessenger
, která by měla metodu
třeba confirmRegistration($user)
, nebo
notifyRegistration($user)
a posílala by email/řadila ho do
nějaké fronty na odeslání.
A listener
class RegistrationEmailListener extends Nette\Object implements Kdyby\Events\Subscriber
{
private $messenger;
public function __construct(UserMessenger $messenger) {
$this->messenger = $messenger;
}
public function getSubscribedEvents() {
return ['App\UserManager::onReqister'];
}
public function onReqister($manager, User $user) {
$this->messenger->notifyRegistration($user);
}
}
Jiří Nápravník napsal(a):
matej21: Můžeš mi prosím nějak laicky vysvětlit, kdy a hlavně proč je kdyby/events výhodné.
Eventy (obecně tedy subscriber/listener pattern) mají pomoct propojit modulární aplikaci.
Například když se ti vytvoří objednávka, zavoláš v metodě
userConfirmedOrder($order)
event
$this->onConfirm($this, $order);
Na to ti naslouchá listener a ten listener zavolá nějakou metodu na třídě co pracuje se skladem a ta vytvoří požadavky na nakoupení zboží. Třeba.
Nebo chceš
- přičítat kredity za objednávku? Listener
- máš časově omezenou soutěž která běží od do a počítá nějaké
soutěžní body? přidáš další listener který bude před zavoláním
metody
$competition->addPoints($user, $order)
zkontroluje že datum vytvoření objednávky spadá do času kdy beží soutěž - chceš po dokončení objednávky přepočítat kde uživatel objednává a přidat mu restauraci do „oblíbených“? listener
Tady těch užití jsou mraky. A ano, máš pravdu, s eventy nevíš co se volá, protože nevíš co je na to navázané. Ale to je přesně ta pointa proč by to někdo dělal :) Je totiž velký rozdíl když mám věci co je potřeba udělat po odeslání objednávky v 10ti třidách kde každá se stará jenom o své a když všechno volám v jedné. SRP :)
Eventy se dají také použít i jako poor man's message queue :)
PS: víte že @Juznacz napsal pro Kdyby/Events rozšíření do PhpStormu?
- Jiří Nápravník
- Člen | 710
Filip Procházka a jo, u modulární aplikace se to dá dobře využít. To v podstatě řeší to, že se mi nělíbí, když mám dva moduly celkem hodně svázané.
A jak to je potom v praxi. Používá se třeba jedna třída, která má v sobě těch listenerů více. Konkrétní příklad, modul pro správu uživatelů. Posílám například maily – potvrzovací, zapomenuté heslo, že byl uživatel aktivován. Děláš v praxi tři listenery, nebo jeden a v tom všechny tyhle maily. Já bych měl třeba nějakou UserMessenger, tam naházel tohle posílání, třídu UserMessengerListener, který by obsahoval samotné události a volal. Jdu na to dobře nebo špatně?
- Filip Procházka
- Moderator | 4668
Pokud se to logicky hodí k sobě, udělám jeden listener, který naslouchá na více událostí, pokud ne udělám jich více.
Na ty 3 věci bych nejspíše udělal listener jeden, hodně to záleží i od konkrétní aplikace, neumím se rozhodnou když neznám všechny souvislosti :)
- Jiří Nápravník
- Člen | 710
Jasné, mě jde spíše o to, jestli to není vyloženě špatný postup. Díky za upřesnění, asi začnu využívat další část z Kdyby:)
- Jiří Nápravník
- Člen | 710
voláš to jako eventy nette, tedy
$this->onRegister(); apod. Ten subscriber se na to sam prichytne. Koukni do
debug baru, zda jsou tam vůbec dobe spárované