[size="3"]Tutorial on ObservableActions?[/size]
In the course of building a RESTful API for a client, I’ve made extensive use of events to make actions reusable and flexible. Since event-handling in actions isn’t widely discussed, I thought I’d make a tutorial covering:
-
Creating a base action class with an init() method and some predefined events (e.g. onAfterConstruct(), onAfterInit())
-
Show how to create custom action events and attach handlers in your controller
-
Build an example GetRecordAction
-
Use event handlers to deal with 403/404/410 situations without cluttering the action code itself
I’m wondering if the community would benefit from a tutorial on this, if this is already a well-known pattern, or if there’s simply a better way to do this.
[size="3"]Principles - Actions should be DRY/SRP[/size]
DRY = Don’t Repeat Yourself
SRP = Single Responsibility Principle
We want classes that are powerful, loosely-coupled, and re-usable. Yii makes it easy to do this, but the documentation/existing tutorials don’t make it obvious how to do this with respect to Actions.
[size="3"]Example Code[/size]
Below is an example of how the GetRecordAction class would be configured in your controller. Note that I’m using anonymous functions in the example. This is just for transparency; in real life you might want to create classes that encapsulate those checks, if only to make them easily re-usable elsewhere in your application.
// In a "BooksController" class...
public function actions()
{
return array(
// Retrieve a book from the database
'getRecord' =>array(
'class' =>'api.components.actions.GetRecordAction',
'modelClass' =>'Book',
'scenario' =>'api.get',
'onBeforeLoad' =>function($event)
{
$accessGranted = Yii::app()->authManager->checkAccess(
'Books.get.record',
Yii::app()->user->id,
array('bookId' =>$event->params['recordPk'])
);
if (!$accessGranted)
throw new CHttpException(403, "EW GETTTOUT");
},
'onAfterLoad' =>function($event)
{
if ($event->params['record']===null)
{
throw new CHttpException(404, "The requested book was not found");
} else if ($event->params['record']->status==3)
{
throw new CHttpException(410, "That book was deleted and is no longer available");
}
},
),
);
}