This is the second in a series of Cgiapp2 Tutorials.
In this tutorial, I cover creating what I call 'Pluggable Applications',
applications that can be distributed and customized to work with other
sites.
Background
In several positions I've held over the years, I've needed to use the same
application with very slight modifications on multiple sites. These include
article applications, galleries, contact forms, and more. The underlying
code typically remains the same -- but I may need to plug the content into a
different sitewide template, or require authentication.
When following MVC
well, many of these tasks are already easy. You can create a new instance of
the controller at will, and slip in new templates to customize the look and
feel. However, things like a sitewide template fall out of the scope of the
application templates; they are designed for a suite of
applications. Authentication is also typically very site dependent; sure,
your application may require a logged in user, but should you really dictate
what credentials are used? shouldn't that be left up to the site owner?
A good Controller can provide this kind of flexibility. With Cgiapp2's
callback hook system, you actually don't need to develop the application to
do some of these tasks; instead, you can leave it up to the end-user
developer to implement. This provides strong portability and incredible
flexibility in your applications.
Example 1: Add content to a sitewide template
One of the most common tasks I need to undertake is to add the content
generated by an application to a sitewide template. In Cgiapp, you can do
this via cgiapp_postrun().
cgiapp_postrun() is executed after the application logic is done, and
receives the generated content as its first argument:
public function cgiapp_postrun($body, $cgiapp)
{
$cgiapp->tmpl_assign('content', $body);
return $cgiapp->load_tmpl('site.phtml');
}
However, if you do this in your application logic, you're deciding things
for later users of the application. Leave it out. Instead, let the end-user
developer register their own postrun hook to do this. As an example:
require_once 'Cgiapp2.class.php';
require_once 'My/Article.php';
class OurSite
{ public
static function postrun
($body, Cgiapp2
$cgiapp) { $cgiapp->
tmpl_assign('content',
$body);
return $cgiapp->
load_tmpl('site.phtml');
}}Cgiapp2::
add_callback('postrun',
array('OurSite',
'postrun'),
'My_Article');
$app =
new My_Article
($options);
$app->
run();
The developer has now registered a 'postrun' hook with the My_Article
application. When the application flow hits the postrun event, it will
trigger OurSite::postrun(), which can then manipulate the content, throwing
it into the developer's sitewide template.
Example 2: Adding authentication
What if an article application doesn't require authentication, but you, as
the end-user developer, want to require it for the edit, add, and delete
views? Register a prerun action. Using our example from above:
require_once 'Cgiapp2.class.php';
require_once 'My/Article.php';
class OurSite
{ protected
static function _validate
($user,
$pass) { // ... validate user ... } public
static function prerun
($action, Cgiapp2
$cgiapp) { if (in_array($action,
array('add',
'edit',
'delete')) { // Need to authenticate... require_once 'Phly/Auth.php';
$auth =
new Phly_Auth
(array(self,
'_validate'));
$auth->
start();
if (!
$auth->
isValid) { // reset to the default entry for the app $cgiapp->
prerun_mode($cgiapp->
start_mode());
return;
} } } public
static function postrun
($body, Cgiapp2
$cgiapp) { $cgiapp->
tmpl_assign('content',
$body);
return $cgiapp->
load_tmpl('site.phtml');
}}Cgiapp2::
add_callback('prerun',
array('OurSite',
'prerun'),
'My_Article');
Cgiapp2::
add_callback('postrun',
array('OurSite',
'postrun'),
'My_Article');
$app =
new My_Article
($options);
$app->
run();
The example above uses Phly_Auth,
but could as easily use another authentication mechanism.
The prerun hook is executed just prior to running the requested action, and
receives the requested action as its first argument. In the code above, we
check to see if the action requires authentication, and if so, check the
user's credentials. If they are not authenticated, we then reset the action
to the default entry action.
Summary
Cgiapp2's callback hook system allows incredible opportunities for end-user
developers to customize applications on a per-instance basis. This tutorial
covered two hooks, prerun and postrun, but several more are available, and
Cgiapp2 provides the means for creating additional hooks in your
applications.
For more information on this topic, see the callback hook documentation.