Event Handling Classes in PHP

Aivar - reckon that’s a really solid way of doing things you have there and agree, some of the things that have happened here (particularily my attempts ;)) are overkill.

One thing that might be nice (but again may be too much) would be to have some kind of filter on incoming parameters, depending on which module is being used, otherwise depending on how you code, users might pass you variables you dont want.

Nokia, btw, probably use something like http://www.vignette.com/ which I believe ends up turning most content into flat HTML files rather then rendering “dynamic” content.

otherwise depending on how you code, users might pass you variables you dont want.

If your code does not depend on register_globals = on and you use the $_GET and $_POST variables, this is no problem since those extra variables can’t affect the script in any way :wink:

I think Harry not only meant variables a client shouldn’t be able to set, but also variables with invalid values…

Vincent

Yeah, but then you’re talking about stuff like form validation, which I think event handling should not be responsible for.

Some variables that do need to be validated are ‘event parameters’ such as an ID of an object to edit. Since these are dynamic, they can not be set as parameters on the event handling schema of some sort.

Say you have a class ‘Event’. You could implement a method validateParameters($params) which checks if the event parameters are valid.

I was also thinking about what might happen with variable variables (the: “depending on how you code”), for example


foreach ( $params as $param ) {
    $$param=$param;
}

…might lead to surprises…

I generally don’t post because I am still trying to grasp concepts of patterns and completely understand a lot of these larger OOP concepts, but I thought you guys might appreciate a simplistic look that I have used in several of my scripts…


<?php
if(!isset($HTTP_GET_VARS['gate']) || !file_exists("actions/{$HTTP_GET_VARS['gate']}.php") || !preg_match('/[a-zA-Z0-9_-]+/', $HTTP_GET_VARS['gate'])){

!isset($HTTP_POST_VARS['gate']) ? $HTTP_GET_VARS['gate'] = 'login' : $HTTP_GET_VARS['gate'] = $HTTP_POST_VARS[gate];

}

require "actions/{$HTTP_GET_VARS['gate']}.php";


$eventHandler	= new $HTTP_GET_VARS['gate']();
$eventHandler->execute();

?>


it’s nothing extravagant but it gets the task done. An object is instantiated based on the gate command, this can of course be modified to go through an unlimited amount of commands (but really think of the ease of abuse this type of script could get, you could take down a server with a large url). If the class doesn’t exist then it just simply results to a default class which can in turn be one that shows an error message that prints out what you tried to access.

foreach ( $params as $param ) {
$$param=$param;
}

Personally, I think variable variables are just as evil as global variables. One reason for this is that your code depends on $params containing the right variables, just like with a global variable you depend on that global variable actually being there.

Agree variable variables can be evil but also sometimes a way to save alot of code, particularily when instantiating objects.

That code should actually be this to do something faintly useful;


$filter=array('username','password','email');

foreach ( $params as $param => $value ) {
   // Check variable exists
   if (in_array($param,$filter) ) {
       $$param=$value;
   }
}

Think

Here is my go at an event register/execution environment:

This class executes events:


<?php
/*
 * Application
 * The controller to execute requests
 */
class Application
{
    /* the name of the app */
    var $name;

    /* the datasource (at the moment only a DB) */
    var $data_source;

    /*
     * Constructor:
     * takes the name and a reference to a datasource
     */
    function Application($name, &$data_source)
    {
        $this->name = $name;
        $this->data_source =& $data_source;
    }


    /*
     * execute(&$request)
     * execute the event handler
     */
    function execute(&$request)
    {
        foreach($request->get_handlers() as $event => $file)
        {
            $this->fire($event, $file);
        }
    }

    /*
     * fire($event, $file)
     * fire an event
     */
     function fire($event, $file)
     {
        require_once($file);
        $handler =& new $event($this->data_source, $this);
        $handler->execute()
     }
}

?>

This class encapsulate a request. You can sub-class it to work with a specific request ie. $_GET, $_POST, XML-RPC etc


<?php
/*
 * Request
 * This class is the object that handles
 * the verifying and parsing of request
 * params(ie. $_REQUEST, $_GET etc)
 */

class Request
{
    /* Handlers to be executed */
    var $handlers;

    /* the request params - associative array */
    var $params;

    /* the map file */
    var $file;
    /*
        A map file:

        param	value	Class 		file -- don't include this line				
        page	index	IndexEvent	/Users/trickie/class.IndexEvent.php
        page	links	LinksEvent	/Users/trickie/class.LinksEvent.php
    */


    /*
     * Constructor:
     * takes the full path to a
     * event -> handler map file
     */
    function Request($event_map_file, $params)
    {
        $this->handlers = array();
        $this->file = $event_map_file;
        $this->params = $params
    }


    /*
     * get_handlers()
     * returns the array of handler names
     * to be executed.
     */
    function get_handlers()
    {
        return $this->handlers;
    }


