SitePoint Sponsor

User Tag List

Page 1 of 13 1234511 ... LastLast
Results 1 to 25 of 384

Hybrid View

  1. #1
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Design an ApplicationController implementation together

    This thread takes of from where the massive skeleton thread becomes a discussion of ApplicationController rather than the FrontController. About right here.

    Quote Originally Posted by Ryan Wray
    It may be nice to branch off into a seperate thread to discuss the Application Controller -- considering this thread was really only concerned with a Front Controller. That way any comments about the Front Controller can be seperated from the Application Controller, and people can become aware that the Application Controller is being developed, instead of maybe getting lost in the development of the Front Controller leading up to it.

    What do you think?
    I agree.

  2. #2
    throw me a bone ... now bonefry's Avatar
    Join Date
    Nov 2004
    Location
    Romania
    Posts
    848
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Someone should define first what an application controller is since it can mean different things.

    I myself consider the application controller just a front controller with a filter in it for handling authentification for example.

  3. #3
    SitePoint Addict
    Join Date
    Jan 2005
    Location
    Ireland
    Posts
    349
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    From my observation of the last thread, the lastest file realease (made by arborint) is available here.

    kyberfabrikken has given a good account of things that need to be thought about when it comes to the Application Controller.

    From now on, hopefully we can sustain this thread independtly from the Front Controller. Alot of information is available about the Front Controller, including development details and code, in this thread

    Now, lets make this thread just as big as the other one!

  4. #4
    SitePoint Guru
    Join Date
    May 2005
    Location
    Finland
    Posts
    608
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Despite the flexibility we attained in the first part, I think it's pretty important for people contributing to the ApplicationController to know a bit about our FrontController design, so as to take advantage of what we already have and avoid overlapping responsibilities - here's a wrap up:
    Quote Originally Posted by Ezku
    • Page flow starts with constructing the FrontController
    • The FrontController takes an object implementing IRequestMapper as its constructor argument
    • The FrontController implements IHandler
    • IHandler defines the execution method, which takes two arguments: a Request and a Response.
    • The FrontController uses the RequestMapper to fetch an object implementing IHandler
    • The Handler is executed by the FrontController
    • Page flow ends with a main level call to Response->out();

    In addition to this, there is the HandlerChain object.
    • The HandlerChain object can be used to construct a chain of Handlers; this may be used eg. to filter the Request or create Controller tree structures
    • Any IHandler-implementing object (The FrontController, "Filter" objects, Controllers or HandlerChains) may be added to the chain
    • When the HC is executed, the contained Handlers will be executed one at a time in the order they were added
    • Note that this is a straight chain and not a Chain of Responsibility
    Conclusive posts by me here (PHP5) and by arborint here (PHP4), both equipped with functioning code packages.

    As for this thread, up first we'd need a solid definition on what an ApplicationController is and what our goals are.

  5. #5
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by arborint
    I agree it is more a ViewHelper than a FormModel (which I noted originally).
    I pretty much agree on that - so it's probably a matter of using the right word for it. How about FormDescriptor instead ? This object would hold a list of which fields the form should have, aswell as their rules and filters. Based on this FormDescriptor, we could create a FormView, which renders the html-markup for the form, and a FormSubmitHandler which would update the form from the request. Dependning on if the form is valid, the FormSubmitHandler would then either redirect back to the FormView (on not valid) or execute a domain-command (on valid). I suppose this makes the FormSubmitHandler an ApplicationController ?

    I have stitched some code together for this, to get us started. The implementation of FormView and FormSubmitHandler are very sketchy - especially the latter could probably lead to some discussion.

    I have re-arranged Filters and Rules a bit ... the biggest change is probably that I introduced a Logger, rather than let the Rule return messages. This is a design I have used before, and I quite like it. What do you think about this ?
    Attached Images Attached Images
    Attached Files Attached Files

  6. #6
    SitePoint Guru
    Join Date
    May 2005
    Location
    Finland
    Posts
    608
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    I have re-arranged Filters and Rules a bit ... the biggest change is probably that I introduced a Logger, rather than let the Rule return messages. This is a design I have used before, and I quite like it. What do you think about this ?
    Looking at the UML it seems very nice. Good job.

  7. #7
    SitePoint Zealot Overunner's Avatar
    Join Date
    Mar 2004
    Location
    Sweden
    Posts
    180
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Just looked briefly at your code. I must say I'm not too wild about having PHP echo HTML-contents. In your view.php for example, you print a bunch of textfields. Why not have these textfields in a template, or perhaps serverpage instead?

    Btw, have you looked at the latest revision of the code in the Front Controller thread? (available here)

  8. #8
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Overunner
    Just looked briefly at your code. I must say I'm not too wild about having PHP echo HTML-contents. In your view.php for example, you print a bunch of textfields. Why not have these textfields in a template, or perhaps serverpage instead?
    That's what I meant when I wrote that they were very sketchy. FormView could be implemented as a serverpage or as a widget, and would use a widget for each fieldtype. Likewise FormSubmitHandler should likely be implemented as a class implementing IHandler.

    A design-issue to consider, which I didn't mention is the FilterChain and Validator classes. There really isn't any reason why they are seperate classes, when they could just be incorporated directly into FieldDescriptor. What's the general feeling towards this ?

  9. #9
    SitePoint Guru
    Join Date
    May 2005
    Location
    Finland
    Posts
    608
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    That's what I meant when I wrote that they were very sketchy. FormView could be implemented as a serverpage or as a widget, and would use a widget for each fieldtype. Likewise FormSubmitHandler should likely be implemented as a class implementing IHandler.
    I'd be interested in seeing a sketch on this later.
    There really isn't any reason why they are seperate classes, when they could just be incorporated directly into FieldDescriptor. What's the general feeling towards this ?
    I don't see a reason for them to be separate. Go ahead.

  10. #10
    SitePoint Guru
    Join Date
    May 2005
    Location
    Finland
    Posts
    608
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    Dependning on if the form is valid, the FormSubmitHandler would then either redirect back to the FormView (on not valid) or execute a domain-command (on valid). I suppose this makes the FormSubmitHandler an ApplicationController ?
    You're right, this is AC functionality. Let's keep it at that - the input validation stuff you're now designing is something for the AC or its delegates to be used. By the way, do they have to be named "Form" when there's no real form functionality, it's just input validation as it is - I suppose the purpose was to create an InputController, which may or may not be different from what you have right now. I hope I'm making sense. :D

  11. #11
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    I pretty much agree on that - so it's probably a matter of using the right word for it. How about FormDescriptor instead ? This object would hold a list of which fields the form should have, aswell as their rules and filters. Based on this FormDescriptor, we could create a FormView, which renders the html-markup for the form, and a FormSubmitHandler which would update the form from the request. Dependning on if the form is valid, the FormSubmitHandler would then either redirect back to the FormView (on not valid) or execute a domain-command (on valid). I suppose this makes the FormSubmitHandler an ApplicationController ?

    I have stitched some code together for this, to get us started. The implementation of FormView and FormSubmitHandler are very sketchy - especially the latter could probably lead to some discussion.

    I have re-arranged Filters and Rules a bit ... the biggest change is probably that I introduced a Logger, rather than let the Rule return messages. This is a design I have used before, and I quite like it. What do you think about this ?
    I really don't see the difference between the code you posted and what Overrunner and I had discussed as a Form Controller except I think Overrunner's rules are superior. It is more a stylistic difference with a Logger and Factory added. I don't know why you'd need a Factory when 99% of the time there will just be one form. I am not a big fan of Loggers because they are just fancy echo() statements and with unit tests they are not really needed. I think if you wanted to tuck the error messages into an object then using the Datasource class would be the most straightforward. But what you really have is a Context object.

    If we extend the InputController class to create a FormController class it the same as your "FormDescriptor" and if we extend the InputController class to create a FormControllerParameter class it the same as your "FieldDescriptor". Inheritence is not the only way to deal with this. We could also have a context object to move the information between them. It would be good to support both methods.

    I notice that because managing forms is so common that monolithic solutions are very common. The thing I have been trying to communicate is that a Form Contoller is really a three state Application Controller. Whereas an Application Controller can deal with N states and can extend across many pages, a Form Contoller really only deals with a single page (or two pages) and has the states: init, redisplay and done. Those three states are built from the following capabilities: determine state, load data, display form, filter/validate, save data. If load/save are the Model and display form is the View, then that puts determine state and filter/validate in the Controller. So far we have filter/validate but we haven't dealt with "determine state".

    Unfortunately the "determine state" part of a From Controller is really just a couple of IF statements (i.e. Form Submitted? No Errors?). That is part of what makes the leap to an Application Controller difficult.

    That get's me back to the Input Controller because it isn't done yet (as McGruff noted it is just a Request Processer right now). How to we add the state logic and possibly dispatch to the Input Controller? I am beginning to think that plug-in state machines (similar in concept/goals the plug-in Mappers in the Front Controller) is the way to go. That decouples the logic of the page moving it out of the housekeeping and structure code. The goal is that you can write a Controller with any behavior by changing just the state machine with the goal of not having the maximum amount of code outside the state machine. We could supply standard single form and wizard (multi-form sequence) state machines (and the requsite RoR emulator ).
    Christopher

  12. #12
    SitePoint Guru
    Join Date
    May 2005
    Location
    Finland
    Posts
    608
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by arborint
    I really don't see the difference between the code you posted and what Overrunner and I had discussed as a Form Controller except I think Overrunner's rules are superior. It is more a stylistic difference with a Logger and Factory added.
    Although I initially liked the Factory, after giving it some thought I must question the need for it. The configuration part is also a bit on the fuzzy side... Perhaps I like the idea but dislike the execution. Whereas the Logger I do like - it's just that you can do it with a regular Datasource, no need for a specialized class. :) If you need persistance, use an extended PersistentDatasource.

    I'm a bit confused - are you creating a FormController or an InputController? The naming, of course, implies the former, but there's nothing form-specific as far as I can tell. Was I right in saying that whichever is for the AC to use?
    Quote Originally Posted by kyberfabrikken
    Whichever way it turns out, I must insist though to keep the interface IRule for obvious reasons.
    As well as the IFilter.

  13. #13
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Ezku
    I'm a bit confused - are you creating a FormController or an InputController?
    I think I was just firing blind. As arborint points out, much of it was just the InputController0.4 code with different naming. I didn't realize it till now.

    As for the DataSource class ... what is that really for ? I can't see it used anywhere in the code, and seems to be such an abstract concept that it bears no real meaning ?

    By the way - Why use arrays for rules/filters in the InputControllerParameter class ? Wouldn't the following be easier and a lot cleaner ?
    PHP Code:
    class InputControllerParameter
    {
        var 
    $name '';
        var 
    $value '';

        var 
    $filters;
        var 
    $rules;

        function 
    InputControllerParameter($name) {
            
    $this->name $name;
            
    $this->filters =& new FilterChain();
            
    $this->rules =& new Validator();
        }

        function 
    addFilter(&$filter) {
            
    $this->filters->addFilter($filter);
        }

        function 
    addRule(&$rule) {
            
    $this->rules->addRule($rule);
        }

        function 
    getValue() {
            return 
    $this->value;
        }

        function 
    setValue($value) {
            
    $this->value $value;
        }

    // end class InputControllerParameter 
    I also noticed that the filterRequest method of the class InputController modifies the original request. I don't think that's a good idea. Besides - the method-name is a bit deceptive. It should probably be named import or something similar ?
    How about :
    PHP Code:
    class InputController
    {
    (...)
        function 
    import(&$request) {
            foreach (
    array_keys($this->params) as $key) {
                
    $this->params[$key]->setValue($this->params[$key]->filters->doFilter($request->get($key)));
            }
        }
    (...)
    // end class InputController 

  14. #14
    SitePoint Guru
    Join Date
    May 2005
    Location
    Finland
    Posts
    608
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    Wouldn't the following be easier and a lot cleaner ?
    Yes. But say - why would one want the InputControllerParameter to keep track of its filters and rules if it's basically the InputController's job, and they [filters & rules] should be able to access all data anyway (in order to have combined requirements)? I'm asking because everyone seems to be doing it and I don't know why.
    As for the DataSource class ... what is that really for ? I can't see it used anywhere in the code, and seems to be such an abstract concept that it bears no real meaning ?
    Yeah, that had me puzzled for a while as well. The fact is it's just an object encapsulating an array. :)

    I guess the point in this context was that the filters and rules, hosted by the InputController, would get passed a Datasource (my DataObject) containing all the data so as to let them access whatever fields they want.

    I use this myself (PHP5):
    PHP Code:
    <?php
    /**
     *    Name:        DataObject.php
     *    Purpose:    Generic data holder object. Provides ArrayAccess and Iterator functionality.
     */
    class DataObject implements IteratorArrayAccess
    {
        protected 
    $data = array();
        
        
    /**
         * Set a parameter.
         * @param    string    parameter name
         * @param    mixed    parameter value
         */
        
    public function set($name$value)
        {
            
    $this->data[$name] = $value;
        }
        
        
    /**
         * Retrieve a parameter.
         * @param    string    parameter name
         * @param    mixed    default value if not found
         */
        
    public function get($name$default=NULL)
        {
            return (isset(
    $this->data[$name]) ? $this->data[$name] : $default);
        }
        
        
    /**
         * Indicate whether or not a parameter exists.
         * @param    string    parameter name
         * @return    boolean
         */
        
    public function has($name)
        {
            return isset(
    $this->data[$name]);
        }
        
        
    /**
         * Remove a parameter.
         * @param    string    parameter name
         */
        
    public function remove($name)
        {
            unset(
    $this->data[$name]);
        }
        
        
    /**
         * Retrieve parameter names.
         * @return    array
         */
        
    public function names()
        {
            return 
    array_keys($this->data);
        }
        
        
    /**
         * Retrieve all data
         * @return    array    object data
         */
        
    public function all()
        {
            return 
    $this->data;
        }
        
        
    /**
         * Replicate data (any old parameters are lost)
         * @param    mixed    Array or ArrayAccess
         */
        
    public function copy($data)
        {
            if (
    is_array($data) || $data instanceof ArrayAccess)
            {
                
    $this->data $data;
                
    reset($this->data);
            }
        }
        
        
    /**
         * Append parameter.
         * @param    mixed    parameter value
         */
        
    public function append($value)
        {
            
    $this->data[] = $value;
        }
        
        
    /**
         * DataObject constructor. Pass a copyable argument to set initial values.
         * @param    mixed    initial values, optional
         */
        
    public function __construct($data NULL)
        {
            
    $this->copy($data);
        }
        
        public function 
    __set($name$value) { return $this->set($name$value); }
        public function 
    __get($name) { return $this->get($name); }
        
        
    /**
         * Iterator implementation
         */
        
        
    public function current() { return current($this->data); }
        public function 
    key() { return key($this->data); }
        public function 
    next() { return next($this->data); }
        public function 
    rewind() { return reset($this->data); }
        public function 
    valid() { return current($this->data) !== FALSE; }
        
        
    /**
         * ArrayAccess implementation
         */
        
        
    public function offsetExists($offset) { return isset($this->data[$offset]); }
        public function 
    offsetSet($offset$value) { $this->set($offset$value); }
        public function 
    offsetGet($offset) { return $this->get($offset); }
        public function 
    offsetUnset($offset) { unset($this->data[$offset]); }
        
    }
    ?>
    There's some basic functionality here that comes in handy in a multitude of objects, say Request.
    I also noticed that the filterRequest method of the class InputController modifies the original request.
    I've been getting this feeling lately that what we need is a Context object after all. I can't quite put my finger on it, but there've been many questions that've had me thinking of the possibilities of introducing Context. Just a hunch, really, since my comprehension on the whole purpose of the class is a bit lacking, to say the least.

    Bah, I'm probably all wrong anyway. Do correct me - now I have to go get some sleep before I drop on my keyboard.

  15. #15
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    As for the DataSource class ... what is that really for ? I can't see it used anywhere in the code, and seems to be such an abstract concept that it bears no real meaning ?
    Funny, I thought you would like the Datasource class as it is really the base class for the Request class and any other class with the main interface of get($name) and set($name, $value) methods.
    Quote Originally Posted by kyberfabrikken
    By the way - Why use arrays for rules/filters in the InputControllerParameter class ? Wouldn't the following be easier and a lot cleaner ?
    I mainly did it to keep the InputControllerParameter class lightweight and more of a Value Object. I see your point, but when I step back and look at how it is used, there is usually only one (maybe two) $filter and $rule per parameter. I didn't want to create the overhead of a FilterChain for each parameter. What do others think?
    Quote Originally Posted by kyberfabrikken
    I also noticed that the filterRequest method of the class InputController modifies the original request. I don't think that's a good idea. Besides - the method-name is a bit deceptive. It should probably be named import or something similar ?
    You caught me! I thought someone might find that and very little slips by you.

    I'll update filterRequest() and make all the rules inherit the Rule class. If I get time I'll try to use kyberfabrikken's form code to extend the Input Controller as a Form Controller. One request for a Form Controller: Does anyone have a clean HTML generation class to use to generate form fields (expecially <select>).
    Christopher

  16. #16
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by arborint
    How to we add the state logic and possibly dispatch to the Input Controller? I am beginning to think that plug-in state machines (similar in concept/goals the plug-in Mappers in the Front Controller) is the way to go. That decouples the logic of the page moving it out of the housekeeping and structure code. The goal is that you can write a Controller with any behavior by changing just the state machine with the goal of not having the maximum amount of code outside the state machine. We could supply standard single form and wizard (multi-form sequence) state machines (and the requsite RoR emulator ).
    That quote had me tinkering for a while, and here is what I came up with;

    Basically, filters are rather trivial so let's forget about them and focus on rules and state.
    I figured that the pivot of the ApplicationController is to maintain state. Different states would result in different Handlers. This is in contrast to the FrontController which doesn't rely on state to choose a handler, but rather on the Request. Besides this, the ApplicationController would also need to be able to change state. And the need for changing state could be described through rules.

    So, the ApplicationController would have an array of Validators. When the ApplicationController is executed, it would run through the array and execute the Validators one by one until a Validator fails, or the array is empty. Each time a validator succeeds, the state is updated to reflect the new level.
    This is quite flexible in that allows for any number of states (multiform wizards for example).

    Of course I couldn't resist the urge to actually implement it, so :
    PHP Code:
    /**
      * @implements IHandler
      */
    class ApplicationController
    {
        var 
    $state 'init';
        var 
    $params;
        var 
    $filter;
        var 
    $validators = Array();

        function 
    ApplicationController() {
            
    $this->params =& new DataSpace();
            
    $this->filter =& new FilterChain();
        }

        function 
    addState($name, &$validator) {
            
    $this->validators[$name] =& $validator;
        }

        
    /**
          * @returns   void
          */
        
    function execute(&$request, &$response) {
            if (
    $request->method == 'POST') {
                
    $this->params->import($this->filter->process($request));
                
    $this->state 'submit';
            }

            foreach (
    array_keys($this->validators) as $state) {
                if (
    $this->validators[$state]->validate($this->params)) {
                    
    $this->state $state;
                } else {
                    break;
                }
            }

            
    $handler =& $this->getHandler($this->state);
            
    $handler->execute($this->params$response);
        }

        function & 
    getHandler($state) {
            
    trigger_error("abstract method");
        }
    // end class ApplicationController 
    PHP Code:
    class MyFormController extends ApplicationController
    {
        function 
    MyFormController() {
            
    parent::ApplicationController();
            
    $validator =& new Validator();
            
    $validator->addRule(new RequiredFieldRule("foo"));
            
    $this->addState('valid'$validator);
        }

        function & 
    getHandler($state) {
            switch (
    $state) {
                case 
    'init' : return new ServerPage("forminit");
                case 
    'submit' : return new ServerPage("forminvalid");
                case 
    'valid' : return new ServerPage("formdone");
                default :
                    
    trigger_error("Unknown state '$state'");
            }
        }

    // end class MyFormController 

  17. #17
    SitePoint Guru
    Join Date
    May 2005
    Location
    Finland
    Posts
    608
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    here is what I came up with
    Interesting. I had to think a while to understand how that relates to actual actions, but that could definitely work. So each page set (like 'news') has its own ApplicationController that's set up with the relevant states and the capability to dispatch to an action according to input parameters. That way no single action needs to look after validation, and by proper design new types of ACs (thinking RoR here) will be easy to derive.

    Your code needs to be refined but it's a good start. How do others like it?

    An important design matter: how would composite views be done with an AC like this?
    Last edited by Ezku; Jul 9, 2005 at 11:05.

  18. #18
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Ezku
    An important design matter: how would composite views be done with an AC like this?
    I don't think that rendering of composite views has much to do with the ApplicationController - We better leave that for later.

  19. #19
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    That quote had me tinkering for a while, and here is what I came up with;
    It's good to see some code, but one thing isn't clear to me; what exactly are the ServerPages that are being called at the end? Has somebody implemented that already, or is it still hypothetical?

  20. #20
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by 33degrees
    It's good to see some code, but one thing isn't clear to me; what exactly are the ServerPages that are being called at the end? Has somebody implemented that already, or is it still hypothetical?
    The handler is created in a hook method in the extending class (MyFormController) so you could return anything which implements the IHandler interface. I just picked ServerPage in the example above.

    Quote Originally Posted by Dr Livingston
    I think Kyber's ServerPages are your common garden Page Controllers
    Yes, pretty much.
    The ServerPage is implemented in the FrontController code (here). It probably should be put in a file for itself, rather than be stuck in with ServerPageMapper.

  21. #21
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    That quote had me tinkering for a while, and here is what I came up with;

    Basically, filters are rather trivial so let's forget about them and focus on rules and state.
    I figured that the pivot of the ApplicationController is to maintain state. Different states would result in different Handlers. This is in contrast to the FrontController which doesn't rely on state to choose a handler, but rather on the Request. Besides this, the ApplicationController would also need to be able to change state. And the need for changing state could be described through rules.

    So, the ApplicationController would have an array of Validators. When the ApplicationController is executed, it would run through the array and execute the Validators one by one until a Validator fails, or the array is empty. Each time a validator succeeds, the state is updated to reflect the new level.
    This is quite flexible in that allows for any number of states (multiform wizards for example).
    I think you are definitely heading in the right direction and your code is giving me more ideas about what this thing might be. I think it might be an inversion of the code you implemented though so I need to experiment. The thing I am groping toward is the ability to trigger an event on a pre-registered condition or trigger an event directly.

    Take the Form Controller example:

    'submit'?
    • | -> no -> load values and display
      |
      | -> yes -> are all form values valid?
      • | -> no -> display with error messages
        |
        | -> yes -> save values and forward

    There is a cascade here, but how do we register events to manage that? Are the submit yes/no events the ones triggered by conditions and then the "yes" handler then triggers redisplay or forward events based on the form->isValid() ?
    Christopher

  22. #22
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by arborint
    The thing I am groping toward is the ability to trigger an event on a pre-registered condition or trigger an event directly.
    (...)
    There is a cascade here, but how do we register events to manage that? Are the submit yes/no events the ones triggered by conditions and then the "yes" handler then triggers redisplay or forward events based on the form->isValid() ?
    It seems that the route is determined by conditions. Each condition may lead to a new condition or to a final Handler. So how about this :
    PHP Code:
    /**
      * @implements IHandler
      */
    class ApplicationController
    {
        var 
    $valid;
        var 
    $fail;

        var 
    $rules = Array();
        var 
    $filter;
        var 
    $method;

        function 
    ApplicationController(&$valid, &$fail$method REQUEST_METHOD_GET) {
            
    $this->valid =& $valid;
            
    $this->fail =& $fail;
            
    $this->method $method;
            
    $this->filter =& new FilterChain();
        }

        
    /**
          * @returns   void
          */
        
    function execute(&$request, &$response) {
            
    $request =& $this->filter->process($request);
            
    $logger =& new Logger();
            if (
    $this->validate($request$logger)) {
                
    $this->valid->execute($request$response);
            } else {
                
    $request->set('errors'$logger->getMessages());
                
    $this->fail->execute($request$response);
            }
        }

        function 
    validate(&$request, &$errorLogger) {
            if (
    $this->method != $request->method) {
                return 
    FALSE;
            }
            
    $valid TRUE;
            for (
    $i=0$l=count($this->rules); $i $l; ++$i) {
                
    $valid $this->rules[$i]->validate($request$errorLogger) && $valid;
            }
            return 
    $valid;
        }

        function 
    addRule(&$rule) {
            
    $this->rules[] =& $rule;
        }
    // end class ApplicationController 
    PHP Code:
    class MyForm extends ApplicationController
    {
        function 
    MyForm() {
            
    $submitHandler =& new ApplicationController(new ServerPage("page/formdone.php"), new ServerPage("page/forminvalid.php"), REQUEST_METHOD_POST);
            
    $submitHandler->addRule(new Rule_Required("foo"));
            
    $submitHandler->addRule(new Rule_Email("foo"));
            
    parent::ApplicationController($submitHandler, new ServerPage("page/forminit.php"), REQUEST_METHOD_POST);
        }
    // end class MyForm 

  23. #23
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Very briefly before I go,

    What do you think about this ?
    I think the idea of using a Logger is an excellent approach. Will try to look at your scripts before the weekend though

  24. #24
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Really good post there arborint - it made a few pieces come together for me.

    Quote Originally Posted by arborint
    I don't know why you'd need a Factory when 99% of the time there will just be one form.
    The thought was that the factory would load a different form from a config-file, that the programmer could supply. I probably didn't make that very clear though.

    Quote Originally Posted by arborint
    I am not a big fan of Loggers because they are just fancy echo() statements and with unit tests they are not really needed.
    What do you mean by not needed ? Anyway ... I kind of like the logger-class. One could for example use a Logger, that logs to $_SESSION, so that the messages were available at next request.
    What I don't like on the other hand is when a method "returns" data by setting a property. Like how the rules return their errormessages in the overunner-code.

    Quote Originally Posted by arborint
    But what you really have is a Context object.
    What do you mean by context object ?

    Quote Originally Posted by arborint
    If we extend the InputController class to create a FormController class it the same as your "FormDescriptor" and if we extend the InputController class to create a FormControllerParameter class it the same as your "FieldDescriptor".
    Right. Let's do that then.

    Quote Originally Posted by arborint
    I am beginning to think that plug-in state machines (similar in concept/goals the plug-in Mappers in the Front Controller) is the way to go.
    That sounds very appealing.

    Off Topic:

    Whichever way it turns out, I must insist though to keep the interface IRule for obvious reasons.

  25. #25
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Ezku
    Yeah, that had me puzzled for a while as well. The fact is it's just an object encapsulating an array.
    Thats what I thought too.

    Quote Originally Posted by arborint
    Funny, I thought you would like the Datasource class as it is really the base class for the Request class and any other class with the main interface of get($name) and set($name, $value) methods.
    In that case it begins to make a bit sense. I just couldn't see Request inheriting from DataSource anywhere. I would prefer calling it DataSpace rather than DataSource btw. since source implies that it's read-only.

    Quote Originally Posted by arborint
    I mainly did it to keep the InputControllerParameter class lightweight and more of a Value Object. I see your point, but when I step back and look at how it is used, there is usually only one (maybe two) $filter and $rule per parameter. I didn't want to create the overhead of a FilterChain for each parameter.
    Quote Originally Posted by overunner
    Anyhow, having a FilterChain/Validator for each parameter is probably overkill in most cases, but it can be (really) important sometimes. I think the framework should be capable of having multiple rules/filters applied to a single parameter. We'll introduce a little overhead, but flexibility in this case is more important.
    I see. Another option would be to put the logic of FilterChain & Validator directly in the InputController class. It's just a forward loop anyway.

    Quote Originally Posted by Ezku
    why would one want the InputControllerParameter to keep track of its filters and rules if it's basically the InputController's job, and they [filters & rules] should be able to access all data anyway (in order to have combined requirements)?
    That's a valid point. We might want to put the rules in the InputController rather than tie them to a parameter.
    If we do that it seems like the InputControllerParameter is just a valueobject, and as such could be disposed of.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •