SitePoint Sponsor

User Tag List

Results 1 to 24 of 24

Thread: MVC for Dummies

  1. #1
    SitePoint Zealot
    Join Date
    May 2001
    Posts
    193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    MVC for Dummies

    Can someone give me a example of MVC based on this simple application; the app will be able to create/edit/delete articles.

    PHP Code:
    CREATE TABLE `articles` (
      `
    idINT NOT NULL AUTO_INCREMENT PRIMARY KEY
      `
    articleTEXT NOT NULL
    ); 
    I.m having trouble understanding the correct way to do this, I had what i thought was a MVC pattern but after posting this im not so sure.

    So i thought if someone could show me and example of the Model, View, amd Controller for the above application, i could better understand it.

    thanks for any input

  2. #2
    SitePoint Zealot
    Join Date
    Aug 2003
    Location
    Sydney
    Posts
    187
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    article.php (preferably the controller)

    This is showing basic control structure
    PHP Code:

    $article 
    = &new Article;

    switch (
    $_GET['act']) {
     case 
    'add':
     
    $article->add($_POST['article']);
     break;

     case 
    'del':
     ...... 
    That is of course without an error checking or output.

    article.class.php (model)

    PHP Code:
    class Article {
    // Probably a constructor
     
    function Article() {}
     function 
    add() {}
     function 
    del() {}
     ......

    article.tpl.php (view)
    PHP Code:
    <?php if ($article) : ?>
    <div class="article">
     <p><?=$article?></p>
    </div>
    <?php elseif ($addform) : ?>
    <div class="article">
     <form .... >
    </div>
    <?php endif; ?>
    This is just the basics. Once i complete my class/controller/template i'll paste it for you.

  3. #3
    SitePoint Zealot
    Join Date
    May 2001
    Posts
    193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ok, here is simplified code of how i would try implement an MVC pattern to the above app.
    Basically the links and forms in the app contain _OBJECT and _METHOD values either via $_GET or $_POST.
    So in this example if i clicked on the "edit" link, i would create an "ArticleViews" object and call the "articleForm" method from that object.
    and by submitting the form i would create a "ArticleModel" object and call the "editArticle" method.
    Would you consider this MVC? I've used this approach and it and have not had any problems, but i feel like i'm missing the boat on this concept.


    PHP Code:

    // Model
    class ArticleModel{
        
        function 
    getArticles()
        {
            
    $sql mysql_query("SELECT * FROM articles");
            return 
    mysql_fetch_array($sql);
        }
        
        function 
    getArticleById($id)
        {
            
    $sql mysql_query("SELECT * FROM articles WHERE id = '$id'");
            return 
    mysql_fetch_array($sql);
        }
        
        
        function 
    createArticle()
        {
            
    $id $_POST['id'];
            
    $article $_POST['article'];
            
    mysql_query("INSERT INTO articles (id, article) VALUES ('$id', '$article')");
        }
        
        function 
    editArticle()
        {
            
    $id $_POST['id'];
            
    $article $_POST['article'];
            
    mysql_query("UPDATE articles SET id='$id', article='$article'");
        }
        
        function 
    deleteArticle()
        {
            
    $id $_POST['id'];
            
    mysql_query("DELETE FROM articles WHERE id='$id'");
        }
    }

    // View
    class ArticleViews{

        function 
    displayArticles()
        {
            
    $a = new ArticleModel;
            
            
    // create link
            
    echo "<a href=\"index.php?_OBJECT=ArticleViews&_METHOD=articleForm\">Create Article</a><br>";
            
            while(
    $article $a->getArticles())
            {
                
    // edit link
                
    echo "<a href=\"index.php?_OBJECT=ArticleViews&_METHOD=articleForm&id=".$article['id']."\">Edit</a><br>";
                
                
    // delete link
                
    echo "<a href=\"index.php?_OBJECT=ArticleModel&_METHOD=deleteArticle&id=".$article['id']."\">Delete</a><br>";
                echo 
    $article['article'];
            }
        }
        
        function 
    articleForm()
        {
            
    // edit
            
    if($_GET['id'])
            {
                
    $a = new ArticleModel;
                
    $article $a->getArticleById($_GET['id']);
                
    $id $article['id'];
                
    $article $article['article'];
                
                echo 
    "<input type=\"hidden\" name=\"_OBJECT\" value=\"ArticleModel\">";
                echo 
    "<input type=\"hidden\" name=\"_METHOD\" value=\"editArticle\">";
            }
            
    // create
            
    else
            {
                echo 
    "<input type=\"hidden\" name=\"_OBJECT\" value=\"ArticleModel\">";
                echo 
    "<input type=\"hidden\" name=\"_METHOD\" value=\"createArticle\">";
            }
            
            echo 
    "<form action=\"index.php\" method=\"post\">";
            echo 
    "<input type=\"hidden\" name=\"id\" value=\"$id\">";
            echo 
    "<input type=\"text\" name=\"article\" value=\"$article\">";
            echo 
    "<input type=\"submit\">";
            echo 
    "</form>";
        }
    }

    // controller
    class AllowableCalls {
        
        function 
    getLoadedClassMethods()
        {
            
    $classes get_declared_classes();
            
            foreach(
    $classes as $class){
                
    $class_methods[] = get_class_methods($class);
            }
            
            foreach(
    $class_methods as $class=>$methods){
                foreach(
    $methods as $method){
                    
    $method_array[] = $method;
                }
            }
            return 
    $method_array;
        }
        
        function 
    getLoadedFunctions()
        {
            
    $functions get_defined_functions();
            return 
    $functions[user];
        }
            
        function 
    getAllowableCalls()
        {
            
    $allowable_calls array_merge($this->getLoadedClassMethods(), $this->getLoadedFunctions(), get_declared_classes());
            return 
    $allowable_calls;
        }
    }


    class 
    Controller{

        function 
    process($allowable_calls$request){
            
            if(
    in_array(strtolower($request['_OBJECT']), $allowable_calls))
            {
                
    $object $request['_OBJECT'];
                
    $moduleObject = new $object;
            }
            else {
                
    $object "DefaultClass";    // default
                
    $moduleObject = new $object;
            }
            
            if(
    in_array(strtolower($request['_METHOD']), $allowable_calls))
            {
                
    $method $request['_METHOD'];
                
    $moduleObject->$method();
            }
            else {
                
    $method "defaultView";    // default
                
    $moduleObject->$method();
            }
        }

    Then in my index.php

    PHP Code:
        $allowableCalls = new AllowableCalls;
        
    $controller = new Controller;
        
    $controller->process($allowableCalls->getAllowableCalls(), $_REQUEST); 

  4. #4
    SitePoint Zealot
    Join Date
    Aug 2003
    Location
    Sydney
    Posts
    187
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Nice work, seems reasonable enough.

    I do like your controller.

  5. #5
    SitePoint Zealot
    Join Date
    May 2001
    Posts
    193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for your input ausurt, so you would say im on the right track here? I recently posted a question (there is a link in my first message above) about this controller and the response i got made me think maybe im not seeing the big picture of MVC.

  6. #6
    SitePoint Evangelist ghurtado's Avatar
    Join Date
    Sep 2003
    Location
    Wixom, Michigan
    Posts
    591
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    What I really dont understand about your design yet is what is exactly the purpose or benefit of getting a list of allowable methods or classes in your app.

  7. #7
    SitePoint Zealot
    Join Date
    Aug 2003
    Location
    Sydney
    Posts
    187
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    ghurtado i think MikeShank does that because his URLs include the _METHOD and _OBJECT to match up the classes. So if there is no such method/object it fails.

    I think input from some of the PHP gurus on this forum would be much appreciated.

  8. #8
    SitePoint Zealot
    Join Date
    May 2001
    Posts
    193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yeah, basically if a user mistypes a url or tries to manipulate the values of _METHOD or _OBJECT the user gets directed to a default object and method. I guess it's me being paranoid
    Last edited by MikeShank; Dec 8, 2003 at 16:43.

  9. #9
    SitePoint Evangelist ghurtado's Avatar
    Join Date
    Sep 2003
    Location
    Wixom, Michigan
    Posts
    591
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Gotcha. I did not know about your URL scheme and default actions. Thanks for the explanation.

  10. #10
    SitePoint Zealot
    Join Date
    May 2001
    Posts
    193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Anyone else have an opinion as to whether the code above is a legitamate MVC pattern? Like I said it seems to work fine for me, but i would really like to get some confirmation that im going in the right (or the wrong) direction with this thing.

  11. #11
    SitePoint Member jcesar's Avatar
    Join Date
    Sep 2003
    Location
    Colombia
    Posts
    21
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Nice work.

    The only problem I see with your code (And this is only thecnical and shouldn't drive your design until latter) is the overhead it has for each request building the array of allowable calls when only method of one class it's gonna be used.

    Perhaphs I've been worring too much about the performance of my applications lately, but currently I'm trying to break up classes so only code that's gonna be execute is included and avoid building too much configuration / options arrays.

    What I'm getting at it's something like Harry Fuecks's WACT framework.

  12. #12
    SitePoint Enthusiast
    Join Date
    Nov 2000
    Posts
    44
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Actually this is really for dummies like myself, an easy-to-understand example that tackles a practical problem. However, just wondering if any other experts/experienced developers agree w/ the implementation? Or there are more potential problems w/ it?

    Regards


    edited: I believe the implementation is similar to what's in php|arch May article.
    Last edited by SoCold; Jan 22, 2004 at 09:49.

  13. #13
    SitePoint Addict
    Join Date
    Feb 2006
    Posts
    281
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This is the most clearest example of MVC in PHP i have ever seen!

    Can you tell me how you would load files if the classes where all in separated scripts.
    Last edited by blueyon; Feb 24, 2007 at 06:09.

  14. #14
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Mike... You were doing so well, upto this point here,

    PHP Code:
    // ...
    function createArticle()
        {
            
    $id $_POST['id'];
            
    $article $_POST['article'];
            
    mysql_query("INSERT INTO articles (id, article) VALUES ('$id', '$article')");
        } 
    // ... 
    This is your Model, thus you should not have $_GET et al in your Model at all; The Model(s) are completely ignorant of this knowledge. A better option would be just to pass in the parameter(s) via the class method it's self, via the Controller.

    As for everthing else, I suppose it would pass... Personally, I wouldn't address $_GET et al directly, but I would encapsulate them, but that isn't here nor there in regards to MVC, but this specific point I make is purely a design issue, in regards to those GLOBALs ($_GET et al).

  15. #15
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    A short example from myself,

    PHP Code:
    // Controller
    // ...
    public function executeQDataspace_Interface $nodes ) {
                
    $page = new QPage_View$nodes );
                
    $page -> addObserver( new QNews_Show_List() /* Model */ );
                
    $page -> renderDOC_ROOT.'templates/en/news/body.tpl' );
            }
    // ... 
    The Request ($_GET et al) has, prior to reaching this point - executing the controller - has been merged with $nodes; I can do this since the $nodes container is the same type as of Request, so architecturally it makes no difference to the triad (in my view).

    Thought I'd mention that, as accessing the Request is via the View therefore. A Model just looks like this,

    PHP Code:
    // Model
    // ...
    public function push$acceptable ) {
                
    // create resource to query database, get records
                
                
    $acceptable -> importarray_shift$records ) ); // initial record
                
    $acceptable -> import( new QParameters( array( $this -> getName() => $records /* each record typeof qdataspace_interface */ ) ) );
            }
    // ... 
    The View it's self is typeof QDataspace_Interface as well, so I only need to push the Model data over to it via the QDataspace::import( QDataspace_Interface $dataspace ); class method.

    You understand, that I make extensive use of this QDataspace container? It just helps in so many ways, for me to decouple a lot of responsibilities; In fact a huge part of my framework hinges on this type (along with another type; QAcceptee_Interface and QAcceptance_Interface [The Visitor pattern]).

    The View accesses each Model by iterating over it,

    PHP Code:
    // View
    // ...
    abstract class QPage extends QDataspace implements QPage_Interface {
            protected 
    $observers = array();
            
            public function 
    __constructQDataspace_Interface $nodes ) {
                
    $this -> import$nodes );
            }
            
            public function 
    addObserver$observer ) {
                
    $this -> observers[$observer -> getName()] = $observer;
            }
            
            public function 
    acceptQAcceptee_Interface $acceptee ) {
                
    // visitor
                
    $acceptee -> push$this );
            }
            
            public function 
    render$template ) {
                foreach( 
    $this -> observers as $observer ) {
                    
    $observer -> push$this );
                }
                
                include_once( 
    $template );
            }
        } 
    Well, pretty complex for those who have no full understanding of how I do things, but if you can get your head around QDataspace_Interface type, then your half way there

  16. #16
    SitePoint Addict
    Join Date
    Feb 2006
    Posts
    281
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    where to but columns and boxes?
    Last edited by blueyon; Feb 25, 2007 at 04:35.

  17. #17
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    ? You've lost me.

  18. #18
    SitePoint Addict
    Join Date
    Feb 2006
    Posts
    281
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston View Post
    ? You've lost me.
    MVC patterns I have seen so far only seem to work for single page with no columns or parts that appear on all pages.

    What pattern do you use in conjunction with MVC for multiparts of a page?

  19. #19
    SitePoint Enthusiast
    Join Date
    Jul 2006
    Location
    South Dakota
    Posts
    77
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    take a look at the composite pattern for the view. This may be what you're looking for.
    TDDJournal: An Experiment in Test Driven Development.

  20. #20
    SitePoint Wizard REMIYA's Avatar
    Join Date
    May 2005
    Posts
    1,351
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston View Post
    This is your Model, thus you should not have $_GET et al in your Model at all; The Model(s) are completely ignorant of this knowledge. A better option would be just to pass in the parameter(s) via the class method it's self, via the Controller.
    Absolutely. All requests must be managed by the Controller.

  21. #21
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    > What pattern do you use in conjunction with MVC for multiparts of a page?

    Composite and the Visitor; You require the Visitor so you can separate the rendering away from each of those Composites. The separation therefore allows you to easily implement a number of renderers... Such as one for (x)Html, Xml, etc.

    The Controller part in my MVC implementation is a Composite, in that it can contain child Controller(s); A given renderer will recurse the Composite structure, from the bottom up (towards the root) to execute each Controller, and in turn, gather the generated output for each Composite in turn.

  22. #22
    SitePoint Addict
    Join Date
    Feb 2006
    Posts
    281
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I have attached a small example of the code I'm using.

    Any ideas how to implement the design patterns that where suggested into my code?

    Help would be appreciated!
    Attached Files Attached Files
    Last edited by blueyon; Feb 26, 2007 at 05:08.

  23. #23
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You've made the same assumption as someone else [MikeShank] in regards to your Model by putting $_GET et al in there, where they should be in the Controller, and these it for the Controller to pass in the parameters to the Model, be it by the constructor, or a class method on the Model.

    Your not escaping your data either going into your SQL which is bad; Apart from that, I can't (seam to) fault it.

  24. #24
    SitePoint Addict
    Join Date
    Feb 2006
    Posts
    281
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dr Livingston View Post
    You've made the same assumption as someone else [MikeShank] in regards to your Model by putting $_GET et al in there, where they should be in the Controller, and these it for the Controller to pass in the parameters to the Model, be it by the constructor, or a class method on the Model.

    Your not escaping your data either going into your SQL which is bad; Apart from that, I can't (seam to) fault it.
    For the escaping part I have some other code somewhere else that cleans all the stuff going into the database. What I have put here is just a baisc example.

    I actually have a full shopping cart system setup using this type of MVC, but I want to make sure I'm coding things the right way.


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
  •