SitePoint Sponsor |
|
User Tag List
Results 51 to 75 of 384
-
Jul 10, 2005, 18:41 #51
- Join Date
- Jun 2004
- Location
- Copenhagen, Denmark
- Posts
- 6,157
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Ezku
Curiously, I found this with google :
http://www.sebastian-bergmann.de/tal...on_Servers.pdf
See page 22-24.
-
Jul 10, 2005, 19:46 #52
- Join Date
- Aug 2004
- Location
- California
- Posts
- 1,672
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Ezku
Originally Posted by Ezku
Christopher
-
Jul 11, 2005, 08:00 #53
- Join Date
- May 2005
- Location
- Finland
- Posts
- 608
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by arborint
PHP Code:parent::FormController(
new ServerPage("page/forminit.php"),
new ServerPage("page/forminvalid.php"),
new ServerPage("page/formdone.php")
);
I do realize a lot of this is just experimentation and sketches, and I have to admit I haven't taken a look at kyberfabrikken's latest code. Perhaps my troubles are already gone; is the input validation part with rules and filters perfectly separatable from FlowController?
-
Jul 11, 2005, 08:34 #54
- Join Date
- Aug 2004
- Location
- California
- Posts
- 1,672
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Ezku
Christopher
-
Jul 11, 2005, 08:39 #55
- Join Date
- Jun 2004
- Location
- Copenhagen, Denmark
- Posts
- 6,157
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Ezku
Originally Posted by Ezku
If we implement the ApplicationController as a state-machine, we still need to process the transitions. The state-machine is a rather passive player - and the logic which decides to trigger changes in it would have to rely on something like the validator.
After seeing the pdf-file, which I linked to in post #51, I tried to use the PEAR::FSM as a basis. I ended up with less code (if you count the FSM-class out), but I'm not sure if I like that approach better. How do you think about that ?
PHP Code:require_once('FSM.php');
class FormController extends FSM
{
var $handlers = Array();
function FormController() {
parent::FSM('INIT', $null = NULL);
$this->validator =& new Validator();
$this->addTransition(
'SUBMIT', // symbol
'INIT', // required state
'NOT_VALID', // default ending state
Array($this->validator, 'validate') // trigger
);
$this->addTransition(
'SUBMIT', // symbol
'NOT_VALID', // required state
'NOT_VALID', // default ending state
Array($this->validator, 'validate') // trigger
);
$this->addHandler('INIT', new ServerPage("page/forminit.php"));
$this->addHandler('NOT_VALID', new ServerPage("page/forminvalid.php"));
$this->addHandler('VALID', new ServerPage("page/formdone.php"));
}
/**
* registers a handler for a given state
*/
function addHandler($state, &$handler) {
$this->handlers[$state] =& $handler;
}
/**
* returns the handler for the current state
*/
function & getHandler() {
if (!array_key_exists($this->_currentState, $this->handlers)) {
trigger_error("no handler registered for state '{$this->_currentState}'");
}
return $this->handlers[$this->_currentState];
}
function execute() {
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$this->process('SUBMIT');
}
$handler =& $this->getHandler();
$handler->execute();
}
}
class Validator
{
function validate() {
if (isset($_REQUEST['foo']) && !empty($_REQUEST['foo'])) {
return 'VALID';
}
}
}
class ServerPage
{
var $filename;
function ServerPage($filename) {
$this->filename = $filename;
}
function execute() {
include($this->filename);
}
}
$controller =& new FormController();
$controller->execute();
Last edited by kyberfabrikken; Jul 11, 2005 at 13:02. Reason: Linked to PEAR::FSM
-
Jul 11, 2005, 11:08 #56
- Join Date
- Sep 2003
- Location
- Glasgow
- Posts
- 1,690
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Ezku
This is all the kind of thing which TDD is good for. By now, you'd have a bunch of interaction tests using mocks and would probably be looking at consolidating with a refactoring stage.
-
Jul 11, 2005, 11:48 #57
- Join Date
- Aug 2004
- Location
- California
- Posts
- 1,672
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I finally got some time last night to actually write some code for this. kyberfabrikken has inspired me and looking at his code has answered some of the questions I had about this thing. I went a little different direction than kyberfabrikken with the states and transitions. I implemented a separate StateMachine class just to show what is going on. This should be integrated into an Application Controller class later (and refactored !).
I wanted to be able to use our standard Rules (Overrunner's) so I added a check() method to the InputController and InputControllerParameter classes so they can be used as rules. Other than that the Input Controller code is the same as before (with some of the naming and code changes requested here).
Instead of kyberfabrikken's boolean conditions I implemented "from state" and "to state" values for the transition. This allows a cascade. We would need to add a session object to save the state for more complex action sets, but it works fine without it for the Form Controller case of an Application Controller which is what I have implemented in this example.
The code dealing with the State Machine looks like this:PHP Code:include_once 'StateMachine.php';
// create state machine and set default state
$statemachine = new StateMachine('init');
// register states managed by this controller
$statemachine->addState(new State('init', new InitHandler($controller)));
$statemachine->addState(new State('submit', new SubmitHandler($controller)));
$statemachine->addState(new State('done', new DoneHandler($controller)));
// register register transitions with from state, to states and rule
$statemachine->addTransition(new Transition('init', 'submit', new RequiredRule('submit', 'submit')));
$statemachine->addTransition(new Transition('submit', 'submit', $controller, false));
$statemachine->addTransition(new Transition('submit', 'done', $controller));
// find state based on transition rules above
$handler =& $statemachine->findState($request);
$handler->execute($request, $response=null);
The code can be downloaded here. It adds the StateMachine class and puts the code above into the example_inputcontroller.php file.Christopher
-
Jul 11, 2005, 11:51 #58
- Join Date
- May 2005
- Location
- Finland
- Posts
- 608
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by kyberfabrikken
I somewhat agree that it's a mix of interests, I can't see any practical problem associated with it. It may be that I've just not thought it through?
This separation is easily done:PHP Code:/**
* Validates and filters input data
*
* @author Ezku (dmnEe0@gmail.com)
* @since Jul 11, 2005
*/
class Validator
{
protected $rules = NULL;
protected $filters = NULL;
/**
* Add filter to stack
* @param object IInputFilter
*/
public function addFilter(IInputFilter $filter)
{
$this->filters[] = $filter;
}
/**
* Add rule to stack
* @param object IInputRule
*/
public function addRule(IInputRule $rule)
{
$this->rules[] = $rule;
}
/**
* Run filters and match rules on DataObject, log errors to Logger
* @param object DataObject
* @param object ILogger
* @return boolean is valid
*/
public function validate(DataObject $data, ILogger $logger)
{
$errors = 0;
foreach ($this->filters as $filter)
{
$data = $filter->process($data);
}
foreach ($this->rules as $rule)
{
$error = $rule->validate($data);
if (!empty($error))
{
$logger->log($error);
++$errors;
}
}
return ($errors == 0);
}
}
interface IInputFilter
{
/**
* Returns filtered DataObject.
* @param object DataObject
* @return object DataObject
*/
public function process(DataObject $data);
}
interface IInputRule
{
/**
* Returns error message on failure, empty on success.
* @param object DataObject
* @return string error message
*/
public function validate(DataObject $data);
}
PHP Code:class FlowController implements IHandler
{
protected $success = NULL;
protected $failure = NULL;
protected $validator = NULL;
public function __construct(IHandler $success, IHandler $failure)
{
$this->success = $success;
$this->failure = $failure;
$this->validator = new Validator;
}
public function execute(Request $request, Response $response)
{
$logger = new Logger;
if ($this->validator->validate($request, $logger))
{
$this->success->execute($request, $response);
}
else
{
$this->request->set('errors', $logger->getMessages());
$this->failure->execute($request, $response);
}
}
public function addFilter($filter)
{
$this->validator->addFilter($filter);
}
public function addRule($rule)
{
$this->validator->addRule($rule);
}
}
(We didn't yet decide on the name of the data holder class, did we?)
-
Jul 11, 2005, 12:18 #59
- Join Date
- May 2005
- Location
- Finland
- Posts
- 608
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Off Topic:
Originally Posted by McGruff
-
Jul 11, 2005, 12:54 #60
- Join Date
- Nov 2001
- Location
- Bath, UK
- Posts
- 2,498
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Ezku
Detestable (adjective): software that isn't testable.
Regards,
DouglasHello World
-
Jul 11, 2005, 12:55 #61
- Join Date
- Jun 2004
- Location
- Copenhagen, Denmark
- Posts
- 6,157
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by McGruff
Originally Posted by ezku
Originally Posted by ezku
Originally Posted by arborint
Or did I miss your point ?
Originally Posted by arborint
Regardless - I definately like this design better than what I posted in post #48.
Shouldn't we try to stick with the post #55 variant though, since it utilizes some really nice and stable code from the PEAR repository?
-
Jul 11, 2005, 13:06 #62
- Join Date
- Sep 2003
- Location
- Glasgow
- Posts
- 1,690
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Ezku
-
Jul 11, 2005, 13:24 #63
- Join Date
- Aug 2004
- Location
- California
- Posts
- 1,672
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by kyberfabrikken
Originally Posted by kyberfabrikken
Originally Posted by kyberfabrikken
Christopher
-
Jul 11, 2005, 13:41 #64
- Join Date
- Jun 2004
- Location
- Copenhagen, Denmark
- Posts
- 6,157
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by arborint
Originally Posted by arborint
Originally Posted by arborint
The relationship between ApplicationController and StateMachine may be composite or through inheritance, but either way the enhancements will happen in the ApplicationController - not in the StateMachine ?
-
Jul 11, 2005, 13:43 #65
- Join Date
- Aug 2004
- Location
- California
- Posts
- 1,672
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by kyberfabrikken
I'm still not convinced of the Logger.Christopher
-
Jul 11, 2005, 14:10 #66
- Join Date
- Jan 2003
- Posts
- 5,748
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I'm still not convinced of the Logger.I see it as being an extension over what basic error reporting you would implement in it's (the Logger) absense? You can do more with an object, than simply putting errors to an array (I assume this is the default alternative?).
-
Jul 11, 2005, 16:19 #67
- Join Date
- May 2005
- Location
- Finland
- Posts
- 608
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by DougBTX
(And thanks for the tip, too.)
Originally Posted by kyberfabrikken
DataSource, as said, implies read-only. DataObject, while accurate, is a bit awkward for a name. On the other hand, DataSpace just seems odd, which leaves me with DataSet. And doesn't that name imply something "dynamic"?
Well - suggestions, votes?
Whether we should use a logger for the validator/rules is also still an open topic. My vote is most definately a 'Yes'.
-
Jul 11, 2005, 16:43 #68
- Join Date
- Jun 2004
- Location
- Copenhagen, Denmark
- Posts
- 6,157
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Ezku
WACT originally used the term DataSpace, but changed it to DataSource ... I'm not quite sure why, but I think they changed the implementation at the same time, so it may be more than just an arbitrary namechange.
Edit:
Phrame has a HashMap class. The nice thing about this name is that it's used in java. The drawback is that it implies putting a couple of methods into the class which we might not want to include in order to match the original. But I'm not sure that's so bad, since it's just about half a dozen and rather usefull ones.
Considering, I think my vote goes for HashMap, even though I think DataSpace sounds much cooler.
Last edited by kyberfabrikken; Jul 11, 2005 at 17:20.
-
Jul 11, 2005, 17:52 #69
- Join Date
- Aug 2004
- Location
- California
- Posts
- 1,672
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Ezku
I think DataObject and DataSet mean other things so shouldn't be used. That leaves us with DataSpace implying like NameSpace an area, or DataSource implying an origin. I'd say that for what we might use it for (the Reqest, Session, etc.) that DataSource makes more sense.Christopher
-
Jul 11, 2005, 19:41 #70
- Join Date
- Aug 2004
- Location
- California
- Posts
- 1,672
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by kyberfabrikken
Also, the Input Controller needs to add some logic to "control" the Application Controller and dispatch the Command(s). So far the InputController class is just a Request Processor so controlling the Application Controller needs to be added.
The Commands also need a way to directly set the state or forward. For example you might implement a three form sequence with the Transitions:PHP Code:Transition('initpage1', 'submitpage1', new RequiredRule('submit'))
Transition('submitpage1', 'donepage1', $controller)
Transition('donepage1', 'initpage2', ????)
Transition('initpage2', 'submitpage2', new RequiredRule('submit'))
Transition('submitpage2', 'donepage2', $controller)
Transition('donepage2', 'initpage3', ????)
Transition('initpage3', 'submitpage3', new RequiredRule('submit'))
Transition('submitpage3', 'donepage3', $controller)
And we really haven't dealt with MVC support yet. An MVC Applicaition Controller would return a Model and View. It would be in the 'skeleton' style to support either a single Command Handler or have a MVCHandler that can create both the Model and View. Then the question is: who passes the Model to the View and then passes the Response along? The MVCHandler or the InputController?
All these and more give me the sense that when the StateMachine class turns into an Applicaition Controller class it will have more to it. The findState() function is a is really the extent of the State Machine and it is pretty trivial to meet the Applicaition Controller's needs.Last edited by arborint; Jul 11, 2005 at 21:32.
Christopher
-
Jul 11, 2005, 22:35 #71
- Join Date
- Sep 2003
- Location
- Glasgow
- Posts
- 1,690
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Ezku
In general, you'll get hamstrung if you don't parcel out different responsibilities in nice, tight classes. I've a feeling it could be a good idea to get to work with a scalpel but I'm not sure where you're at right now.
-
Jul 11, 2005, 23:04 #72
- Join Date
- Aug 2004
- Location
- California
- Posts
- 1,672
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by McGruff
I would recommend to anyone who is not currently using Filter/Rule style processing of the request to give this code a try. It will focus you on each parameter you are accepting and probably improve the security of you code.Christopher
-
Jul 12, 2005, 03:24 #73
- Join Date
- May 2005
- Location
- Finland
- Posts
- 608
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by McGruff
PHP Code:/**
* Facade for InputValidator and InputFilterChain
*
* @author Ezku (dmnEe0@gmail.com)
* @since Jul 12, 2005
*/
class InputController
{
protected $validator = NULL;
protected $filter = NULL;
public function __construct()
{
$this->validator = new InputValidator;
$this->filter = new InputFilterChain;
}
/**
* Process input
* @param object DataObject
* @param object ILogger
* @return boolean validity
*/
public function process(DataObject $data, ILogger $logger)
{
$data = $this->filter->process($data);
$validity = $this->validator->validate($data, $logger);
return $validity;
}
public function addRule($rule)
{
$this->validator->addRule($rule);
}
public function addFilter($filter)
{
$this->filter->addFilter($filter);
}
}
PHP Code:/**
* Validates input data
*
* @author Ezku (dmnEe0@gmail.com)
* @since Jul 11, 2005
*/
class InputValidator
{
protected $rules = NULL;
/**
* Add rule to stack
* @param object IInputRule
*/
public function addRule(IInputRule $rule)
{
$this->rules[] = $rule;
}
/**
* Match rules on DataObject, log errors to Logger
* @param object DataObject
* @param object ILogger
* @return boolean is valid
*/
public function validate(DataObject $data, ILogger $logger)
{
$errors = 0;
foreach ($this->rules as $rule)
{
$error = $rule->validate($data);
if (!empty($error))
{
$logger->log($error);
++$errors;
}
}
return ($errors == 0);
}
}
PHP Code:/**
* Filters input data
*
* @author Ezku (dmnEe0@gmail.com)
* @since Jul 12, 2005
*/
class InputFilterChain implements IInputFilter
{
protected $filters = NULL;
/**
* Add filter to stack
* @param object IInputFilter
*/
public function addFilter(IInputFilter $filter)
{
$this->filters[] = $filter;
}
public function process(DataObject $data)
{
foreach ($this->filters as $filter)
{
$data = $filter->process($data);
}
return $data;
}
}
Am I asking things that are already resolved? Sorry for lagging behind, as I see most of you are already at the ApplicationController implementation, full steam.
-
Jul 12, 2005, 04:29 #74
- Join Date
- Mar 2004
- Location
- Sweden
- Posts
- 180
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Hmm, we seem to have a lot of Controllers and stuff in the air, so I'm going to ask a bunch of questions
1. How is the Application Controller, Input Controller and Flow Controller related to each other? Do they
co-operate anything? By just looking at the code, I think the responsibilities of the Flow Controller overlap with the Input Controller.
2. In one of kyberfabrikken's example (here), he seem to have put request/(form) validation code in the Application controller, which we also have in the Input Controller. Do we need such validation in both places?
3. arborint: Why did you introduce a Transition object? How does it work exactly?
4. Should a Form Controller inherit from the AC or IC or neither?
5.Originally Posted by arborint
arborint: I think you should rename the processRequest method in the InputControllerParameter class to processParameter. Since the entire request will get processed in the Input Controller rather than in a single parameter.
Originally Posted by Ezku
Sorry for lagging behind, but I think we should primarly focus on the AC / Statemachine etc, and leave the Input Controller for a moment.
-
Jul 12, 2005, 05:03 #75
- Join Date
- Jun 2004
- Location
- Copenhagen, Denmark
- Posts
- 6,157
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Overunner
The main difference between the two designs is that in the FlowController-design, there is no InputController. Instead that resposibility is pushed into the FlowController which acts as a combination of Validator, InputController and Transition. The actual implementation may seperate theese into different components, which would make the FlowController a composite of thoose. This is what Ezku have been moving towards in post #58
On the contrary, the StateMachine-design has an InputController as the main catalyst, which use the StateMachine for holding state (Transitions describe a change in state). It has a 1:1 relationship between Transition<->Validator like the FlowController-design, but they are passive players, in contrast to the FlowController-design.
Originally Posted by arborint
I have a sneaky feeling that as begin to work on the InputController, the code will end up looking more like the FlowController-design.
Originally Posted by Ezku
Originally Posted by Overunner
Bookmarks