    /*
     * map_handlers()
     * parse the request params
     * and use the file to map
     * request params to handlers
     */
    function map_handlers()
    {
        die('not implemented');
    }


    /*
     * verify_request(&$security_object)
     * secure the session, verify input etc
     */
     function verify_request(&$security_object)
     {
        return $security_object->verify($this);
     }


     /*
      * get_param($key)
      * returns the value of $key
      * if $key doesn't exist, return false
      */
      function get_param($key)
      {
        if(array_key_exists($key, $this->params))
        {
            return $this->params[$key];
        }
        return false;
      }

}



?>

This class encapsulates an event. Sub-class it to make specific event handlers:


<?php
/*
 * Event
 * This is the event handler that does a specific
 * action. It is self contained. A base class.
 *
 * 	TODO:
 * 	improve mechanism to fire new events/request
 */
class Event
{
    /* The data source (ie DB) */
    var $data_source;

    /* The application object */
    var $app;

    /*
     * Constructor:
     * Takes the data source
     */
    function Event(&$data_source, &$app)
    {
        $this->data_source =& $data_source;
        $this->app =& $app;
    }

    /*
     * execute()
     * execute the event handler
     */
    function execute()
    {
        die('not implmemented');
    }

    /*
     * fire(&$request)
     * fire a new request
     */
     function fire($event, $file)
     {
        $this->app->fire($event, $file);
     }
}

?>

This class is the skeleton of a security class. This is where you could check authenticate users etc:


<?php
class Security
{
    function Security()
    {

    }

    function verify(&$request)
    {

    }

}

?>

And finally here is an example of how you would execute events:


<?php
// require files etc

$data_source = //create the data source ie. DB
$app = new Application('New App', $data_source);
$security = new Security();

// $request_one will do stuff based on $_GET variables,
// and if necessary fire the execution of a POSTRequest
// in other words nesting events.
$request_one = new GETRequest('/Users/trickie/map1.inc.php', $_GET);
if($request_one->verify_request())
{
    $request_one->map_handlers();
    $app->execute($request_one);
}
?>

It is all a bit rough and ready but have a look and let me know what you think.

where did everyone go?

where did everyone go?

here: http://www.sitepointforums.com/showthread.php?s=&threadid=90531

I took a different approach than what you guys are doing. I made mine mimic ASP.NET’s approach to events. I dubbed the script “Odan”. It’s not fully complete yet, but it works well.

My plan is to fork PHP 3, and use that to create an something similar to ASP.NET. I’d have to re-code the PHP engine though. :frowning:

Here’s an example of how it works with forms:

layout.tpl

=============


<html>
  <body>
  <label:lbl1 visible="false" />
  <form:frm1>
    <input type="text" name="msg" />
    <input type="submit" value="submit" />
  </form:frm1>
  </body>
</html>

The code:


<?php
include("odan.php");

# Loads the template and creates all the objects;
page_start("layout.tpl");

# Executes when 'frm1' is submitted;
function frm1_submit()
{
  global $lbl1;
  $lbl1->text = "You submitted the form!";
  $lbl1->visible = true;
}

# Bind all values and create the HTML output;
page_bind();

# Display the output;
page_display();
?>

Here’s what happens:

When the page is first loaded, all the objects are created, and the page is displayed with the form. Once the form is submitted, the function form_name_submit()is called.

That’s the most basic example of how it works. Other examples are at:http://www.odan.net/

wonder’s when daholygoat is coming back to wd1 - omni :wink:

Although this thread has covered two topics, I wanted to add to just one of them. In writting an HTTPRequest class, I found that it would be nice to have a method

HTTPRequest::hasParam()

as well, since sometimes you just want to know if the parameter was set at all. This helps to avoid notice errors. A few other changes I propose are that HTTPRequest::getParam() should return NULL if the paramater was not found, so it is easy to run is_null() on the result rather than !== false (but that would just be a style change really).

Finally, it would be a neat idea to have getParam() take 3 options:

  • a name
  • a default value (if not set)
  • boolean for counting empty string as a valid value, else use default

so my method is like

function getParam($name, $default = null, $emptyIsValid = false)
{
    switch ($this->getMethod())
    {
        case 'GET':
            if (isset($_GET[$name]))
            {
                $returnValue = $_GET[$name];
            }
        break;

        case 'POST':
            if (isset($_POST[$name]))
            {
                $returnValue = $_POST[$name];
            }
            break;
    }

    // only return value if exists and non-empty unless empty is valid
    if (isset($returnValue) && ($emptyIsValid || "$returnValue" != '')
    {
        return $returnValue;
    }
    // return the default value
    else {
        return $default;
    }
}

then hasParam() can just be

function hasParam($name)
{
    return is_null(HTTPRequest::getParam($name, null, true));
}

Hi, everybody! :wavey: I see you’re trying to make somethning like ASP.NET.
Try TurboPHP. It’s a PHP IDE with events. I think events without IDE is nothing!

It like WebMatrix by the feutures.

It likes WebMatrix by the feutures.