SitePoint Sponsor

User Tag List

Page 8 of 16 FirstFirst ... 456789101112 ... LastLast
Results 176 to 200 of 384
  1. #176
    SitePoint Zealot
    Join Date
    Jul 2005
    Posts
    194
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I think the ideas, is nice but what happens when you want to have a wizard-like form? Because then you would need a FormController (= Application controlller). But would this be initaited in the RequestMapper os would it be taken over?

    I suppose you would need create the FormController in the class who implements IRequestMapper? Because the code doeS:

    PHP Code:
        // execute from the WebApplication::Execute() // triggered by the framework bootstrap file as:
        //
        // $applicationInstance = ApplicationController::getInstance();
        // $applicationInstance->execute();
        
    public function execute() {
             
    $frontController = new FrontController( new RequestMapper_ContentPage() );
            
    $frontController->execute(  new Request(), $response = new Response() );
            try {
                
    $response->out();
            } catch ( 
    Exception $e ) {
                echo 
    $e;
            }
        } 

  2. #177
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    As wdeboer and timw have mentioned, headers are a bit tricky. I don't really have an answer to this, but having some pseudo-headers as timw suggested may be the best solution. The response would then have to translate theese into actual headers before rendering.
    Headers aren't tricky at all, here's what a response object could look like.

    PHP Code:
    class Response {
        var 
    $DEFAULT_HEADERS = array('Cache-Control' => 'no-cache');
        
        var 
    $body;
        var 
    $headers;
            
        function 
    Response() {
            
    $this->body '';
            
    $this->headers $this->DEFAULT_HEADERS;
        }
        
        function 
    add_header($header$value) {
            
    $this->headers[$header] = $value;
        }
        
        function 
    redirect($to_url$permanently false) {
            
    $this->headers = array(
                
    'Status' => $permanently "301 Moved Permanently" "302 Found",
                
    'location' => $to_url
            
    );
            
            
    $this->body "<html><body>You are being <a href=\"$to_url\">redirected</a>.</body></html>";
        }

        function 
    out() {
            foreach (
    $this->headers as $header => $value) {
                
    header("$header$value");
            }
            
            if(
    $_SERVER['REQUEST_METHOD'] == 'HEAD') {
                return;
            } else {
                print 
    $this->body;
            }
        }
        


  3. #178
    SitePoint Zealot
    Join Date
    Jul 2005
    Posts
    194
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Looks nice, also a good way of redirecting.

  4. #179
    SitePoint Addict timvw's Avatar
    Join Date
    Jan 2005
    Location
    Belgium
    Posts
    354
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You've posted the proof that headers can be tricky

    For example, the code can't handle
    Cache-Control: no-store, no-cache, must-revalidate
    Cache-Control: post-check=0, pre-check=0

    That is why i choose $headers = array('name' => '...' , 'value' => '....') and used
    headers("{$header['name']}: {$header['value']}", true);

  5. #180
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by timvw
    You've posted the proof that headers can be tricky

    For example, the code can't handle
    Cache-Control: no-store, no-cache, must-revalidate
    Cache-Control: post-check=0, pre-check=0

    That is why i choose $headers = array('name' => '...' , 'value' => '....') and used
    headers("{$header['name']}: {$header['value']}", true);
    Why not just:
    Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0

    Is there a problem with doing that that I'm not aware of?

  6. #181
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    Composition of views would be done at the controller-level (in the MyAction class). Something akin to this :
    PHP Code:
    class MyOtherAction
    {
        function 
    execute(&$request, &$response) {
            
    $inner =& new MyAction();
            
    $buffer =& new Response();
            
    $inner->execute($request$buffer);

            
    $t =& new Template();
            
    $m =& new Model();
            
    $t->set("bar"$m->get("bar"));
            
    $t->set("inner"$buffer);
            
    $response->setContent($t->render());
        }

    I think your code shows why heirarchical views make sense. You have resorted to using building a heirarchy using Response objects when the Response is really a special case of a View (like the Request is a special case of a DataSource). Using either controllers or views that understood parent/child relationship would make this code much simpler.
    Christopher

  7. #182
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by timvw
    You've posted the proof that headers can be tricky

    For example, the code can't handle
    Cache-Control: no-store, no-cache, must-revalidate
    Cache-Control: post-check=0, pre-check=0

    That is why i choose $headers = array('name' => '...' , 'value' => '....') and used
    headers("{$header['name']}: {$header['value']}", true);
    This is not really a problem in the Front Controller "skeleton" code (I don't know how it works in kyber and ezku's current code). You can easily add headers in any Controller by simply doing:
    PHP Code:
    $response->setHeader('Cache-Control''no-store, no-cache, must-revalidate, post-check=0, pre-check=0'); 
    At least if should work that way. You could certainly make it more intellegent by extending the Response class and writing a more sophisticated setHeader() method. If you have recommendations for improvements please submit them.
    Christopher

  8. #183
    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 think your code shows why heirarchical views make sense. You have resorted to using building a heirarchy using Response objects when the Response is really a special case of a View (like the Request is a special case of a DataSource).
    It could certainly be made more elegant. Thoose three lines are something you would use a lot throughout the application, so they should probably be simplified somehow.
    I'm quite sure that it's a better design to compose controllers rater than views though. Since each view may use different models, they would need a controller to provide this. Besides - with the composition happening at controller-level, you may easily compose the final view of different view-types. You could for example mix different templating-engines with eachother.

    Quote Originally Posted by arborint
    Using either controllers or views that understood parent/child relationship would make this code much simpler.
    We could make an Action baseclass, and stuff a renderChild(&$child) method into it.

  9. #184
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    We could make an Action baseclass, and stuff a renderChild(&$child) method into it.
    You could but what happens when you need to render something differently? I have implemented a Visitor as my renderer, and it's this pattern that is ideal for the task at hand.

    One other thought that I have arrived at is an alternative to the Visitor, would be to Decorate a common renderer instead which would be a viable option, if your not too keen on using a Visitor?

    However I don't think a class method alone is upto the task, as you cannot apply an Interface to a class method it's self, though the class method could accept an Interface I suppose but I'm not at ease with that.

    Not exactly sure why, just a gut feeling I have?

  10. #185
    SitePoint Guru
    Join Date
    May 2005
    Location
    Finland
    Posts
    608
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    I'm quite sure that it's a better design to compose controllers rater than views though. Since each view may use different models, they would need a controller to provide this. Besides - with the composition happening at controller-level, you may easily compose the final view of different view-types. You could for example mix different templating-engines with eachother.
    I agree 100%.
    We could make an Action baseclass, and stuff a renderChild(&$child) method into it.
    Sounds too familiar to be true

    To lazy load as much as possible (= avoid rendering until $response->out()), I'd like having a CompositeView of some sort, under which Views would go; with a Template class this is easy as you just assign variables and then add another file to the render stack. Anyone following me?

  11. #186
    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 Dr Livingston
    I have implemented a Visitor as my renderer, and it's this pattern that is ideal for the task at hand.
    That sounds probable, could you be a bit more concrete ?

  12. #187
    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'd like having a CompositeView of some sort, under which Views would go; with a Template class this is easy as you just assign variables and then add another file to the render stack. Anyone following me?
    Well, yes and no. I don't think there is much to save that way, since the heavy lifting is mostly done in the controller anyway. There is no reason why you couldn't cache the output of a controller, though.

  13. #188
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    It could certainly be made more elegant. Thoose three lines are something you would use a lot throughout the application, so they should probably be simplified somehow.
    I'm quite sure that it's a better design to compose controllers rater than views though. Since each view may use different models, they would need a controller to provide this. Besides - with the composition happening at controller-level, you may easily compose the final view of different view-types. You could for example mix different templating-engines with eachother..
    You are correct about the heirarchy being controllers, not views. What I am looking for is something that easily handles doing the most common case where you pass a connection object to the model and the model to the view, then get the rendered output of the view. It has mapper and controller functions. Here is non-fuctioning concept code:
    PHP Code:
    class ControllerMVC {

    fuction HandlerMVC ($action, &$connection) {
        
    $model_path 'models/' $action 'Model.php';
        
    $model_class $action 'Model';
        
    $this->model =& new Handle($model_path$model_class);

        
    $view_path 'views/' $action 'View.php';
        
    $view_class $action 'View';
        
    $this->view =& new Handle($view_path$view_class);

    // this could be a gateway or mapper as well
        
    $this->connection =& $connection;
    }

    function 
    execute () {
        
    $view =& $this->view::resolve();
        
    $model =& $this->model::resolve();
        
    $model->setConnection($this->connection);
        return 
    $view->render($model);
    }


    Why it is more like a view is that it returns the rendered output rather than just appending it to the Response. We need some way to build the heirarchical connections up front and then let it all run assigning the output of childern to the right parts of the parent view.
    Christopher

  14. #189
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    We need some way to build the heirarchical connections up front and then let it all run assigning the output of childern to the right parts of the parent view.
    This is tricky, isn't it? Since I'm unable to post any of the script that I've developed at the moment, I'll try to tackle it from another angle?

    First of all, looking at the class above is like looking at a 3D object in a 2D world. Where it comes down to Composites, and hierarchacal structures (whilst rendering a web page) you do need to look at it from another perspective?

    You are talking multiple Views here, one per Controller? But why, when all the hierarchacal nodes are rendered in the same manner. You only need the one View...

    Secondly, I mentioned a Visitor before? The benifit of this is that any Composite node has access to it. This reduces duplication, and it reduces coupling. There are a number of other factors, but I'll not go into them (not related to this discussion, at this point in time, so why complicate matters?).

    So you could build the hierarchacal structure (the structure of your proposed web page) via script for example,

    PHP Code:
    $page = new Composite'page''' );
    $page -> attach( new Composite'searchbox''page' ) );
    $page -> attach( new Composite'menu''page' ) );
    $content = new Composite'content''page' );
    $breadcrumb = new Composite'breadcrumb''content' );
    $content -> attach$breadcrumb );
    $page -> attach$content );
    // ... etc 
    Now, the thoery of this untested concept is that the Composite it's self could act as the Controller as well btw yes? The Composite would resolve the pathnames required to fetch the files based on the name you pass into a new Composite. If on the otherhand, your not comfortable with this idea, you could pass in the Controller it's self instead?

    PHP Code:
    // ...
    $content = new Composite'content', new Controller() );
    // in this case, the Controller it's self would have the second parameter as I
    // used in the above example, accessable publically.
    // ... 
    I prefer the first method Just for the record, the first parameter passed into a new Composite, is the Composites own ID, and the second parameter, is the Composites, parent Composite.

    PHP Code:
    // ie for the second method
    $breadcrumb = new Composite'breadcrumb', new Controller() );
    $content -> attach$breadcrumb );
    // ...
    // ...
    class Composite {
    // ...
    public function attach$idIController $controller ) {
    $composite = new Composite$controller );
    $composite -> parent $controller -> getParent();
    $this -> children[$id] = $composite;
    }
    // ... 
    How is the Controller aware of a Request object you ask? It doesn't directly, though it knows of it via the Visitor... Remember, that each and every Composite visits the Visitor. Sneaky?

    So, where does that leave us? Now that you have the structure, you need a way to recurse over it. That is why you (really) need an ID and a PARENT. It just makes your life a whole lot easier.

    Anyways, I'm having to get some sleep now, but I'll leave this as it stands at the moment, and you all can think about this, and maybe it can be continued tomorrow?

    ...

  15. #190
    SitePoint Zealot
    Join Date
    Jul 2005
    Posts
    194
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi DrLivingstone, the idea you currently mentioned above, looks abit like my idea of a render tree. But I will think about it a bit more tomorrow

  16. #191
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Just for the record, the first parameter passed into a new Composite, is the Composites own ID, and the second parameter, is the Composites, parent Composite.
    In that same regards, you could just as well pass in an XML Dom Node instead, and have this Dom Node hold the configuration information about the Controller, and it's file paths, etc.

    That would then leave the Composite to fetch as and when required, the information via an XPath object. In this manner, it just makes it more flexible I suppose? At the moment, the script that I've developed, there is not that same flexibility, so this is proberly the direction that I'm heading towards anyway

    looks abit like my idea of a render tree.
    Interesting... Would you care to post some examples? I'll try to clean up things tomorrow and post something like the recursion part (should be easy enough since I could refactor the classes I already have I think).

  17. #192
    SitePoint Zealot
    Join Date
    Jul 2005
    Posts
    194
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Well, the code I use is as follows.

    PHP Code:
    $context Application->getApplicationContext();

    // Obtian the rootfolder for this user, the getRootFolderByUserId() will return a tree of a objects that are accesible by the user, meaning all the objects with
    // read/write rights assigned to it for this user.
    $rootObject rootObject::getRootFolderByUserId$context->getCurrentUser() );
    if ( !
    $rootObject instanceof IRootObject ) {
        throw new 
    IllegalNodeTypeException'The root folder should be of type systemfolder.' );
    }

    // After we obtain the rootfolder this user, we should use the getNodeByPath() method to get the node by path
    $rootNode $rootObject->getNodeByPath$context->request->get'REQUEST_URI' ) );

    if ( !
    $rootNode instanceof INode ) {
        throw new 
    IllegalNodeTypeException'The node isn't of the expected typeThis error should be happeningtime to call support.' );
    }

    // we now got the rootnode of that'
    s request by the usermost of the time this should be the web visitor (a Anonymous Role user)
    $rootNode NodeFilter::execute$rootNodeNODEFILTER_ELEMENTS_ONLY ); 
    // NodeFilter is a object that filters out nodes that aren't used and return the result, NODEFILTER_ELEMENTS_ONLY maps against the name of a Filter that's available, and will be created at runtime and execute. (filtering through recursive)

    // now we have a hierarchy of nodes that are site elements, all "system" objects are filtered away such as user, usergroup and other magice thing. Only objects defined as site_element are still available.

    $page = new Composite$rootNode->getNodeType(), NODE_NO_PARENT );
    $nodeType $page->getNodeType();
    foreach ( 
    $rootNode->getNodeType() as $node ) {
       
    $page->attach( new Composite$node->getNodeType(), $nodeType );
       
    $nodeType $node->getNodeType();
    }

    // after the composites are generated, the main node composite's render()-method will be triggered, which will create a output
    $outputResult $page->render();
    of ( !$outputResult ) {
        throw new 
    UnexpectedException'The creation of the page failed.' );
    }

    // INode implements getProperty() to obtain the properties from a object/node.
    $context->response->setMimeType$rootNode->getProperty'mimetype' ) );
    $context->response->setContent$outputResult ); 
    Hopefully it's interesting,n if you got a better idea or class design... dont hesitate

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

    I'd like to know where you guys would put things like access control. As I've said earlier, I think each actions/command should have an isSecure() method to determine if the client need some credential(s) to execute it. But where should this check take place? And how?

  19. #194
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I think each actions/command should have an isSecure() method to determine if the client need some credential(s) to execute it. But where should this check take place?
    Wouldn't the best place for this be the Application Controller? I too have the isSecure class method for an Action, which returns boolean. But it is variable as to where you put it I suppose, you could put the responsibility into the Front Controller or in a lower layer.

    What ever suits you and the application design. There is no fixed rule I'd imagine?

  20. #195
    SitePoint Addict
    Join Date
    May 2003
    Location
    The Netherlands
    Posts
    391
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I don't think the responsability of knowing if a user is allowed to perform some action should reside in the action itself. IMO the action should be unaware. Build an authorizator object that returns the privileges for the current user and compare those privileges with the action to be performed.

  21. #196
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by nacho
    I don't think the responsability of knowing if a user is allowed to perform some action should reside in the action itself. IMO the action should be unaware. Build an authorizator object that returns the privileges for the current user and compare those privileges with the action to be performed.
    It seems like for Access Control we need three things:

    1. The conditions that access is granted or denied, such as "groups allowed: admin, artist, editor"

    2. What action is taken when access is denied, such as redirecting to an access denied page or sign-in page.

    3. The data from the session/user specifying what the current access privileges are, for example "signed-in" and "in group editor".

    The question becomes: where in the code are the methods to set the above three values, and where in the code are the calls those methods located.
    Christopher

  22. #197
    SitePoint Member
    Join Date
    Feb 2004
    Location
    Poland
    Posts
    9
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I don't like the idea of having an isSecure() method inside the action. First, the action is loaded unnecessarily if the method fails, since it is not going to be executed. Second, if you want to enforce consistent access control across actions belonging to a single area, I think that you have to make them inherit from a common base class that supplies the correct required credentials. But what if some of your actions are simple server pages, and others a full-blown application controller? You can't have multiple inheritance.

  23. #198
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I've mentioned this before, but what about this - not hypothetical - situation:

    - a user can only edit a news article when he has posted that article himself. In other words $user->id == $news->userID.

    How do you fit that in with your three things needed for Access Control, arborint?

  24. #199
    SitePoint Addict
    Join Date
    May 2003
    Location
    The Netherlands
    Posts
    391
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by arborint
    The conditions that access is granted or denied, such as "groups allowed: admin, artist, editor"
    To start with, I'd define the method to use: RBAC, ACL, ...

    Besides, actions should also be known beforehand so they can be mapped, and business objects (objects upon which an action is performed) should probably be hierarchichal in a way that if the object above the hierarchy does not allow an action you should not have to look any further.

    Quote Originally Posted by arborint
    What action is taken when access is denied, such as redirecting to an access denied page or sign-in page.
    I'd default to an error handler if an action is not allowed.

    Quote Originally Posted by arborint
    The data from the session/user specifying what the current access privileges are, for example "signed-in" and "in group editor".
    This can easily be a hash table loaded when the application gets started. Kind of a lazy loading.

    Quote Originally Posted by arborint
    The question becomes: where in the code are the methods to set the above three values, and where in the code are the calls those methods located.
    I'd take a traditional approach with an authenticator, and authorizator (it sounds weird ) and in the Action Controller (i don't know if you're using something like that; i have not followed the entire thread) I'd check the authorizator before performing an action, probably calling a method IsAllowed which returns a boolean ...

  25. #200
    SitePoint Zealot
    Join Date
    Jul 2005
    Posts
    194
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Dr Livingston: Did you had a look at my code I posted above I thought you wanted to see it


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
  •