Kdyby/Events @ProchazkaFilip
Co si povíme? ● ● ● ●
teorie kolem eventů jak to funguje v Nette Kdyby/Events prakticky diskuze? připravte si otázky!
Teorie kolem eventů
Co jsou eventy/hooky? ● modulárnost ● rozšiřitelnost ● znovupoužitelnost
Eventy v Nette? class Circle extends Nette\Object { public $onChange = []; public function setRadius($radius) { $this->radius = max(0, $radius); $this->onChange($this, $this->radius); }
Eventy v Nette? $circle = new Circle; $circle->onChange[] = function($circle, $newValue) { echo 'there was a change!'; }; $circle->setRadius(10);
Nette magic class Nette\Object { public function __call($name, $args) { foreach ($this->{"on$name"} as $cb) { call_user_func_array($cb, $args); } }
Naco další event systém? ● není to lazy ● kompatibilita s otatními systémy ○ doctrine\orm ○ symfony\event-dispatcher
Lazy eventy? $circle->onChange[] = function($arg) use ($foo) { $foo->hardWork($arg); }; $circle->onChange[] = function($arg) use ($bar) { $bar->hardWork($arg); };
Doctrine ORM? class Listener implements EventSubscriber { function getSubscribedEvents() { return ['onFoo', 'onBar']; } function onFoo($args) { // ... }
Doctrine ORM? $evm = new EventManager(); $evm->addEventSubscriber( new Listener() );
Doctrine ORM? $evm->dispatch( 'onFoo', new Args($foo, $radius) );
Symfony? class Listener implements EventSubscriberInterface { function getSubscribedEvents() { return ['onFoo', 'onBar']; } function onFoo($args) { // ... }
Symfony? $evd = new EventDispatcher(); $evd->addSubscriber( new Listener() );
Symfony? $evm->dispatch( 'onFoo', new Event($foo, $radius) );
Co takhle, Kdyby se všechny systémy daly používat dohromady?
xkcd.com/927
Kdyby/Events = Nette events (+ Doctrine EventManager)? (+ Symfony EventDispatcher)?
Pojďme vyřešit problém z praxe class OrderProcess { function openOrder(); function addItem($item); function finish(Order $order);
Přidáme posílání emailů... public function __construct( EntityManager $em, Nette\Security\User $user, Nette\Http\Session $session ){
Požadavek: “Po dokončení objednávky se bude posílat email”
Přidáme posílání emailů... public function __construct( EntityManager $em, Nette\Security\User $user, Nette\Http\Session $session, Nette\Mail\IMailer $mailer ){
Požadavek: “Přidej mi tam kredity za objednávky”
Přidáme kredity.. public function __construct( EntityManager $em, Nette\Security\User $user, Nette\Http\Session $session, Nette\Mail\IMailer $mailer, My\CreditsRewarder $rewarder ){
Požadavek: “Jeden partner chce objednávky posílat do svého pokladního systému”
Externí pokladní systém.. public function __construct( EntityManager $em, Nette\Security\User $user, Nette\Http\Session $session, Nette\Mail\IMailer $mailer, My\CreditsRewarder $rewarder, Partner\CashRegisterClient $partner ){
Požadavek: “Budeme posílat smsky”
Posílání smsek... public function __construct( EntityManager $em, Nette\Security\User $user, Nette\Http\Session $session, Nette\Mail\IMailer $mailer, My\CreditsRewarder $rewarder, Partner\CashRegisterClient $partner, My\Sms\Sender $smsSender ){
Požadavek: “V příštích 6 hodinách vracej 50% hodnoty objednávky v kreditech, za všechny objednané burgery”
SRP
(Single Responsibility Principle)
Vraťme se na začátek... public function __construct( EntityManager $em, Nette\Security\User $user, Nette\Http\Session $session ){
… a přidejme si jeden event class OrderProcess public $onFinish = []; function finish(Order $order) { // ... $this->onFinish($this, $order); }
… a napíšeme si listenery class OrderMailerListener implements Subscriber { function getSubscribedEvents() { return [ 'OrderProcess::onFinish' ]; }
… a napíšeme si listenery class OrderMailerListener function __construct(IMailer $mailer); function onFinish(Order $order) { // .. $this->mailer->send($message); }
… a napíšeme si listenery class CreditsRewardListener function __construct( Rewarder $r, User $user); function onFinish(Order $order) { $this->rewarder->reward( $this->user->id, $order->price * 0.05); }
… a napíšeme si listenery class SmsSenderListener function __construct(Sms\Sender $sender); function onFinish(Order $order) { // .. $this->sender->send($message); }
Nezapomenout registrovat events: subscribers: - OrderMailerListener - CreditsRewardListener - SmsSenderListener
Profit!
Poslední nejasnosti ● Jak se $onFinish dostane k listenerům? ● Nemělo to být lazy? ● Můžu naslouchat na více událostí v jednom listeneru? - Jistě!
A co nějaké nevýhody? ● Nevíme vůbec co se zavolá ● IDE s tím neumí pracovat
PhpStorm ❤ Kdyby/Events & @juznacz FTW!
Dejte @juznacz follow je to borec
A co ty message queue?
Závěrem? Eventy nejsou silver bullet, užívejte s rozumem.
Dotazy?
Díky za pozornost! filip-prochazka.com Follow me maybe? @ProchazkaFilip