Tutorials: Creating Event Listeners

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

Type Prototype Class Lifecycle Event
START before stdout.xml is read
APPLICATION after stdout.xml is parsed into object
REQUEST after user request is read into , and objects
RESPONSE after body is compiled but before it's rendered
END after was rendered back to caller

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 configuration XML is read. A common example is the need to set start time, in order to benchmark duration of handling later on:

class StartListener extends { public function run() { $this->attributes->setStartTime(microtime(true)); } }

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

$object->addEventListener(::START, "StartListener");

Since method setStartTime does't exist in Attributes class @ application/models folder, you need to modify it and add setters and getters:

class Attributes extends { 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 configuration XML is read. 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:

require("application/models/RestAPI.php"); class RestAPIListener extends { 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 application/listeners then add this line to index.php in the right place after is instanced:

$object->addEventListener(::APPLICATION, "RestAPIListener");

Since method setRestAPI does't exist in Attributes class @ application/models folder, you need to modify it and add setters and getters:

class Attributes extends { private $restAPI; ... public function setRestAPI(RestAPI $restAPI): void { $this->restAPI = $restAPI; } public function getRestAPI(): RestAPI { return $this->restAPI; } }

REQUEST: After Request Is Processed

Abstract class listens to events that execute AFTER , and objects are created. A common example is user country detection:

require("application/models/CountryDetector.php"); class CountryDetectionListener extends { public function run() { $countryDetector = new CountryDetector($this->request->getClient()->getIP(), $this->request->headers()); $this->attributes->setCountry($countryDetector->getCountry()); } }

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

$object->addEventListener(::REQUEST, "CountryDetectionListener");

Since method setCountry does't exist in Attributes class @ application/models folder, you need to modify it and add setters and getters:

class Attributes extends { private $country; ... public function setCountry(Country $restAPI): void { $this->country = $country; } public function getCountry(): Country { return $this->country; } }

RESPONSE: Before Response Is Shown

Abstract class listens to events that execute AFTER body was set but before it's committed back to caller. A common example comes from a need of crypting response on top of SSL:

require("application/models/Encryptor.php"); class EncryptionListener extends { 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 application/listeners then add this line to index.php in the somewhere right before $object->run();:

$object->addEventListener(::RESPONSE, "EncryptionListener");

END: On Application End

Abstract class listens to events that execute AFTER was rendered back to caller. A common example is the need to set end time, in order to benchmark duration of handling:

class EndListener extends { public function run() { $duration = microtime(true)-$this->attributes->getStartTime(); $this->attributes->getLogger()->info("Duration: ".$duration); } }

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

$object->addEventListener(::END, "EndListener");
×