Events In Practice
GlasgowPHP - May 2017
$(whoami)
Scott Pringle
PHP Developer @ People's Postcode Lottery
DDDEdinburgh Organiser
What Is An Event?
An event is an action recognized by software, that may be handled by the software
https://en.wikipedia.org/wiki/Event_(computing)#Description
An Event is the encapsulation of a recorded action within an application
Me, probably plagiarising someone...
<?php
namespace Demo;
class UserRegistered
{
private $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function user(): User
{
return $this->user;
}
}
Events have 0 or more listeners
<?php
namespace Demo;
class UserRegisteredListener
{
private $emailer;
public function __construct(Emailer $emailer)
{
$this->emailer = $emailer;
}
public function onUserRegistered(UserRegistered $event)
{
$this->emailer->send(
$event->user()->email(),
'Subject',
'Message'
);
}
}
Simple, right?
Thinking In Events
As Developers we...
- Think in Actions
- Something "will" happen
Context
- Video Subscription Platform (E.G. Netflix)
- Trials Are Available
- Payments are not taken instantly
- Payments get authorised & scheduled
User Registers
Add payment details
authorise payments
Add Subscription
Actions not events
thinking in events is hard!
Mindset change from "will" to "has"
Thinking in reactions, not actions
Event Driven Architecture
4 Principal Layers
- Event Generator
- Event Channel
- Event Processing
- Downstream Activity
Event Generator
- Senses A Change
- Frames The Change As An Event
Event Channel
- Middleware from Event Generator
to Event Processor - TCP/IP connection / Input file
- Stores events into queues for Processors
Event Processing
- Where the magic happens
- 0 or more reactions
- Could live outside application
Downstream Activity
- Consequence of Event Processing, e.g.
- Order confirmed emails being sent
- Stock count being updated
Events in Frameworks & Libraries
Symfony HTTP Kernel
- kernel.request
- kernel.controller
- kernel.view
- kernel.response
- kernel.terminate
- kernel.exception
Doctrine
- preRemove
- postRemote
- prePersist
- postPersist
- preUpdate
- postUpdate
- ...
All Of These Are Events Which Can Be Subscribed To / Published
I can't build an app using pre-defined events?!
Why not?
Custom Hooks Are Available
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
/Users/robo/dev/php/Doctrine/doctrine-mapping.xsd">
<entity name="User">
<lifecycle-callbacks>
<lifecycle-callback type="prePersist" method="doStuffOnPrePersist"/>
<lifecycle-callback type="postPersist" method="doStuffOnPostPersist"/>
</lifecycle-callbacks>
</entity>
</doctrine-mapping>
<?php
namespace Demo;
class User
{
// All the properties
public function doStuffOnPrePersist()
{
$this->persisted = true;
}
public function doStuffOnPostPersist()
{
$this->persisted = false;
}
}
I want more control
That I Can Agree With!
- More explicit the events, the better
- Control exactly where an event is triggered
- Which controller, console command etc
- Events mean more to the business
<?php
namespace Demo;
class UserRegisterController
{
private $eventDispatcher;
public function __construct(EventDispatcherInterface $eventDispatcher)
{
$this->eventDispatcher = $eventDispatcher;
}
public function __invoke(Request $request)
{
$user = new User(...);
$this->eventDispatcher->dispatch(
'event.user_registered',
new UserRegistered(
$user
)
);
return new JsonResponse();
}
}
<!-- app/config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="app.event.user_registered" class="Demo\EventListener\UserRegistered">
<tag name="kernel.event_listener" event="event.user_registered" method="onUserRegistered" />
</service>
</services>
</container>
I've probably got that wrong...
Events Can be Used as Messages
Events can be handled asynchronously
Events should be immutable
Tell other parts of your application to do something
Create an audit trail...
Tell other applications to do something
- Events Can Be Streamed
- Kafka
- RabbitMQ
- Any Other Queuing System
- File system
Event Sourcing
Events used to create state
No more relational tables
State becomes rebuildable
Predict state with Mocked events
Complete application history
You don't think of an audit log until you're audited
Treat events As first class citizens
Driven by Problem Domains
Map to things that really happen in your organisation
Business People don't care about technology
They only care about results
Questions?
Thank you
Twitter: @Luciam91
http://slack.scotlandphp.co.uk
Events In Practice
By Scott Pringle
Events In Practice
- 1,446