SitePoint Sponsor

User Tag List

Page 1 of 2 12 LastLast
Results 1 to 25 of 36
  1. #1
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    926
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)

    Controllers and Actions in MVC

    I'd like to know how to properly create controllers and actions in MVC. So far I've used them in implementations that were not true MVC so I may not have a correct understanding about when I should create a new controller and when a new action - I'd like to learn some proper basics.

    Let's say I have some common tasks with managing users:

    1. Add user
    2. Edit user
    3. List users
    4. Delete users, hide/unhide users (toggle a flag on or off)
    5. Display single user data

    Below I'm presenting my suggested scenarios, please comment on each one whether it looks good on not:

    Pt. 1 & 2: adding and editing a user are almost identical in html display (same form) so I suspect these will require one controller with two actions. One controller because one controller is always tied to one view. Additionally, I think I will need submit actions that will get values submitted by POST and either redirect to another page or redisplay the form in case of a validation error. So I end up with 4 actions:

    PHP Code:
    class UserFormController {
        
        public function 
    add() {
            
    // ...
        
    }

        public function 
    edit() {
            
    // ...
        
    }

        public function 
    addSubmit() {
            
    // ...
        
    }

        public function 
    editSubmit() {
            
    // ...
        
    }


    Pt. 3: Listing users - there will be features like listing all users, filtering by criteria and pagination. I suspect I can get away with 1 controller with 1 action and simply pass all the necessary parameters from GET to the model in the action.

    Pt. 4:: Deleting (selected) users, hiding/unhiding users - this is supposed to delete the users or perform some other operation in the db on the user and redirect back to the user list. Do I need the view at all in this case? I suppose I can create one controller with 3 actions:

    PHP Code:
    class UserChangeController {

        public function 
    delete() {
            
    // ...
        
    }

        public function 
    hide() {
            
    // ...
        
    }

        public function 
    show() {
            
    // ...
        
    }

    What do I do about the view then? Do I create an empty one or allow my system to have viewless controllers? I'm a little baffled with this one - do I use these actions to pass POST criteria to specific methods in the model that will perform the requested updates on the users in the db? Like this:

    PHP Code:
    class UserChangeController {

        public function 
    delete() {
            
    $userIds array_keys($_POST['checkboxes']);
            
    $this->model->deleteUsers($userIds);

            
    // I don't know if this is the best place to do redirection?
            
    header("Location: " $_POST['redirect']);
            exit;
        }

    Pt. 5:: a page which displays user info - this should be easy, 1 controller and 1 action.

  2. #2
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,154
    Mentioned
    14 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Lemon Juice View Post
    I'd like to know how to properly create controllers and actions in MVC.
    Well... first off, to avoid any debates, we need to clarify which "kind" of MVC you want to implement. Instead of retyping it all, see one of my past posts.
    "First make it work. Then make it better."

  3. #3
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    926
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Jeff Mott View Post
    Well... first off, to avoid any debates, we need to clarify which "kind" of MVC you want to implement. Instead of retyping it all, see one of my past posts.
    In this case I want to implement MVC in its purest traditional sense, the one TomB is advocating.

  4. #4
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    How you actually structure the individual actions is application specific and not specified by MVC itself. However, here's how I do adding/editing. They are essentially identical. I have my model look like something like this:

    PHP Code:
    <?php
    class UserEditController {
        private 
    $user;
        private 
    $userMapper;

        public function 
    __construct(UserMapper $userMapper) {
            
    $this->userMapper $userMapper;
        }    

        public function 
    setEditing($id) {
            
    $this->user= = $this->userMapper->findById($id);                
        }
        
        public function 
    getUser() {
            return 
    $this->user;
        }

        public function 
    save($data) {
            if (
    $data['id'] == null) {
                
    //Adding
            
    }
            else {
                
    //Editing
            
    }
        }


    }
    The controller then does this:

    PHP Code:
    <?php
    class UserEditController {
        private 
    $model;


        public function 
    __construct(UserEditModel $model) {
            
    $this->model $model;
        }

        
    //Default action
        
    public function main($id null) {
            
    $this->model->setEditing($id);
        }

        public function 
    submit() {
            
    //Do some sanity checks on $data then send it to the model for saving
            
    $this->model->save($_POST['user']);                
        }

    }

    The view populates the form from $model->getUser() if $model->getUser() doesn't return null. This way everything is reused. In actual fact, because of the way my DataMapper works (by using ON DUPLICATE KEY UPDATE) I never need the if/else for detecting adding/editing but that's an implementation detail!



    Listing users - there will be features like listing all users, filtering by criteria and pagination. I suspect I can get away with 1 controller with 1 action and simply pass all the necessary parameters from GET to the model in the action.
    Possibly, strictly speaking these should all be separate actions but to achieve combinations your router would need to handle calling multiple actions on one request (Which isn't a bad thing) but that's quite a big topic in itself. The simplest way, with a URL:Controller action router is, as you say, having the controller parse $_GET and set the model's state accordingly. The model should expose methods for sort/filter/paginate and the controller would call each of them.


    Pt. 4:: Deleting (selected) users, hiding/unhiding users - this is supposed to delete the users or perform some other operation in the db on the user and redirect back to the user list. Do I need the view at all in this case? I suppose I can create one controller with 3 actions:
    On which view does the "delete" button sit? If it's the user list, then the UserList controller should have an action called "delete" which calls a (reusable!) model method which contains the implementation. Any place you have a delete user button would call the model's action. On the redirect, you'll send someone to a different page. Perhaps one that sates "The following users have been deleted: x,y,z". That view could then include the list view again to show the updated list, if you so wished. That "Thank you" view may not have a model and almost certainly wouldn't need a controller.


    PHP Code:
    Pt5:: a page which displays user info this should be easy1 controller and 1 action
    Not necessarily. Depending on what it's doing. If it's purely display then you don't need a controller, however if you need to get the ID of the user being edited from $_GET then you need a controller for that. It seems redundant to have a controller with one action that just sets one value on the model but this is where the power of MVC actually comes in; the model's state can be set from anywhere so another part of the system could pull in the model and view from another view without needing the controller.

  5. #5
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    926
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Tom, thanks for your code examples. If MVC does not specify the structure of actions then it's even more valuable to see some real world examples.


    Quote Originally Posted by TomB View Post
    PHP Code:
    Pt5:: a page which displays user info this should be easy1 controller and 1 action
    Not necessarily. Depending on what it's doing. If it's purely display then you don't need a controller, however if you need to get the ID of the user being edited from $_GET then you need a controller for that. It seems redundant to have a controller with one action that just sets one value on the model but this is where the power of MVC actually comes in; the model's state can be set from anywhere so another part of the system could pull in the model and view from another view without needing the controller.
    Yes, it's purely display but the user ID sits in the URL of the page so is it possible to do without a controller? I think I need a controller to pass GET to the model's state, is this correct?

    Another thing, even if this was a static page that didn't need any parameters from the URL (for example, a contact page) how would I do without a controller? A page like that needs its own URL (unless I'm including the view's content somewhere else), which equals a fresh page request. If we assume that each page request initiates the MVC in this way:
    PHP Code:
    model = new Model();
    $controller = new Controller($model);
    $view = new View($controller$model);
    echo 
    $view->output(); 
    then it's clear that the page needs a controller because the view requires it. How is it then that I don't need a controller? What am I missing here?

  6. #6
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    Yes, it's purely display but the user ID sits in the URL of the page so is it possible to do without a controller? I think I need a controller to pass GET to the model's state, is this correct?
    Yes that's correct. That's a controller action, which then tells the model what user is being dealt with.

    A view only needs a controller if the view has user interaction (or in our case, links/form submissions). These need to link back to a specific (interchangeable) controller. In the real world, to make these actions interchangeable, your view would also need access to a router, which worked out the route for a given controller action (The inverse of what the router does on the request, taking a url and routing to a controller action, in the view the router would take a controller and an action name and generate a URL for it).

    If there are no actions, the view doesn't need to request the controller in its constructor.

    However, "Load the the user with the ID 123 into the view" is a user action if it's coming from a URL so requires an action.

  7. #7
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    926
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    So basically, for static pages can I do something like this
    PHP Code:
    $model = new Model();
    $view = new View(null$model);
    echo 
    $view->output(); 
    ?

    To go even further, if I wanted to have an even simpler static page, could I do without the model as well?
    PHP Code:
    $view = new View(nullnull);
    echo 
    $view->output(); 
    The model provides data to the view but if the view only outputs some simple html and doesn't require any data from the model then would it be a good idea to allow views without a model? I suppose this would not be MVC anymore, but perhaps an MVC system could allow to be a V system on some requests?

  8. #8
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    Well even better:

    PHP Code:
    $view = new View();
    echo 
    $view->output(); 
    The view shouldn't ask for parameters if it's never going to need them. However, if the view can optionally have a model/controller then yes it makes sense to ask for them. It depends what the view is doing, but it should never ask for constructor arguments if it's never going to use them.

    Edit: Realistically though, for a "static page" you'll probably define it in this kind of way so that it's reusable.

    PHP Code:
    class StaticView {
        private 
    $model;

        public function 
    __construct(StaticModel $model) {
            
    $this->model $model;
        }

        public function 
    output() {
            return 
    $this->model->getStaticPage();
        }

    You could then optionally have a controller which set a state on the model saying which page to load. The model could then load the page from somewhere. It's a good example of MVC in action actually: The model is interchangeable and could then be substituted to load the static HTML from the filesystem, a database, a web service etc.

    Edit2: And before someone says "Well the view is redundant then!" the view could be substituted to one which does some post-processing on the HTML that's been received.

  9. #9
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    926
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by TomB View Post
    Edit: Realistically though, for a "static page" you'll probably define it in this kind of way so that it's reusable.
    Thanks, this makes sense and the StaticPage view looks quite convenient!

    One more question, on your site you provide an example where UserEditController and UserListController extend Controller and it's not really clear why you are extending Controller. I suppose Controller is some kind of default controller but I can't see anything in it that is actually inherited and used. And if controllers are supposed to be minimalist is it worthwhile creating hierarchies where one extends the other?

  10. #10
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    I'll amend the example there, occasionally it's useful for a controller to extend a base class but it's certainly not necessary and in the case it isn't. I'll make the example more clear.

  11. #11
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    926
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by TomB View Post
    I'll amend the example there, occasionally it's useful for a controller to extend a base class but it's certainly not necessary and in the case it isn't. I'll make the example more clear.
    Okay, that's great! Thanks for your answers, Tom, they are very instructive.

    Off Topic:

    If I may have a suggestion for your site, it would be great if your code examples were actually tested (not unit-tested but simply run by you to check if they execute fine). I tried getting to work your Dice for routing as you explained it but the code fragments had a few typos I had to correct and in the end Dice errored out not being able to find a component whose name started with '$route_' (xdebug pointing to line 33). Probably these are trivial things to correct by someone who knows how these patterns work but a bit more difficult for someone who is just learning them. I'll get to play with DI for routing maybe at some later point so I'm not asking you for help with this now, I just want to make a general suggestion. Also, the working example of Router is not working. Apart from that you've got a lot of useful information on yout site!

  12. #12
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,154
    Mentioned
    14 Post(s)
    Tagged
    0 Thread(s)
    Sorry, I just have to ask one quick question.

    Quote Originally Posted by TomB View Post
    PHP Code:
    class StaticView {
        private 
    $model;

        public function 
    __construct(StaticModel $model) {
            
    $this->model $model;
        }

        public function 
    output() {
            return 
    $this->model->getStaticPage();
        }

    Presumably getStaticPage() is returning HTML. Why are we delegating presentation to the model?
    "First make it work. Then make it better."

  13. #13
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    926
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Jeff Mott View Post
    Presumably getStaticPage() is returning HTML. Why are we delegating presentation to the model?
    My guess is that HTML returned by getStaticPage() comes from a data source like a database. So the view is actually using the model to get data from the database, the model is not creating the presentation. We can imagine that the admin panel may have a rich text editor for the page content. This can be looked upon as incorrect because we are throwing HTML into the db and then we are using the value, which is a mix of presentation and content (and possibly some behaviour in javascript) but in the real world this is often the most practical solution. TomB may correct me if I'm wrong on this

  14. #14
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,154
    Mentioned
    14 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Lemon Juice View Post
    My guess is that HTML returned by getStaticPage() comes from a data source like a database. So the view is actually using the model to get data from the database
    I suppose I didn't notice that we were assuming that the static HTML was stored in a database.
    "First make it work. Then make it better."

  15. #15
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by Jeff Mott View Post
    I suppose I didn't notice that we were assuming that the static HTML was stored in a database.

    We're not assuming anything, that's the point. The model could get the HTML from anywhere, the view doesn't care. MVC provides a basic method of applying proper Separation of Concerns to your code. Should a model load HTML? Sure, why not! It is just data after all! A model almost certainly shouldn't be generating HTML on the fly, but loading data is loading data, the model doesn't care whether that data is HTML or any other format or what the view is going to use it for.

    Answer this: Should the model load a CSV file? An XML file? Obviously, the answer is yes. A HTML file is no different. You wouldn't question a MVC set up where the model loaded a CSV file and the view outputted some HTML using data from the CSV (via the model). Why question a MVC set up where a model loads an HTML file and outputs a CSV (or in this case, outputs HTML)? The separation of concerns is the same; as long as the View doesn't know the implementation of the model and the Model doesn't care what the view does with the data then we're all good!

    You may wish to load the HTML and extract some specific data from it prior to displaying it, you may wish to display it as is. The goal here is to separate the loading and processing of the data. This allows us to use the same processing logic on data from multiple sources or apply different processing to data from the same source.

  16. #16
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,154
    Mentioned
    14 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by TomB View Post
    Answer this: Should the model load a CSV file? An XML file? Obviously, the answer is yes.
    Well, actually, I would think that the model would provide only the data. It's the view that would present that data as CSV or XML or JSON... or as HTML.
    "First make it work. Then make it better."

  17. #17
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    926
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Jeff Mott View Post
    Well, actually, I would think that the model would provide only the data.
    One of the reasons why I think model can't have the restriction to load only raw data is that sometimes you really don't have access to raw data. For example, you want to extract information from a separate server and you only have access to their HTML pages. In this case you have no choice other than load formatted data.

    Edit: on second thought... maybe my example wasn't the best one because it seems you think that the model should only provide raw data to the view regardless of how the data is fetched from the outside...

  18. #18
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by Jeff Mott View Post
    Well, actually, I would think that the model would provide only the data. It's the view that would present that data as CSV or XML or JSON... or as HTML.
    The model must get its data from somewhere. The point I was trying to make is that the View shouldn't be concerned with the initial format (or location) of the data it's going to use. The model could load data from a web service, database, CSV file, XML file or a binary signal intercepted between satellite dishes and the View would just read data in some data in a predefined format from the model. Whether that format is a string, an array, an object or anything is the contract between the model and the view and the only thing the view needs to know about the model. "I'll get data in this format from this model API call". How that data was constructed is of no concern of the views. The view is then free to present that data in any way it likes irrespective of what format and where the model happened to get the data initially.

  19. #19
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    I'll provide a practical example, because it's probably easier to follow. I won't use HTML as an output format as that's too weighted in PHP and makes things less obvious.



    PHP Code:
    interface TomsModel {    
        public function 
    getData();
    }

    interface 
    TomsView {
        public function 
    output();
        public function 
    getMimeType();

    Let's assume getData() provides a key => value array of some arbitrary data and view:utput() returns a string and getMimeType() returns the MIME type of the data in output();

    I can now define some views to display the data in a variety of formats:

    PHP Code:
    class JSonView implements TomsView {
        private 
    $model;

        public function 
    __construct(TomsModel $model) {
            
    $this->model $model;
        }

        public function 
    output() {
            return 
    json_encode($this->model->getData());
        }

        public function 
    getMimeType() {
            return 
    'application/json';
        }
    }


    class 
    CsvView implements TomsView {
        private 
    $model;

        public function 
    __construct(TomsModel $model) {
            
    $this->model $model;
        }

        public function 
    output() {
            
    $stream =  fopen('php://temp/');
            foreach (
    $this->model->getData() as $row) {
                
    fputcsv($stream$row);    
            }
            return 
    stream_get_contents($stream);
        }

        public function 
    getMimeType() {
            return 
    'text/csv';
        }
    }



    //Using the pchart library to display the data as a pie chart: http://pchart.sourceforge.net/documentation.php?topic=exemple15
    class PieChartView implements TomsView {
        private 
    $model;

        public function 
    __construct(TomsModel $model) {
            
    $this->model $model;
        }

        public function 
    output() {
            
    $dataSet = new pData;
            foreach (
    $this->model->getData() as $row) {
                
    $dataSet->addPoint($row);
            }
            
    $dataSet->addAllSeries();

            
    $chart = new pChart(300300);    
            
    $chart->drawBasicPieGraph($dataSet->GetData(), $dataSet->GetDataDescription(),120,100,70,PIE_PERCENTAGE,255,255,218);  
            return 
    $chart->render();
        }

        public function 
    getMimeType() {
            return 
    'image/png';
        }



    The beauty of this is that these views could work with any of these models:


    PHP Code:
    class DatabaseModel implements TomsModel {
        private 
    $pdo;

        public function 
    __construct(PDO $pdo) {
            
    $this->pdo $pdo;
        }

        public function 
    getData() {
            return 
    $this->pdo->query('.....');
        }
    }



    class 
    CSVModel implements TomsModel {
        private 
    $csvFile;

        public function 
    __construct($csvFile) {
            
    $this->csvFile $csvFile;
        }

        public function 
    getData() {
            
    $returnData = array();
            if ((
    $handle fopen($this->csvFile'r')) !== false) {
                    while ((
    $data fgetcsv($handle1000",")) !== FALSE) {
                        
    $returnData[] = $data;
                }

                   }
                
    fclose($handle);

            return 
    $returnData;            

        }
    }


    class 
    SatelliteInteceptorModel implements TomsModel {


        public function 
    __construct(SatelliteStream $statelliteStream) {
            
    $this->satelliteStream $statelliteStream) ;

        }

        private function 
    decode($data) {
            
    //...
        
    }

        public function 
    getData() {
            
    $data $this->decode($this->satelliteStream->interceptData);

            
    //format $data into an array that the view is expecting
            
    return $data;
        }


    Any of these models can be used with any of the views. This is where MVC shines because the data source is entirely disconnected from the display logic. The model provides the view with some data in a format they both know about. The view does whatever it likes to this data in order to display it and the model takes data from any source and puts it into the format that the view can use. This makes the display logic reusable because it can be used with any of the models and it means a new model can be added without having to write a new view for it.

    For example, I could write a new model which combined data from two separate CSV files and still use the same view.

    As you see, it's possible to go from CSV -> CSV using my example code and have a lot of redundant processing but, this redundancy is what allows the view to be agnostic of the data source and is a very small price to pay for having interchangeable components. Yes the view could just load the CSV directly and output it, but then its data source must always be a CSV file.

  20. #20
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,154
    Mentioned
    14 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by TomB View Post
    The model must get its data from somewhere. The point I was trying to make is that the View shouldn't be concerned with the initial format (or location) of the data it's going to use.
    But for a static page, as Lemon described it, there isn't any data. It's just a static view. So to me, it seemed... unusual... when you delegated that to the model.
    "First make it work. Then make it better."

  21. #21
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    if it's truly a "static page" then why are you going via PHP to load it? The answer, of course, is that you want to do something with that HTML such as nest it inside another view.

    HTML is just data, a simple string (usually) loaded from a file. The HTML is the data in this scenario and the contract between the model and the view is that the model will return a string (or a string of HTML), which the view can then use to do something with. Loading a file is certainly the responsibility of a model and not a view. The views job is to format the data from the model. If the format of the data is already that which the model provides it, well, it doesn't need to do anything.

  22. #22
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    926
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Jeff Mott View Post
    But for a static page, as Lemon described it, there isn't any data. It's just a static view.
    When I first mentioned 'static page' in this thread I meant a page where all data is hardcoded in the view therefore no model is necessary.

    Later TomB expanded on the static page implementation so that the page's content could be loaded from somewhere like a db. Then the model becomes necessary. Such a page is not as static as the one in the previous case because the content is loaded dynamically from somewhere. We may use the term 'static' to mean different things here.

  23. #23
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,154
    Mentioned
    14 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by TomB View Post
    HTML is just data, a simple string (usually) loaded from a file. The HTML is the data in this scenario and the contract between the model and the view is that the model will return a string (or a string of HTML), which the view can then use to do something with. Loading a file is certainly the responsibility of a model and not a view. The views job is to format the data from the model. If the format of the data is already that which the model provides it, well, it doesn't need to do anything.
    Out of curiosity, if the HTML "data" could only be retrieved by rendering a template (which is an extremely common scenario), then is that still the responsibility of the model? If loading a file is "certainly" the responsibility of a model and not a view, then is it the model's job to load templates?
    "First make it work. Then make it better."

  24. #24
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,154
    Mentioned
    14 Post(s)
    Tagged
    0 Thread(s)
    Actually, nevermind. I'll butt out. Sorry for turning this thread debate-ish. I'll stop injecting myself into the conversation.
    "First make it work. Then make it better."

  25. #25
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    Actually, nevermind. I'll butt out. Sorry for turning this thread debate-ish. I'll stop injecting myself into the conversation.
    It's a good question so I'll answer it anyway! Debates are good, there isn't a right/wrong answer with anything at this level. Some answers are better than others, but it's how you define "better" that makes a rather large difference and that's certainly up for debate.

    Quote Originally Posted by Jeff Mott View Post
    Out of curiosity, if the HTML "data" could only be retrieved by rendering a template (which is an extremely common scenario), then is that still the responsibility of the model? If loading a file is "certainly" the responsibility of a model and not a view, then is it the model's job to load templates?
    The view shouldn't be concerned with how its template was constructed (Standard dependency injection arguments apply).

    Ideally your view would look like this:

    PHP Code:
    class TemplateView {
        public function 
    __construct(Template $templateModel $model) {        
        }

    And, for what its worth, the template shouldn't be concerned with loading files either:

    PHP Code:
    //A basic factory for constructing template objects from files
    class TemplateFileLoader {
        public function 
    loadTemplate($file) {
            return new 
    Template(file_get_contets($file));
        }
    }

    class 
    Template {
        public function 
    __construct($html) {
            
    $this->html $html;
        }


    The view would then do any processing/variable assignment to the template. Where that template comes from is not a concern of the view. The implementation details of how views actually work is beyond MVC but loading a template is definitely a different responsibility to rendering/processing it. The view could load the file, but it does limit flexibility quite severely as the logic contained within the view is only usable with that one template.

    So a view which displayed static templates, would take a template, no model, and simply render it without any additional logic.

    One option is to have the view ask the model for the template file location but then the template must be loaded from the filesystem in a very specific manner by the view. Alternatively you could have the view ask the model for the fully constructed template object. This works, but itself limits flexibility because then the model is supplying both the template and the data that's going to be used in the template. Of course, the model is then exposed to implementation details of the view (it knows the view will use templates), breaking encapsulation. As with most of these things, the simplest, and purest solution in OOP terms is the best. Pass the fully constructed template as a dependency to the view as in my example above.


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
  •