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 | Lucinda\STDOUT\EventListeners\Start | before stdout.xml is read |
APPLICATION | Lucinda\STDOUT\EventListeners\Application | after stdout.xml is parsed into Lucinda\STDOUT\Application object |
REQUEST | Lucinda\STDOUT\EventListeners\Request | after user request is read into Lucinda\STDOUT\Request, Lucinda\STDOUT\Session and Lucinda\STDOUT\Cookies objects |
RESPONSE | Lucinda\STDOUT\EventListeners\Response | after Lucinda\STDOUT\Response body is compiled but before it's rendered |
END | Lucinda\STDOUT\EventListeners\End | after Lucinda\STDOUT\Response 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!
Abstract class Lucinda\STDOUT\EventListeners\Start 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 Lucinda\STDOUT\EventListeners\Start
{
public function run()
{
$this->attributes->setStartTime(microtime(true));
}
}
Save class above in application/listeners then add this line to index.php right after Lucinda\STDOUT\FrontController is instanced:
$object->addEventListener(Lucinda\STDOUT\EventType::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 \Lucinda\STDOUT\Attributes
{
private $startTime;
...
public function setStartTime(float $startTime): void
{
$this->startTime = $startTime;
}
public function getStartTime(): float
{
return $this->startTime;
}
}
Abstract class Lucinda\STDOUT\EventListeners\Application 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 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 application/listeners then add this line to index.php in the right place after Lucinda\STDOUT\FrontController is instanced:
$object->addEventListener(Lucinda\STDOUT\EventType::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 \Lucinda\STDOUT\Attributes
{
private $restAPI;
...
public function setRestAPI(RestAPI $restAPI): void
{
$this->restAPI = $restAPI;
}
public function getRestAPI(): RestAPI
{
return $this->restAPI;
}
}
Abstract class Lucinda\STDOUT\EventListeners\Request listens to events that execute AFTER Lucinda\STDOUT\Request, Lucinda\STDOUT\Session and Lucinda\STDOUT\Cookies objects are created. A common example is user country detection:
require("application/models/CountryDetector.php");
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 application/listeners then add this line to index.php in the right place after Lucinda\STDOUT\FrontController is instanced:
$object->addEventListener(Lucinda\STDOUT\EventType::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 \Lucinda\STDOUT\Attributes
{
private $country;
...
public function setCountry(Country $restAPI): void
{
$this->country = $country;
}
public function getCountry(): Country
{
return $this->country;
}
}
Abstract class Lucinda\STDOUT\EventListeners\Response listens to events that execute AFTER Lucinda\STDOUT\Response 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 Lucinda\STDOUT\EventListeners\Application
{
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(Lucinda\STDOUT\EventType::RESPONSE, "EncryptionListener");
Abstract class Lucinda\STDOUT\EventListeners\End listens to events that execute AFTER Lucinda\STDOUT\Response 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 Lucinda\STDOUT\EventListeners\Start
{
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(Lucinda\STDOUT\EventType::END, "EndListener");