views:

139

answers:

3

I'm about to do a PHP website using the MVC pattern. I am not using a framework as the site is fairly simple and I feel that this will give me a good opportunity to learn about the pattern directly. I have a couple questions.

Question 1: How should I organize my views? I'm thinking of having a Page view which will have the header and footer, and which will allow for a Content view to be nested between them.

Question 2: If I have 5 Content pages, should I make 5 different views that can be used as the content that is nested within the Page view? Or, should I make them all extend an abstract view called AbstractContent?

Question 3: What about controllers? I think there should be one main controller at least. But then where does the request go from there? To another controller? Or should I just call the Page view and leave it at that? I thought that controllers were supposed to handle input, possibly modify a model, and select a view. But what if one of the views nested within the view that a controller calls requires additional input to be parsed?

Question 4: Are controllers allowed to pass parameters into the view? Or should the controller simply modify the model, which will then affect the view? Or is the model only for DB access and other such things?

+1  A: 
  1. Think about what ways you'd want your HTTP responses to look like: full pages with/without nav, stripped pages for printing, JSON & XML responses, an index/sitemap. After you feel the site is forming, add more and more shortcuts for getting your response out there with as little code as possible.
  2. If the page layout is similar, I would use the same view and load content into it from a model (possibly a database).
  3. Check out the Front Controller pattern: you should always be able to intersect the request in a single point of entry. I would put something hierarchally in front of your controllers and then have one controller per "main page" (forum, blog, news). This is sufficient to control, but you'd have to decide what chunks are large/small enough for you.
  4. Controllers are responsible for everything that gets passed into the views. Controllers should fetch data & settings & what-not from models and pass on to the views.
chelmertz
This is helpful; +1 :). But I thought the controller makes changes to the model (ie updates the db etc) whereas the view fetches data from it (like in this diagram: http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller). Is that not the case?
Cam
I read more carefully now, you said "I thought that controllers were supposed to handle input, possibly modify a model, and select a view." which I agree with, so yes!
chelmertz
So the view should be able to fetch data directly from the model? For example could I have the controller modify some user settings, and have the view fetch those settings from the model (the mdoel would of/c provide an easy-to-use interface for that)?
Cam
I'd rather have a controller in between a model and the view at all times. Both methods are valid I guess but I'd prefer to only handle UI related logic in the view, not being in charge of making new calls to the model (directly).
chelmertz
+2  A: 

Question 1:

This is indeed a way to do this, and one which I allways use.

Question 2:

Just keep views as simple as possible. I tend to create just 5 separate views (plain php files).

Question 3:

In the normal mvc pattern, there is one front controller (which OS just a bootstrap file, the index.php) which executes one controller.

In HMVC, controllers can send additional request to other controllers.

Question 4:

The normal MVC pattern applies on normal apps, where views are persistent, and can observe the models. With web applications this is not possible, because every request everything is reloaded. So the most used pattern is to let the controller pass the parameters to the view.

Ikke
+1, Thanks. 1, 2, 3 make sense. For 4, it's good to know I can pass parameters to the view. However can I also have the view interact with a model to get info from the DB, or should that all be provided by the controller? Also - does each view specifically need one controller and one model exactly? I was thinking more along the lines of having one controller per view, and one model per thing from the database I need to abstract.
Cam
+2  A: 

1 - This is a matter of preference. The simplest way would be to have a separate header and footer file. Then you could do something like this in your page controller

$title="Page Title";
$var1 = 'var1';
$var2 = 'var2';
$var3 = array("asdf","adsfasdf","234");    

include(HEADER); //$title is in header
include(DIR_VIEWS . 'page.php'); //$var1/2/3 are in page.php
include(FOOTER);

// variable were created before pages were included so they will be set in the templates

If you were to go the nested route you would have to start fiddling with str_replace and that starts heading towards a template engine, out of scope for this answer.

2 - No need to make views objects. A "view" can just be a file on your filesytem that contains the html for that view. Like my example above. These pages can contain basic php to loop/echo variables as well.

3 - You are describing a front controller (sometimes called dispatcher or router). This is really the way to go. There are a couple methods for creating a front controller.

You can have an array of urls that point to controllers.

$routes = array (

    '~^/home/$~' => 'home.php',
    '~^/contact/$~' => 'contact.php',
    '~^/blog/.*?$~' => 'blog.php'

);

or you can use the first "directory" in the url as the controller name and load that file form your controller directory.

4 - The entire point of the controller is to get info from the model and pass the data to the view.


Edited for comment


If you want a bunch of views to have a sidebar you just include that view in the other view. For example:

<div id="content">
    <p>lorem ispum stuff</p>
</div>
<?php include(DIR_VIEWS . 'sidebar.php');

Just make sure that in controllers that "control" pages with sidebars you include some code for sidebar functions:

if ( $_GET['keywords'] ) {
    $sidebar_search_results = get_search_results($_GET['keywords']);
}
// this code should be in a file that you include

$sidebar_search_results could be an array of results that your sidebar view parses and displays.

Galen
For nested views, I think my problem is this: What if I have 4 very different views - but all of them do share one common element (let's say a News panel). I would like to make the News panel a nested view within each of the 4 main views. The problem is that the News panel needs to get data from somewhere. And what if the news panel has a search feature? Then it would need a controller too, to make sure the search parameters are being handled. How could I do something like that?
Cam
@Galen's "Edited for comment": With nested views, the idea is that the views should be fairly independant - that is I'd like to be able to switch them out at a moment's notice. This way though, I'm adding unecessary code to the controller at the top, which could become very annoying if I have too many deeply-nested views. What do you think?
Cam
If you have a search function you're going to need code to do the searching. Thats going to have to be in the controller no matter what. If you need to switch the layout of the sidebar, you just overwrite sidebar.php with the new code.
Galen
Gotcha. I guess if multiple controllers use the same search code, it's a simple matter of putting that code in a functions file or something. Thanks :)
Cam
yes put it all in a separate file and include it.
Galen
and remember this is just one way to do it, and a simple one at that.
Galen