Skip Navigation

Callbacks in Disco

The latest nightlies of Disco add the ability to attach callbacks at each of the major Disco process points. This new functionality allows you to use Disco in a more flexible way, and in most cases makes it unnecessary to extend the Disco base class to build web applications that use Disco.  By so doing, it allows you to structure your code how you want to, rather than how Disco requires you to, and can keep you from having to build big inheritance trees to share functionality among Disco forms. It also opens up the possibility of reusable plugins to Disco -- I'll touch on that a little later in this post.

What are callbacks?

A callback specifies a particular global function, static method on a class, or dynamic method on an object. In PHP, there are a few different kinds of callbacks:

Callback Type Form
Global function string 'function_name'
Static method on a class array('class_name','method_name')
Method on an instantiated object array(&$object, 'method_name')
(Ampersand is only necessary in PHP 4)
Anonymous function (PHP 5.3+) See Lambdas/closures (php.net) for info on how these are constructed

How does that apply to Disco?

In Disco's callback system, callbacks are used to instruct Disco to call the specified function/method at a particular point in its process. For example, if we want to send an email of the contents of a form, we might write a function that takes a disco object as its first parameter:

function emailFormContents(&$disco)
{
$body = '';
foreach($disco->get_values() as $k=>$v)
{
if(is_array($v))
$v = implode('; ',$v);
$body .= $k.': '.$v."\n\n";
}
return mail('mryan@carleton.edu','Form Submission',$body);
}

We can then tell Disco to call this function at the process phase...

$d = new disco();
$d->add_element('name');
$d->add_callback('emailFormContents','process');
$d->run();

And Disco will send the results of the form off as an email.

Process points

Disco has a set of different points where you can attach callbacks. This is a list of all of them:

  • init
  • on_first_time
  • on_every_time
  • pre_show_form
  • post_show_form
  • no_show_form
  • pre_error_check_actions
  • run_error_checks
  • post_error_check_actions
  • post_error_checks
  • process
  • where_to

Each callback point corresponds to an disco method that, if you were doing things in the traditional way, you would have to overload in an extension of disco to insert code at that point. Callbacks attached to most points simply take a reference to the disco object and interact with the object. There are two major exceptions to this rule:

  1. Callbacks attached to pre_show_form, post_show_form, and no_show_form should return XHTML strings that Disco will insert in the appropriate places
  2. Callbacks attached to where_to should return a URL

Creating a shim

One pattern available when using callbacks is to write a shim to manage a disco form, like so:

class discoShim
{
var $_email = '';
var $_where_to = '';
function set_email($address)
{
$this->_email = $address;
}
function set_where_to($url)
{
$this->_where_to = $url;
}
function send_as_email(&$disco)
{
$body = '';
foreach($disco->get_values() as $k=>$v)
{
if(is_array($v))
$v = implode('; ',$v);
$body .= $k.': '.$v."\n\n";
}
return mail($this->_email,'Form Submission',$body);
}
function next_url(&$disco)
{
return $this->_where_to;
}
}


$s = new discoShim();
$s->set_email('foo@example.edu');
$s->set_where_to('http://www.example.com');

$d = new disco();
$d->add_element('first_name');
$d->add_element('last_name');
$d->add_element('favorite_color','radio',array('options'=>array('blue'=>'Blue','green'=>'Green','red'=>'Red','yellow'=>'Yellow')));
$d->add_callback(array(&$s, 'send_as_email'),'process');
$d->add_callback(array(&$s, 'next_url'),'where_to');
$d->run();

Creating reusable functionality

You can also create tools that do a simple things, but can be used in any number of disco forms. For example, let's say you want to make sure all forms get a standard, consistent boilerplate signoff:

class boilerplate
{
function add_boilerplate(&$disco)
{
$disco->add_element('boilerplate','checkbox');
$disco->set_display_name('boilerplate','I agree to the <a href="#">Terms and conditions</a>');
$disco->add_required('boilerplate');
}
}


$b = new boilerplate();

$d = new disco();
$d->add_element('first_name');
$d->add_element('last_name');
$d->add_element('favorite_color','radio',array('options'=>array('blue'=>'Blue','green'=>'Green','red'=>'Red','yellow'=>'Yellow')));
$d->add_callback(array(&$b, 'add_boilerplate'),'on_every_time');
$d->run();

Conclusion

I hope you now understand a few of the uses of Disco's callback system. If you have any questions, please send me an email or comment on the Reason discussion group.