SitePoint Sponsor

User Tag List

Page 2 of 3 FirstFirst 123 LastLast
Results 26 to 50 of 52

Thread: Pragmatic MVC

  1. #26
    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)
    However, in a few cases, global variables can be suitable for use. They can be used to avoid having to pass frequently-used variables continuously throughout several functions, for example.
    I don't agree with that quotation. It's not a suitable use - it's just a description of what a global is.
    Replacing globals with locals is a way of decoupling code. There is a tradeoff in added complexity each time you decouple code. Therefore, the proper degree of decoupling befitting to an application is diretly related to the size of it. While globals are bad for large bodies of code, they are much less problematic in small applications. So the only suitable use I see for globals are in very small applications. Then again - that can be said about almost any aspect of application design.

  2. #27
    SitePoint Guru
    Join Date
    Aug 2005
    Posts
    986
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    That's the case most times, but $_GET et al are different. Can you give a code example that shows where a local is better than $_GET? I agree that it's bad to use $_GET in your model for example, but in the controller, it's use is perfectly acceptable.

    @Hal9k:

    You code looks good. Remember that MVC can be done in many ways, and that your code isn't wrong as long as you separate M, V and C. One tip though: you are checking for exceptions, and you store it in an instance variable. Why don't you let the exeption unwind the stack further? The client code is then responsible for checking for errors (it's the same now, but you use isError() instead of the exception).

  3. #28
    Afraid I can't do that Dave Hal9k's Avatar
    Join Date
    Mar 2004
    Location
    East Anglia, England.
    Posts
    640
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for your suggestion Fenrir, actually thanks for everyone who's replied to this post, it's certainly given me a better insight into MVC, especially the finer points.

  4. #29
    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 Fenrir2
    That's the case most times, but $_GET et al are different. Can you give a code example that shows where a local is better than $_GET?
    When debugging code that misbehaves.

  5. #30
    SitePoint Guru
    Join Date
    Aug 2005
    Posts
    986
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Can you give a specific example that shows this? I can't think of one personally.

  6. #31
    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 Fenrir2
    Can you give a specific example that shows this? I can't think of one personally.
    How about: http://www.sitepoint.com/forums/show...&postcount=101 ?

  7. #32
    SitePoint Zealot DerelictMan's Avatar
    Join Date
    Oct 2005
    Posts
    123
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    As somewhat of an aside, I wonder why the PHP devs didn't make $_GET/$_POST/et. al. immutable so that you could be sure that they reflected only what was passed in from the user, and weren't modified somewhere else? Seems like that would prevent nightmare scenarios like the one described in your linked post... But then again I suppose that wouldn't be "the PHP way".

  8. #33
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by DerelictMan
    As somewhat of an aside, I wonder why the PHP devs didn't make $_GET/$_POST/et. al. immutable so that you could be sure that they reflected only what was passed in from the user, and weren't modified somewhere else? Seems like that would prevent nightmare scenarios like the one described in your linked post... But then again I suppose that wouldn't be "the PHP way".
    It's the same kind of thinking that gave us register_globals and magic_quotes; seemed like a good idea at the time, but lots of potential for trouble. Unfortunately, unlike register_globals and magic_quotes, I don't think there's much of a case for changing it, and it would be a prrety big backwards compatibility break.

    In any case, the request arrays are globals, just like any other global, and have exactly the same advantages and disadvantages as all other globals. The fact that PHP treats them as a special case does not make them less problematic.

  9. #34
    SitePoint Guru
    Join Date
    Aug 2005
    Posts
    986
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    That is not the sort of example I was thinking of. I meant an example that shows that a requestwrapper is better than just $_GET in some (maybe most) cases. Besides, you could have done the same stupid thing with a requestwrapper.

  10. #35
    SitePoint Wizard Ren's Avatar
    Join Date
    Aug 2003
    Location
    UK
    Posts
    1,060
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Centralised magic_quotes handling. Using $_GET is multiple places could make this a nightmare.

  11. #36
    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 Fenrir2
    I meant an example that shows that a requestwrapper is better than just $_GET in some (maybe most) cases.
    An input/request object makes it easier to create a command line version of the app. If data arrives from $input->getFoo() the rest of the code doesn't need to know where it came from. I think it's also more secure: the input object can just return null or false if a value fails a validation rule. Tainted vars can never escape and validation is centralised in one place rather than scattered throughout the app.

  12. #37
    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 Fenrir2
    That is not the sort of example I was thinking of. I meant an example that shows that a requestwrapper is better than just $_GET in some (maybe most) cases.
    What do you mean by requestwrapper?

  13. #38
    SitePoint Enthusiast
    Join Date
    Nov 2004
    Location
    Canberra, Australia
    Posts
    66
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    What do you mean by requestwrapper?
    Come on, kyber, use your noodle.

    I believe he means the difference between:

    PHP Code:
    $foo $_GET['foo'
    and

    PHP Code:
    $foo $request->get('foo'); 

  14. #39
    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 {RainmakeR}
    Come on, kyber, use your noodle.
    I don't like to assume what other people thinks. From the post, I can see two possible meanings of requestwrapper. Either he means an object, wrapping the variables (As you suggest). Or he is simply referring to passing the global variable as a parameter to the method, rather than accessing it through the global scope.
    If we assume that he meant the first thing, his answer doesn't make much sense. That's why I asked.

  15. #40
    SitePoint Guru
    Join Date
    Aug 2005
    Posts
    986
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    An input/request object makes it easier to create a command line version of the app. If data arrives from $input->getFoo() the rest of the code doesn't need to know where it came from. I think it's also more secure: the input object can just return null or false if a value fails a validation rule. Tainted vars can never escape and validation is centralised in one place rather than scattered throughout the app.
    That's not true ;-). Your validation should be in the model, and you only have this problem if you put it in the controller. If you want to create a commandline version, you can just *put* the parameters in $_GET, rather than putting them in a $input object. How many times have you made a commandline version of a web application?

    Requestwrapper:

    Code:
     $SchemaController = new SchemaController(new RequestWraper($_GET));
    echo $SchemaController->SchemaView->toString();

  16. #41
    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 Fenrir2
    That is not the sort of example I was thinking of. I meant an example that shows that a requestwrapper is better than just $_GET in some (maybe most) cases.
    It's not what you said though - You're mixing apples and oranges now. We were comparing a global variable ($_GET) to a local variable (pass in method).
    The question of a requestwrapper or a native array is a different one. Whether you choose to wrap the data in an object or not, you still have to choose to make this object global or to pass it in.
    The example illustrated how using a global variable can be hard to debug, since you have no way to figure out where it was manipulated from. As you say yourself, the problem at hand is not that the variable is an array - the problem is that it's global in scope. I don't like global objects any more than global arrays.

  17. #42
    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 Fenrir2
    Your validation should be in the model, and you only have this problem if you put it in the controller.
    I think validation has to be performed by the controller - certainly anything which has a bearing on application controller logic (also being discussed here). Validation rules could be defined in domain objects although there could be some problems with that.

    Quote Originally Posted by Fenrir2
    If you want to create a commandline version, you can just *put* the parameters in $_GET, rather than putting them in a $input object.
    Not as clean a solution as polymorphism?

    Quote Originally Posted by Fenrir2
    How many times have you made a commandline version of a web application?
    Fair point. A graphic-rich web site wouldn't make much sense on the command line but a lot of things do - eg tools for installing, managing files etc. SimpleTest can be run from the command line.

    I think the fact that you can easily drop in an argv-parsing Input object reveals a better design which isn't dependent on an http/cli context. You don't want to make things more complicated than they need to be but it just seems like an obvious thing to encapsulate. As well as getters for safe, validated values, an input object can be used like this:
    PHP Code:
        if($input->isProcessable()) {
            
    // process the submission
        
    } else {
            
    // redisplay the form
        

    A controller needs to make decisions (application controller logic) and can ask an input object about any relevant input state.

  18. #43
    SitePoint Guru
    Join Date
    Aug 2005
    Posts
    986
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I think validation has to be performed by the controller - certainly anything which has a bearing on application controller logic (also being discussed here). Validation rules could be defined in domain objects although there could be some problems with that.
    Ruby on Rails uses validation in the model and it works very well.

    Not as clean a solution as polymorphism?
    Where do you see polymorphism? Could you give an example?

    In the example you give, what is $input exactly? I don't understand it how it lets you write the same code that will work with a commandline and with a http request.

    You could do this, for example:

    Code:
    if(this_is_the_commandline)
    {
      // set $_GET (or $_REQUEST) to commanline args
    }
    Problem solved .

    It's not what you said though - You're mixing apples and oranges now. We were comparing a global variable ($_GET) to a local variable (pass in method).
    The question of a requestwrapper or a native array is a different one. Whether you choose to wrap the data in an object or not, you still have to choose to make this object global or to pass it in.
    The example illustrated how using a global variable can be hard to debug, since you have no way to figure out where it was manipulated from. As you say yourself, the problem at hand is not that the variable is an array - the problem is that it's global in scope. I don't like global objects any more than global arrays.
    OK, I thought you thought that objects would solve this, but I was wrong apparently. I just wanted to show you that you can do evil things with global objects too.

    If you pass in every value as a parameter, you have the one-thing-changes-change-code-in-3-places-problem, so this method isn't very good.

    If you pass in a requestwrapper object, you solved that problem, but you have to put it in every controller method. You could pass in $_GET too. The problem with this is that you can do the same thing without passing it in by using $_GET directly. I know you can do evil things with globals, but if you only read them in the controller, you are safe. The code will be exactly the same, except for 3 differences: (1) you don't pass $_GET in (2) you write "function action_name()" instead of "function action_name($input)" (3) you write $_GET instead of $input.

  19. #44
    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 Fenrir2
    Ruby on Rails uses validation in the model and it works very well.
    I wish I had time to learn some Ruby - can't comment on rails.

    A controller has to ask other objects for information in order to decide what to do next. With rules in domain objects, they have to be loaded even if it turns out they aren't going to be used if the validation fails and the controller decides to do something else instead. Either that or application controller logic is going to leak into the domain. The former isn't a bad choice if that's the way you like to cut the OOP cake but the latter would be.

    Quote Originally Posted by Fenrir2
    Where do you see polymorphism? Could you give an example?
    Input has state and I think makes a good object. I'd use it something like this:
    PHP Code:
             // check for valid syntax (form forging, query string tampering etc)
             
    if( !$input->hasValidSyntax()) {
                 
    // bug out
             
    }
             
    // form submission
             
    if($input->isProcessable()) {
                  
    // process the form (*now* I'll load the 
                 // domain objects used to process the sub...)
             
    } else {
                
    // redisplay the form
            
    }
             
    // $input gets passed around all over the place
             // other objects get values with:
             
    $foo $input->getFoo();
              
    $bar $input->getBar(); 
    There is no mention of GPC anywhere - except in the input object of course. If I do want to switch to a CLI context I can use a different input object. And change the views. It might get more complicated but that's a start.

    Quote Originally Posted by Fenrir2
    Code:
    if(this_is_the_commandline)
              {
                // set $_GET (or $_REQUEST) to commanline args
              }
    Isn't that a bit "ugly"? http GET, POST etc don't have any meaning on the command line.

    Also, I believe an Input object promotes better security. It can act like a kind of firewall - a single, guarded front door which never lets anything bad through (so long as it's configured correctly). If you scatter $_GET etc throughout the app it's much harder to review what is being checked and what isn't.

  20. #45
    SitePoint Guru
    Join Date
    Aug 2005
    Posts
    986
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I wish I had time to learn some Ruby - can't comment on rails.
    Ruby is far easier than PHP and most other languages. If you can program (which you can, and basic oop understanding helps too) you can learn basic Ruby in an hour

    A controller has to ask other objects for information in order to decide what to do next. With rules in domain objects, they have to be loaded even if it turns out they aren't going to be used if the validation fails and the controller decides to do something else instead. Either that or application controller logic is going to leak into the domain. The former isn't a bad choice if that's the way you like to cut the OOP cake but the latter would be.
    If you put the validation in the model every domain object will be validated. The extra loading is not a big overhead. Look at this:

    Code:
    class Post < ActiveRecord::Base
      validates_presence_of :title
    end
    
    post = Post.new(:content => "bla bla...")
    
    if post.save()
      # post has been saved
    else
      # validation made sure this post can't be saved with the save() method
    end
    because post doesn't have a title, and there is a validation rule which requires it, this post will not be saved. If you do this:

    Code:
    post = Post.new(:title => 'foo', :content => 'bar')
    It will be saved if you call save().

    Code:
    // check for valid syntax (form forging, query string tampering etc)
             if( !$input->hasValidSyntax()) {
                 // bug out
             }
             // form submission
             if($input->isProcessable()) {
                  // process the form (*now* I'll load the
                 // domain objects used to process the sub...)
             } else {
                // redisplay the form
            }
             // $input gets passed around all over the place
             // other objects get values with:
             $foo = $input->getFoo();
              $bar = $input->getBar();
    I don't understand what the methods do. Can you give me examples? (getFoo = $_GET['foo'] ??)

    There is no mention of GPC anywhere - except in the input object of course. If I do want to switch to a CLI context I can use a different input object. And change the views. It might get more complicated but that's a start.
    With $_GET/$_REQUEST, you can set its contents if it's in CLI context.

    Isn't that a bit "ugly"? http GET, POST etc don't have any meaning on the command line.
    I find a big class much uglier, but I agree that $_GET doesn't sound good. $_REQUEST is fine for me though.

    Also, I believe an Input object promotes better security. It can act like a kind of firewall - a single, guarded front door which never lets anything bad through (so long as it's configured correctly). If you scatter $_GET etc throughout the app it's much harder to review what is being checked and what isn't.
    As I mentioned above, I prefer validation in the models, but you can do this if you want:

    Code:
    filter_bad_things($_REQUEST);

  21. #46
    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 Fenrir2
    You could pass in $_GET too. The problem with this is that you can do the same thing without passing it in by using $_GET directly.
    You miss the point.

    Yes, it's the same, but with one tiny little difference - There are no invisible side effects. It may not be a problem if you're a single developer, and are able to keep your entire application design in your head. For anybody else, it's pure sabotage.

    Quote Originally Posted by Fenrir2
    I know you can do evil things with globals, but if you only read them in the controller, you are safe.
    Didn't you just suggest writing to the globals in your latest post?
    Even if you didn't, how is someone comming in to work with your code going to know that? Or if you use third party code, how can you be sure it doesn't tamper with the globals?

  22. #47
    SitePoint Guru
    Join Date
    Aug 2005
    Posts
    986
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    You miss the point.

    Yes, it's the same, but with one tiny little difference - There are no invisible side effects. It may not be a problem if you're a single developer, and are able to keep your entire application design in your head. For anybody else, it's pure sabotage.
    There are no side effects if you read $_GET.

    Didn't you just suggest writing to the globals in your latest post?
    Even if you didn't, how is someone comming in to work with your code going to know that? Or if you use third party code, how can you be sure it doesn't tamper with the globals?
    Yes I did, but only in one place, and not in the controller, and only if you don't want to use validation in the model! If you wrap $_GET in a class, and you filter bad information, you're tampering with it too?

  23. #48
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    > but only in one place, and not in the controller, and only if you don't want to use validation in the
    > model

    Which pretty much limits your freedom, so why limit your options?

    > and you filter bad information, you're tampering with it too?

    In what way? You have to prevent the illegal data getting to the heart of your application, and if you encapsulate $_GET et al within a class, then there is only one centralised place to contend with. I disagree with the term tampering as your not really tampering with it...

    You see, $_GET et al still exist in their original state within the encapsulated class as is, it's just that you filter the data and then allow your application access to the data that's filtered (sanitised?) instead.

    If you don't encapsulate $_GET et al then you need to specifically filter (sanitise) the data at every level where your application uses $_GET et al. Really, I can't see the problem you have with this?

  24. #49
    SitePoint Guru
    Join Date
    Aug 2005
    Posts
    986
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Which pretty much limits your freedom, so why limit your options?
    You can do validation with PHP-style boilerplate code in the controller, but that doesn't feel right.

    In what way? You have to prevent the illegal data getting to the heart of your application, and if you encapsulate $_GET et al within a class, then there is only one centralised place to contend with. I disagree with the term tampering as your not really tampering with it...

    You see, $_GET et al still exist in their original state within the encapsulated class as is, it's just that you filter the data and then allow your application access to the data that's filtered (sanitised?) instead.

    If you don't encapsulate $_GET et al then you need to specifically filter (sanitise) the data at every level where your application uses $_GET et al. Really, I can't see the problem you have with this?
    But why is filtering $_GET directly "wrong" if you can get much cleaner code that way?

  25. #50
    Afraid I can't do that Dave Hal9k's Avatar
    Join Date
    Mar 2004
    Location
    East Anglia, England.
    Posts
    640
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    It seems like I inadvertently opened a can of worms

    Anyway, here's my revised code for anyone who cares:

    Dir structure:
    Code:
    install.php
    /controllers/schema_controller.php
    /views/schema_view.php
    /models/schema_model.php
    Code:
    install.php:
    PHP Code:
    require_once 'views/base_html_view.php';
    require_once 
    'views/schema_view.php';
    require_once 
    'libs/classes/Database.php';
    require_once 
    'libs/classes/RequestWrapper.php';
    require_once 
    'models/schema_model.php';
    require_once 
    'controllers/schema_controller.php';

    $SchemaController = new SchemaController(new RequestWrapper()); 
    $SchemaController->render(); 
    Code:
    schema_controller.php:
    PHP Code:
    error_reporting(E_ALL E_NOTICE);

    class 
    SchemaController
    {
        private 
    $SchemaModel;
        private 
    $SchemaView;
        private 
    $Request;

        function 
    __construct($Request)
        {
            
    $this->Request $Request;
            
    $this->SchemaModel = new SchemaModel();
            
    $this->SchemaViewFactory();
            
    $this->run();
        }
        
        function 
    SchemaViewFactory()
        {
            switch (
    $this->Request->offsetGet('display'))
            {
                case 
    'plaintext'
                    
    $this->SchemaView = new SchemaPlaintextView();
                break;
                
                default:
                    
    $this->SchemaView = new SchemaHTMLView();
            }
            
        }
        
        function 
    run() 
        {
            try 
            {
                
    $this->SchemaModel->connectDatabase();
                
    $this->SchemaModel->createUserTable();
            } 

            catch (
    DatabaseException $Exception
            {
                
    $this->SchemaView->addError($Exception);
            }
        }
        
        function 
    render()
        {
                echo 
    $this->SchemaView->toString();
        }

    Code:
    schema_view.php:
    PHP Code:
    class SchemaHTMLView extends HTMLView
    {
        
        
        function 
    __construct()
        {
            
    HTMLView::__construct('style.css');
        }

        function 
    addError($Exception)
        {
            
    $error_message $Exception->getMessageArray();
            
    $this->body .= "<p>" $error_message['database_reports'] . "</p>";
            
    $this->title "Installation Error";
        }

        function 
    toString()
        {
            
    $this->addHeader();
            
    $this->addBody();
            
    $this->addFooter();

            return 
    $this->page;
        }

    }

    class 
    SchemaPlaintextView
    {
        private 
    $body;
        
        function 
    addError($Exception)
        {
            
    $error_message $Exception->getMessageArray();
            
    $this->body .= $error_message['database_reports'];
        }
        
        function 
    toString()
        {
            return 
    $this->body;
        }
        

    Code:
    schema_model.php:
    PHP Code:
    class SchemaModel
    {
        
        private 
    $Database;
        public 
    $Exception;
        
        function 
    connectDatabase()
        {
            
    $this->Database = new Database('''''''');
        }

        function 
    createUserTable()
        {
            
    $users =<<<EOD
    // sql here
    EOD;
            
                
    $this->Database->query($users);
        }
        



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
  •