Vincent's post reminded me of stuff I read about Struts, a java opensource framework.
I think some of you might be interested in reading the users guide, especially :
http://jakarta.apache.org/struts/use...ontroller.html
| SitePoint Sponsor |
Vincent's post reminded me of stuff I read about Struts, a java opensource framework.
I think some of you might be interested in reading the users guide, especially :
http://jakarta.apache.org/struts/use...ontroller.html




If I understand it correctly, struts has an XML file where all 'events' (aka Commands / Actions) are registered. When a request is received, struts looks in this XML file to determine the appropriate Action class to instanciate and to execute.
I don't like the fact however that you seem to be tied to registering each form and its field in that XML file too.
This is explained at :
http://jakarta.apache.org/struts/use...apping_example
One of the advantages is to let you change the application flow without editing the code (but the configuration file). I guess a side effect is that the file can be seen as a (partial) description of the dynamic parts of the application.

vudu - thanks for the tip off on struts - you're spot on! When I get some more time to spend on this, I'll update the code to do things that way (I like it when there's already some kind of standard in place).
And reading that struts description, that's exactly what I'm aiming for - what I'm actually heading for is not really event handling but the "Controller" in a Model View Controller pattern.
Many thanks again for a push in the right direction.The goal of an Action class is to process a request, via its execute() method, and return an ActionForward object that identifies where control should be forwarded (e.g. a JSP) to provide the appropriate response.
The Chain of Responsibility pattern (Gang of four) has a different approach to this problem
(in case hashtables don't satisfy your wants/needs)




The method of event-handling Chain of Responsibility describes is more suited to desktop applications, where an event is something like the user clicking on the screen.
I think that in this thread we have established that in PHP an event is a request made by the browser to an application. Correct me if I'm wrong, but I don't see how CoR could be helpful in such a situation, especially because CoR works from 'small' (in a desktop application: something like a textbox) to 'big' (the entire screen) and event handling in PHP works exactly the opposite way: from 'big' (the entire application, a module) to 'small' (a specific command to execute).

Ran into an interesting PHP project today: http://phrame.itsd.ttu.edu/
Open SourcePhrame is a Web development platform for PHP that is based on the design of Jakarta Struts. It provides a basic Model-View- Controller architecture, and adds standard components such as HashMap, ArrayList, and Stack.
As I understand, events in php are used to organize the flow of execution on top level of program. I see the problems with huge switch statement or chain of ifs (have had problems with this myself) but I still don't see the need for so sophisticated solutions as those presented in this thread. Here is what I invented to cure the "chain of ifs" problem.
Usually my scripts (exept those that contain only function or class definitions) had three parts:
1. first I set things up like connect to database, create helper objects and so on
2. then I had that chain of ifs, to decide what action to take this time. If there was no action needed, then this part did nothing.
3. and then I showed the page
After reading this thread I tried to encapsulate responsibilities of a script into an object like this:
In every script there is an object that encapsulates all functionality that user can get out of this script. Lets call it "a module". Its task is to provide interface for functionality not to implement it.
so, I deciced to use the set of public methods instead of events table.PHP Code:class EmployeeModule extends WebModule
{
// 1. - constructor
// don't care whether there will be an action this time
function EmployeeModule ($params)
{
$this->db = new DBConnection ('scott', 'tiger');
// any other setup here, including creating
// business objects
}
// 2. - public "action" methods or event handlers.
// What method to call depends on a special input
// parameter, for example 'task' or 'message', all
// other parameters end up as parameters for that method
function update ($params)
{
}
function delete ($params)
{
}
function doSomethingElse ($params)
{
}
// 3. - presentation
// don't care whether there was an action this time
function show ($params)
{
// here compile all data to present and then ...
include ('Employee.template.php');
}
}
As each method takes one parameter (an associative array of script input parameters), it's possible to manipulate this object automatically like this:
Module don't depend on $_GET or something like this, so its possible to use it as a submodule in another module that may forward some of its messages (or events) to submodules.PHP Code:// creates module; if there is an action parameter present
// then calls module's handleMessage($msg, $params) method
// (this is inherited from WebModule and by default calls
// method named $msg)
// and then asks module to show itself
RequestHandler::run ('EmployeeModule');
Or you can use a module like a switch that takes care of application level tasks like user authentication and database connection but forwards specific messages to a module specified with an input parameter.
Main classes are very simple:
I'd be happy hearing your critics on this idea.PHP Code:class WebModule
{
function WebModule ($params=array())
{
// do nothing by default
}
function handleMessage ($msg, $params=array())
{
return $this->$msg($params);
}
function show ($params=array())
{
// output nothing by default
}
}
class RequestHandler
{
function run ($module_class_name)
{
$params = array_merge ($GLOBALS['HTTP_GET_VARS'],
$GLOBALS['HTTP_POST_VARS']);
$module = new $module_class_name ($params);
if ($params['_msg']) {
$module->handleMessage ($params['_msg'], $params);
}
$module->show($params);
}
}
Aivar
Last edited by aivarannamaa; Dec 2, 2002 at 13:26.
Sure, CoR could be a bit 'too much', but then, I think that entirely depends on how you apply the pattern. If your interpretion of "specific commands to execute" were represented as handler classes that take care of the desired action to be taken, it's not all that hard to build a chain of responsibility, and in some cases you could probably even benefit from it (I'm just assuming you know how the pattern can be applied).Correct me if I'm wrong, but I don't see how CoR could be helpful in such a situation, especially because CoR works from 'small' (in a desktop application: something like a textbox) to 'big' (the entire screen) and event handling in PHP works exactly the opposite way: from 'big' (the entire application, a module) to 'small' (a specific command to execute).
But like I said, applying CoF in situations described here is usually way beyond what you want, but I'm just saying it can be done that way. I personally use a hashtable in most of these cases, easy enough. I'm not even a fan of CoF, but that's a completely different story![]()
this is a bit off topic, but how are events on pages like these are handled, i'm not too sure what their backend are driven by, but how they work with ",".
http://www.nokia.com/nokia/0,5184,65,00.html

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.




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 wayotherwise depending on how you code, users might pass you variables you dont want.![]()



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
...might lead to surprises...PHP Code:foreach ( $params as $param ) {
$$param=$param;
}
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...
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.PHP Code:<?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();
?>




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.foreach ( $params as $param ) {
$$param=$param;
}

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;
ThinkPHP Code:$filter=array('username','password','email');
foreach ( $params as $param => $value ) {
// Check variable exists
if (in_array($param,$filter) ) {
$$param=$value;
}
}




Here is my go at an event register/execution environment:
This class executes events:
PHP Code:<?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 Code:<?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 Code:<?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 Code:<?php
class Security
{
function Security()
{
}
function verify(&$request)
{
}
}
?>
And finally here is an example of how you would execute events:
PHP Code:<?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.

here: http://www.sitepointforums.com/showt...threadid=90531where did everyone go?
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.
Here's an example of how it works with forms:
layout.tpl
=============
The code:PHP Code:<html>
<body>
<label:lbl1 visible="false" />
<form:frm1>
<input type="text" name="msg" />
<input type="submit" value="submit" />
</form:frm1>
</body>
</html>
Here's what happens:PHP 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();
?>
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![]()
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
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).PHP Code:HTTPRequest::hasParam()
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
then hasParam() can just bePHP Code: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;
}
}
PHP Code:function hasParam($name)
{
return is_null(HTTPRequest::getParam($name, null, true));
}





Hi, everybody!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!
Last edited by Mika; Feb 2, 2003 at 05:57.





It like WebMatrix by the feutures.
Bookmarks