Korektní využívání MVC a Managerů

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Ripper
Člen | 56
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

@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
+
0
-

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
+
0
-

@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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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:)

akadlec
Člen | 1326
+
0
-

Můžu trochu hloupý dotaz? Když si udělám nějaký UserListener a ten bude mít metody onRegister, onPswChange atd. jak potom tyto eventy odpálím? Zkoušel sem to navěsi na onSuccess metodu formu ale metoda se nezavolala.

Jiří Nápravník
Člen | 710
+
0
-

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é

akadlec
Člen | 1326
+
0
-

Takže kdybych to aplikoval na příspěvek filipa tak v objektu: App\UserManager zavolám $this->onRegister() ? a kdyby.subscriber se o to postará?

mkoubik
Člen | 728
+
0
-

Ano (předpokládám že máš App\UserManager zaregistrovaný jako službu).

akadlec
Člen | 1326
+
0
-

No já to bral jen teoreticky, a jako službu jsem to uvažoval ;)