logo

Tutorials: Creating Event Listeners

Same as JavaScript, STDOUT MVC API and Console MVC API allow developers to bind logic to application lifecycle events (addEventListener) in request-response handling process. Syntax:

$object->addEventListener(EVENT_TYPE, CLASS_NAME);

Following EVENT_TYPE are available for STDOUT MVC API, corresponding to a prototype respective listener must extend, triggered on a lifecycle event:

Event Type Class Prototype Triggered
::START Before stdout.xml is read
::APPLICATION After stdout.xml is read, before request is read
::REQUEST After request is read, before controller runs
::RESPONSE After view resolver runs, before response is outputted
::END After response is outputted

Similar EVENT_TYPE are available for Console MVC API, corresponding to a prototype respective listener must extend, triggered on a lifecycle event:

Event Type Class Prototype Triggered
::START Before stdout.xml is read
::APPLICATION After stdout.xml is read, before request is read
::REQUEST After request is read, before controller runs
::RESPONSE After view resolver runs, before response is outputted
::END After response is outputted

Framework comes with its own bindings, necessary to integrate APIs it's composed of, but developers will more often than not need to add their own, as long as rules are followed:

Please keep in mind event listeners will be executed in the order they are set!

START: On Application Start

Abstract class / listens to events that execute BEFORE stdout.xml is read.

Example

A common example is the need to set start time, in order to benchmark duration of handling later on:

namespace Lucinda\Project\EventListeners; class StartListener extends Lucinda\STDOUT\EventListeners\Start { public function run() { $this->attributes->setStartTime(microtime(true)); } }

Save class above in src/EventListeners then add this line to index.php right after is instanced:

$object->addEventListener(Lucinda\STDOUT\EventType::START, Lucinda\STDOUT\EventListeners\StartListener::class);

Since method setStartTime does't exist in in , you need to modify it and add these lines:

private $startTime; public function setStartTime(float $startTime): void { $this->startTime = $startTime; } public function getStartTime(): float { return $this->startTime; }

APPLICATION: After XML Is Processed

Abstract class / listens to events that execute AFTER stdout.xml is read.

Example

A common example is to integrate new features via stdout.xml (eg: a Rest API to call later):

<rest_api host="api.example.com" authkey="asdfgh"/>

Which needs following listener:

namespace Lucinda\Project\EventListeners; use Lucinda\Project\Models\RestAPI; class RestAPIListener extends Lucinda\STDOUT\EventListeners\Application { public function run() { $tag = $this->application->getTag("rest_api"); $restAPI = new RestAPI((string) $tag->host, (string) $tag->authKey); $this->attributes->setRestAPI($restAPI); } }

Save class above in src/EventListeners then add this line to index.php in the right place after is instanced:

$object->addEventListener(Lucinda\STDOUT\EventType::APPLICATION, Lucinda\STDOUT\EventListeners\RestAPIListener::class);

Since method setRestAPI does't exist in , you need to modify it and add these lines:

private $restAPI; public function setRestAPI(Lucinda\Project\Models\RestAPI $restAPI): void { $this->restAPI = $restAPI; } public function getRestAPI(): Lucinda\Project\Models\RestAPI { return $this->restAPI; }

REQUEST: After Request Is Processed

Abstract class / listens to events that execute AFTER http request / console request is processed.

Example

A common example is user country detection:

namespace Lucinda\Project\EventListeners; use Lucinda\Project\Models\CountryDetector; class CountryDetectionListener extends Lucinda\STDOUT\EventListeners\Request { public function run() { $countryDetector = new CountryDetector($this->request->getClient()->getIP(), $this->request->headers()); $this->attributes->setCountry($countryDetector->getCountry()); } }

Save class above in src/EventListeners then add this line to index.php in the right place after is instanced:

$object->addEventListener(Lucinda\STDOUT\EventType::REQUEST, Lucinda\STDOUT\EventListeners\CountryDetectionListener::class);

Since method setCountry does't exist in in , you need to modify it and add these lines:

private $country; public function setCountry(Lucinda\Project\Models\Country $restAPI): void { $this->country = $country; } public function getCountry(): Lucinda\Project\Models\Country { return $this->country; }

RESPONSE: Before Response Is Shown

Abstract class / listens to events that execute AFTER body was set but BEFORE it's rendered back to caller.

Example

A common example comes from a need of crypting response on top of SSL:

namespace Lucinda\Project\EventListeners; use Lucinda\Project\Models\Encryptor; class EncryptionListener extends Lucinda\STDOUT\EventListeners\Response { public function run() { $encryptor = new Encryptor(); $this->response->setBody($encryptor->encrypt($this->response->getBody())); } }

This way, whoever knows the URL of a web service will see garbled response unless he has a key to decrypt it. So save class above in src/EventListeners then add this line to index.php in the somewhere right before $object->run();:

$object->addEventListener(Lucinda\STDOUT\EventType::RESPONSE, Lucinda\STDOUT\EventListeners\EncryptionListener::class);

END: On Application End

Abstract class / listens to events that execute AFTER was rendered back to caller.

Example

A common example is the need to set end time, in order to benchmark duration of handling:

namespace Lucinda\Project\EventListeners; class EndListener extends Lucinda\STDOUT\EventListeners\End { public function run() { $duration = microtime(true)-$this->attributes->getStartTime(); $this->attributes->getLogger()->info("Duration: ".$duration); } }

Save class above in src/EventListeners then add this line to index.php right before $object->run();:

$object->addEventListener(Lucinda\STDOUT\EventType::END, Lucinda\STDOUT\EventListeners\EndListener::class);
×