SitePoint Sponsor

User Tag List

Page 3 of 16 FirstFirst 123456713 ... LastLast
Results 51 to 75 of 397
  1. #51
    SitePoint Addict
    Join Date
    Jan 2005
    Location
    Ireland
    Posts
    349
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Here is good article which fits very well into this thread. It was written by Harry Fuecks, which many from this forums know.

    http://www.phppatterns.com/index.php...leview/81/1/1/

  2. #52
    SitePoint Wizard DougBTX's Avatar
    Join Date
    Nov 2001
    Location
    Bath, UK
    Posts
    2,498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston
    WRT?? Don't know what that abbrev. is for, but to answer your other question I can't share any script.
    I meant "with respect to", sorry for confusion

    I was really looking for a KISS CoR, as (I don't think) I've used one before. I see no reason (in principle) why OO can't follow, KISS. If KISS CoR doesn't exist, I guess I won't get to see an example

    Edit: I'm also a little fuzzy on how CoR (from what I understand of it) fits in here. Why do you want a chain? Aren't you looking for something which branches instead?

    Douglas
    Hello World

  3. #53
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston
    Not now, I just pass around the Request object, which encapsulates both Request and Response now.
    I wouldn't recommend that. It's a pretty basic OOP idea that classes should have clearly defined responsibilities. A response doesn't have a lot in common with a request.

    Request objects tend to get passed around almost everywhere and thus can appear as a convenient location to store all kinds of widely-used objects or parameters. A temptation to be resisted.

    Quote Originally Posted by kyber
    I fail to see the real need for a Request-object. I really don't see the harm done in using the superglobals directly.
    For one thing it's bad layering. GPC input only exists with a particular kind of presentation layer - http. If domain objects are accessing GPC directly presentation is bleeding into the domain.

    There's also the question of input validation. I'm not suggesting for one moment that you're not doing any validation, but the advantage of a request object is that you can provide named accessors to guaranteed, safe values. They'll either be validated and passed on or set to null if they fail - raw GPC input never gets anywhere near the app.

    With a single location for all input validation it's likely to be carried out more carefully and methodically than if it were scattered throughout the app. A request object can create a clear Cartesian boundary between the internal application and the outside world - which as you say also makes it easier to swap out a CLI presentation layer.

  4. #54
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    "with respect to"
    Thanks for making it clearer, though I'll more likely forget about the meaning tomorrow

    One advantage (of many) of using a Chain of Responsibility (over basic switch) is that the CoR can be configurable. I like this approach

    By branching, you mean a hierarchacal structure, again this is where the Composite comes in. At the moment, the Composite for me holds what Controllers (proberly a bad description, as they're not actually controllers) to use for each node, and I use a CoR to sift through each handler, using the Request, to select which action to take.

    The action selects which template fragment to use, and returns it to the composite along with any model data. A Visitor puts the model data to the template, and then the template is parsed into the parent composites template fragment... and so on until you reach the root node

  5. #55
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    convenient location to store all kinds of widely-used objects or parameters. A temptation to be resisted.
    Correct, though my Request object is read only all the way McGruff The Request class (which does the encapsulation) is merely a container I suppose, but with additional responsibilities such as verifying that there is an ID parameter for example?

    From one application to another, the terminology of an ID can change, thus I don't have it (the responsibility) in the HttpRequest class. It may appear to be madness, but I like the approach and the responsibilities are clearly defined.

    There's also the question of input validation. I'm not suggesting for one moment that you're not doing any validation, but the advantage of a request object is that you can provide named accessors to guaranteed, safe values. They'll either be validated and passed on or set to null if they fail - raw GPC input never gets anywhere near the app.

    With a single location for all input validation it's likely to be carried out more carefully and methodically than if it were scattered throughout the app. A request object can create a clear Cartesian boundary between the internal application and the outside world - which as you say also makes it easier to swap out a CLI presentation layer.
    For once, I can agree with you on this.

  6. #56
    SitePoint Wizard DougBTX's Avatar
    Join Date
    Nov 2001
    Location
    Bath, UK
    Posts
    2,498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston
    One advantage (of many) of using a Chain of Responsibility (over basic switch) is that the CoR can be configurable. I like this approach
    This is the bit I don't understand: if the chain changes depending on the request, isn't the code that creates the chain the code which replaces the switch? OR, do you just put all your handlers into the chain, then run your action/command/request and see what happens? Won't this lead to loading up the whole app when only part of it is needed for any given request?

    When I say branching, I mean rendering, say, a news page instead of a contact page. Each will require different data (one a list of articles, the other possibly static html) so needs to be handled differently. I don't mean a composite - that would mean rending the news and contact pages at the same time, which might be a little confusing to the visitor

    Douglas

    Edit: can't resist a random Ruby example: the Doctor says "though my Request object is read only all the way McGruff", Ruby says "my_request_object.freeze"!
    Hello World

  7. #57
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    that would mean rending the news and contact pages at the same time, which might be a little confusing to the visitor
    A pun? Funny...

    By configurable, I mean that you'd have just a handler class defined by a tight interface. This handler would take a reference (an XPATH reference for example), prior to this (newly created) handler being attached to a chain of handlers.

    So... You parse an XML file (for example), lift each node (via XPATH for example), and create a new instance of the handler class. This object is attached to the chain of handlers (basically this is an array, encapsulated within another class).

    You pass in the Request to the (lets call the class ActionChainController) class which cycles through the chain of handlers, passing in the Request. So, it's the handler class it's self, which looks at the XPATH reference, to see if there is a match against the Request passed into it (the handler class).

    If there is a match, execute a given action, which is found btw, by querying the XPATH reference (the action file, and the class name etc, if a child node of the parent node which you queryied originally you see ), and you execute that given action.

    If no match found, you move onto the next handler in the chain, defaulting at the end. Hope this helps to clear things up.

  8. #58
    SitePoint Wizard DougBTX's Avatar
    Join Date
    Nov 2001
    Location
    Bath, UK
    Posts
    2,498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston
    A pun? Funny...
    Heh, didn't notice that one

    Thanks for describing your setup, its interesting how people solve these problems. Now I see why you wouldn't consider it "light weight" or KISS. I'm guessing too many Java books

    Cheers,
    Douglas
    Hello World

  9. #59
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'll post some script later this week once I get some more time, so you can see how I do things in regards to the configurable Chain of Responsibility.

    I had this script developed prior to a written contract, so it's upto myself what I can do with it

  10. #60
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This is a really excellent discussion. In response to Ryan Wray, I think I think you ask the right question "Are we answering his question correctly:" and I think you also recognize that cadmiumgreen was implementing a common pattern (Front Controller) without knowing it.

    My point for pushing the discussion a little was that I believe that if there was a simple, clean, understandable "skeleton" for the Front Controller and Application Controller patterns it would be of great benefit to users like cadmiumgreen. This same question has come up hundreds of times in PHP forums and it gets answered with lots of words, but seldom with clean example code.

    As for the Request object, I undersand kyberfabrikken resistance to a Request object. But I think a Request object adds a couple of best practices that make it a good addition for the purpose of this skeleton:

    1. A Request class implements escaping of all request vars transparently. I think this is such an important feature that it is worth having a Request object just for this reason.

    2. A Request class encapulates the request which provides a solid basis for adding Filtering and Validation classes.

    3. In conjuction with a Response class it abstracts the entire Request enabling more features to be added without breaking things. For example, I added PATH_INFO to the request to show that your Front Controller could dispatch on an "action" param, or on "PATH_INFO" using the same interface.

    I like the direction that kyberfabrikken is going. I would like to see the Chain of Responsibility implemented so that you could add an "action" dispatcher and default and error dispatchers to the chain and run it. Support for and addChild() method would allow for this.
    Christopher

  11. #61
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Support for and addChild() method would allow for this.
    Attach() would be a better definition, as addChild suggests that there may be a parent, which is not always the case? But that's just me being fussy huh

  12. #62
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Either addChild() or Attach() is fine. I picked addChild() because if someone extended the basic skeleton to support parent/child controllers it would make sense. But attach() works for me to. Maybe you could take a pass at kyberfabrikken code to add the Chain of Responsibility.
    Christopher

  13. #63
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    A Request class implements escaping of all request vars transparently. I think this is such an important feature that it is worth having a Request object just for this reason.
    I disagree. Escaping of quotes in incoming values is necessary to insert them into an SQL statement. Coincidentally, MySQL (and others, not sure which ones though) support quotes that are escaped with slashes, but the SQL standard prescribes that slashes are doubled. In principle, the method by which quotes are escaped is database-dependent. Based on that argument it is my opinion that the code that carries out 'escaping' of values should reside in the database (abstraction) layer.

    But that is nitpicking of course. I'll try to contribute something useful, an answer to cadmiumgreen's questions:

    how common is it to use a 'skeleton' script?
    If you're referring to the switch statement code in your post, Very common I believe. Most 'simple' scripts I have looked at use a structure similar to that. Whether it is good practice is not really relevant. I can say that I once started out exactly like that.

    When your website grows, you will find that the switch statement becomes very large and also possibly very complicated (nested switch, plus if/else statements). You'll find that you repeat a lot of the same code: case 'something': include 'something': case 'somethingelse'. A simple solution for this is to use an associative array to lookup the file belonging to the value of the content parameter. Think of it like a dictionary that translates the content parameter to a file to include.

    Note to myself and other people: when you throw around design patterns, think of the problem that these patterns are meant to solve and whether that problem is an actual issue.

    I would like to know the general practice that most PHP developers use when designing a website that generally has the same menus, but the content changes.
    Your code example is, I believe, general practice. There is nothing wrong with it as far as I can see.

    For all websites out there, how are these HTML/PHP scripts usually written?
    With a text editor

    Would PEAR help at all?
    I don't see how.
    Last edited by Captain Proton; Jun 11, 2005 at 14:31. Reason: typo

  14. #64
    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 like the direction that kyberfabrikken is going. I would like to see the Chain of Responsibility implemented so that you could add an "action" dispatcher and default and error dispatchers to the chain and run it. Support for and addChild() method would allow for this.
    Well, there isn't much to it, but here goes :
    PHP Code:
    class RequestMapper_DefaultMapper extends RequestMapper 
    {
        var 
    $default=NULL;
        function 
    RequestMapper_DefaultMapper($default=NULL) {
            
    $this->default $default;
        }
        function & 
    mapRequest() {
            if (!
    is_null($this->default)) {
                return new 
    Dispatcher_ServerPage($this->default);
            }
            return 
    NULL;
        }
    }

    class 
    RequestMapper_ServerPageMapper extends RequestMapper 

        function & 
    mapRequest() { 
            if (isset(
    $_GET['page'])) {
                return new 
    Dispatcher_ServerPage($_GET['page']); 
            }
            return 
    NULL;
        } 
    }

    class 
    RequestMapper_ActionMapper extends RequestMapper 

        function & 
    mapRequest() { 
            if (isset(
    $_GET['action'])) {
                if (!
    preg_match("/^(\w*)$/"$_GET['action'])) {
                    
    trigger_error("Illegal Kontrol_Action [".$_GET['action']."]"E_USER_WARNING);
                    return 
    NULL;
                }
                return 
    Action::CreateAction($_GET['action']);
            }
            return 
    NULL;
        } 
    }

    class 
    RequestMapper_MapperChain extends RequestMapper
    {
        var 
    $_requestMappers=Array();
        function & 
    mapRequest() { 
            for (
    $i=0,$l=count($this->_requestMappers); $i $l; ++$i) {
                
    $dispatcher =& $this->_requestMappers[$i]->mapRequest();
                if (
    is_a($dispatcher'Dispatcher')) {
                    return 
    $dispatcher;
                }
            }
            return 
    NULL;
        }
        function 
    addMapper(&$requestMapper) {
            
    $this->_requestMappers[] =& $requestMapper;
        }

    PHP Code:
    $mapper =& RequestMapper_MapperChain();
    $mapper->addMapper(new RequestMapper_ActionMapper());
    $mapper->addMapper(new RequestMapper_ServerPageMapper());
    $mapper->addMapper(new RequestMapper_DefaultMapper('default.php'));
    $frontController =& new InputController($mapper); 
    $frontController->execute(); 
    Note that the performance could be improved by adding handles instead of actual objects to the chain.

  15. #65
    SitePoint Wizard DougBTX's Avatar
    Join Date
    Nov 2001
    Location
    Bath, UK
    Posts
    2,498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Captain Proton
    I disagree. Escaping of quotes in incoming values is necessary to insert them into an SQL statement.
    It is actually the opposite! PHP, with some php.ini settings, applies addslashes automagically. Which, if you want clean inputs, you have to remove before you apply a db specific escaping.

    Douglas
    Hello World

  16. #66
    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)
    A Request class implements escaping of all request vars transparently. I think this is such an important feature that it is worth having a Request object just for this reason.
    Quote Originally Posted by Captain Proton
    I disagree. Escaping of quotes in incoming values is necessary to insert them into an SQL statement.
    Actually I think he meant the opposite. That the Request-class could counteract the non-sense of magic-quotes.

    Edit:

    I didn't see the above post before hitting send. Seems I was right on that


    With a single location for all input validation it's likely to be carried out more carefully and methodically than if it were scattered throughout the app.
    Well ... sometimes you need access to the model-layer to complete the validation. I put the validation in a seperate class in the controller domain (FormAction ... extended from Action), which is closely related to a dedicated FormModel, that describes the validation-rules. And there's a FormView widget too ofcourse. Quite similar to PEAR's QuickForm, except I have seperate classes for M, V and C.

  17. #67
    SitePoint Zealot Overunner's Avatar
    Join Date
    Mar 2004
    Location
    Sweden
    Posts
    180
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi!

    One quick question in the middle of this very interesting discussion: What is the purpose of the Response-object?

  18. #68
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I use it to set headers, and cause a redirect

  19. #69
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Here is a rearrangement of kyberfabrikken's code. It reduces things a little and name the Front Controller (which kyberfabrikken will not like). I also added the Request class (which kyberfabrikken will also not like) so that the code works with both GET and POST requests.

    I did what I could in a quick pass. This code should run without errors. It could certainly use more clean-up. It does not handle errors well. And, I agree that using a Handle class would improve things. Also I was not sure what direction kyberfabrikken wanted to go on the Action class so that part does not work.
    PHP Code:
    class Request {
        var 
    $_request = array();
            
        function 
    Request() {
            if (!
    strcasecmp($_SERVER['REQUEST_METHOD'], 'POST')) {
                
    $this->_request =& $_POST;
            } else {
                
    $this->_request =& $_GET;
            }
            
    $this->_request['PATH_INFO'] = $_SERVER['PATH_INFO'];
            if (! 
    get_magic_quotes_gpc()) {
                 
    $this->removeSlashes($this->_request);
            }
        }
        
        function 
    removeSlashes(&$str) {
            if (
    is_array($str)) {
                foreach (
    $str as $key => $val) {
                    if (
    is_array($val)) {
                        
    $this->removeSlashes($val);
                    } else {
                        
    $array[$key] = stripslashes($val);
                    }
               }
            } else {
                
    $str stripslashes($str);
            }
        }
        
        function 
    get($name) {
            return 
    $this->_request[$name];
        }
            
        function 
    set($name$value) {
            if (
    $name) {
                
    $this->_request[$name] = $value;
            }
        }
        


    class 
    Dispatcher_ServerPage
    {
        var 
    $dirName './';    // 'ServerPages/';
        
    var $fileName;

        function 
    Dispatcher_ServerPage($fileName) {
            
    $this->fileName $fileName;
        }
        function 
    execute() {
            @include(
    $this->dirName $this->fileName);
        }
    }

    class 
    RequestMapper_DefaultMapper
    {
        var 
    $default=NULL;
        function 
    RequestMapper_DefaultMapper($default=NULL) {
            
    $this->default $default;
        }
        function & 
    mapRequest(&$request) {
            if (!
    is_null($this->default)) {
                return new 
    Dispatcher_ServerPage($this->default);
            }
            return 
    NULL;
        }
    }

    class 
    RequestMapper_ServerPageMapper
    {
        function & 
    mapRequest(&$request) {
            
    $page $request->get('page');
            if (
    $page != '') {
                return new 
    Dispatcher_ServerPage($page);
            }
            return 
    NULL;
        }
    }

    class 
    RequestMapper_ActionMapper
    {
        function & 
    mapRequest(&$request) {
            
    $action $request->get('action');
            if (
    $action != '') {
                if (!
    preg_match("/^(\w*)$/"$action)) {
                    
    trigger_error("Illegal Action [".$action."]"E_USER_WARNING);
                    return 
    NULL;
                }
                return 
    Action::CreateAction($action);
            }
            return 
    NULL;
        }
    }

    class 
    FrontController
    {
        var 
    $_requestMappers = array();

        function 
    addMapper(&$requestMapper) {
            
    $this->_requestMappers[] =& $requestMapper;
        }

        function 
    execute(&$request) {
            
    $n count($this->_requestMappers);
            for (
    $i=0$i<$n; ++$i) {
                
    $dispatcher =& $this->_requestMappers[$i]->mapRequest($request);
                if (
    is_a($dispatcher'Dispatcher_ServerPage')) {
                    
    $dispatcher->execute($request);
                    break;
                }
            }
            return 
    NULL;
        }
    }


    $frontController =& new FrontController();
    $frontController->addMapper(new RequestMapper_ActionMapper());
    $frontController->addMapper(new RequestMapper_ServerPageMapper());
    $frontController->addMapper(new RequestMapper_DefaultMapper('default.php'));

    $frontController->execute(new Request()); 
    You need to create a default.php page and a another page (e.g. test.php) to run the above code.
    Christopher

  20. #70
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thought,

    so that the code works with both GET and POST requests.
    I don't make the destinction of where the request comes from, either $_GET or $_POST, I use $_REQUEST instead. This is within the HttpRequest class, and I leave it to the Request class (encapsulates HttpRequest and HttpResponse) to make the destinction if and when it's required.

    Just thought I'd add that to the discussion

  21. #71
    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
    so that the code works with both GET and POST requests
    $_REQUEST ?
    But anyway ... sometimes you actually might want to distinguish between GET and POST within the same request.

    Quote Originally Posted by arborint
    It reduces things a little and name the Front Controller
    I feel inclined to point out why that makes me sour. I understand the whole solution as eing the frontcontroller, thus having class by the same name is misguiding. That's the reason for calling it InputController. But actually, we could do completely without that class, since all it does is two lines of code - it gets the dispatcher from the requestmapper, and then it executes the dispatcher. We could just put thoose two lines of code directly in the bootstrap file. If that would help to clarify what the FrontController is, I'm willing to go with it.

    Quote Originally Posted by arborint
    I also added the Request class
    If we should have a Request class, I must insist to also have a Response-class. I don't like Dr Livingston's inclination to merge the two, however tempting it may be. McGruff already explained why, and I agree on that.

    Quote Originally Posted by Dr Livingston
    I use it to set headers, and cause a redirect
    So do I.

  22. #72
    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
    Fowler uses the term Input Controller to describe a controller that dispatches based on input from the request. My understanding is that both the Front Controller and Application Controller are Input Controllers (as is the Page Controller) because they provide their controller functionality based (usually) on the request. In that sense all of these controllers should extend a base Input Controller which dispatches based on an input from the request.
    I think you're right. I used InputController because I can't figure out exactly where the difference is between FrontController and ApplicationController, so I don't really bother to distinguish. To me they're just InputControllers. Perhaps they are even just Controllers ? It's about the context anyway, since you could easily have two bootstrap-scripts, each looking like the above code. Would they be FrontControllers ?

    About the Request and Response objects ; arborint's challenge was to make the minimal FrontController. I think we can probably agree on how to implement things, but we will differ on which elements to include. The discussion about Request and Response isn't as much if they are appropriate (I agree that Request has uses, even though it may not seem that way from my posts). The question is if it's needed in very simple applications ? I think not, and you would probably agree?
    Some of the reasons why "Frameworks like Mojavi, WACT, etc. have controllers crammed full of code to support the specifics of the framework." (quote:arborint) is that they are prepared to handle very big applications, so they bring in the big guns. I think such things should be optional if we are to stay on the course. The same thing goes for Handle (which I earlier suggested used with the RequestMapper). It's really useful, and I wouldn't leave home without it, but for a minimal setup it's overhead, since it essentially trades simplicity for efficiency.

    Quote Originally Posted by arborint
    Also I was not sure what direction kyberfabrikken wanted to go on the Action class so that part does not work.
    The Action was meant as a object-oriented dispatcher object, implementing a Command-pattern. It would carriy out updates, and redirect to a view (ServerPage). It wouldn't produce output.
    PHP Code:
    class RequestMapper_ActionMapper extends RequestMapper
    {
        var 
    $factory=NULL;
        function 
    RequestMapper_ActionMapper(&$factory) {
            
    $this->factory =& $factory;
        }

        function & 
    mapRequest() {
            if (isset(
    $_GET['action'])) {
                if (!
    preg_match("/^(\w*)$/"$_GET['action'])) {
                    
    trigger_error("Illegal Kontrol_Action [".$_GET['action']."]"E_USER_WARNING);
                    return 
    NULL;
                }
                return 
    $this->factory->createAction($_GET['action']);
            }
            return 
    NULL;
        }
    }

    class 
    ActionFactory {
        function & 
    createAction($actionName) {
            
    $className 'Action_'.$actionName;
            if (!
    class_exists($className)) {
                require_once(
    'Action/'.$actionName.'.php');
            }
            return new 
    $className;
        }
    }
    /**
      * @abstract
      */
    class Action extends Dispatcher
    {


  23. #73
    SitePoint Wizard DougBTX's Avatar
    Join Date
    Nov 2001
    Location
    Bath, UK
    Posts
    2,498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'm seeling lots of code that extends RequestMapper, but where (and what and why) is this RequestMapper?

    Also, what is the distinction between a page and an action? It seems arbitary.

    Douglas
    Hello World

  24. #74
    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 DougBTX
    I'm seeing lots of code that extends RequestMapper, but where (and what and why) is this RequestMapper?
    It's just an abstract class (or interface if you use php5). See post #35

    Quote Originally Posted by DougBTX
    Also, what is the distinction between a page and an action? It seems arbitary.
    As you see, I use ServerPages (aka DispatcherView) as the default view. So that would be your 'page'. Action is a Command - it performs some sort of update to the Model and redirects to a view (ServerPage).
    The Action would most likely deal with POST requests, while the ServerPage's would result from a GET request. This seperation is more about REST than MVC, but it's kind of the same thing.
    You might prefer to use a TemplateView rather than DispatcherView, which is fine. In that case you'll need a View which looks a lot like the Action :
    PHP Code:
    class RequestMapper_ViewMapper extends RequestMapper
    {
        var 
    $factory=NULL;
        function 
    RequestMapper_ViewMapper(&$factory) {
            
    $this->factory =& $factory;
        }

        function & 
    mapRequest() {
            if (isset(
    $_GET['view'])) {
                if (!
    preg_match("/^(\w*)$/"$_GET['view'])) {
                    
    trigger_error("Illegal View [".$_GET['view']."]"E_USER_WARNING);
                    return 
    NULL;
                }
                return 
    $this->factory->createView($_GET['view']);
            }
            return 
    NULL;
        }
    }

    class 
    ViewFactory {
        function & 
    createView($viewName) {
            
    $className 'View_'.$viewName;
            if (!
    class_exists($className)) {
                require_once(
    'View/'.$viewName.'.php');
            }
            return new 
    $className;
        }
    }
    /**
      * @abstract
      */
    class View extends Dispatcher
    {

    View/Test.php
    PHP Code:
    class View_Test extends View
    {
        function 
    execute() {
            
    $t =& new Template('templates/test.tpl.html');
            
    $t->set('title''Test');
            
    $t->set('body''Hello World');
            echo 
    $t->render();
        }

    As you can see, it's copy&paste from Action, but the distinction is important, so they get seperate classes. They could probably share a common RequestMapper, since the factories are seperated out anyway. Any candidates for a name ?

  25. #75
    Employed Again Viflux's Avatar
    Join Date
    May 2003
    Location
    London, On.
    Posts
    1,127
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Curious bystander...

    Is the encapsulation of HttpRequest and HttpResponse an attempt at duplicating how you would handle the situation with a Java Servlet?


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
  •