Write your own MVC with PHP

Views accessing datalogic and the DAO? Insanity!

That is certainly not MVC. MVC is pretty clear on who does what and I’m pretty sure Java, .Net, and possibly RoR/Django guys would have a heart attack if a Model accessed the database.

If you’re calling a function in the controller which is getting data from the model and passing it to the view, you’re doing it wrong in most cases and adding an extra, unnecessary step.

But your muddling your separation of concerns. Sometimes adding a Facade layer into your app does introduce duplicated and translation code. The reason you add this Facade is because of abstraction or architecture reasons because you may have to swap out a layer.

A model being coupled to your database layer is really bad news.

I don’t know about the rest of the platforms you just mentioned, but Rails is notorious for using an active record pattern, which couples model to data access quite strongly.

I think some confusion comes from the use of the term MVC, which is perhaps a misnomer. You can’t replicate the MVC pattern properly on the web - owing to it’s stateless nature:
http://en.wikipedia.org/wiki/Model%E2��view–controller
In this example of MVC - the view renders the Model via an Observer relationship - so while the view isn’t manipulating the model, it must be aware of it. MVC wasn’t developed in the context of web applications.

what we use is more like n-tier architecture, layered applications. This looks more familiair to me, and more appropriate to the paradigm of web development.

“A fundamental rule in a three-tier architecture is the client tier never communicates directly with the data tier; in a three-tier model all communication must pass through the middleware tier. Conceptually the three-tier architecture is linear. However, the MVC architecture is triangular: the view sends updates to the controller, the controller updates the model, and the view gets updated directly from the model.”

You can see that for n-tier, the controller handles interactions between the view and the model, whereas TomB’s approach is more akin to true MVC.

CodeIgniter seems to use n-tier: http://codeigniter.com/user_guide/overview/appflow.html

Zend uses Two-Step transform pattern: http://martinfowler.com/eaaCatalog/twoStepView.html

edit: this was in response to Winged Spider

You’re over simplifying it.

The view is accessing the data via the model. The model is the only thing accessing data, how this is done is irrelevant. Again, the model is a layer, not an entity. The model can read the data using a Data Mapper or any other DAO.

I’ll quote the wikipedia article on MVC again:

A view queries the model in order to generate an appropriate user interface (for example, the view lists the shopping cart’s contents). The view gets its own data from the model. The controller may (in some implementations) issue a general instruction to the view to render itself. In others, the view is automatically notified by the model of changes in state (Observer) which require a screen update.

Want a more academic citation?

http://faculty.washington.edu/hanks/Courses/560/s06/Handouts/mvc_observer.pdf

The views know of the model and will interact with the model.
* If a button is clicked an action message might be sent to a model object in order to get something done.

  • If a new value is typed into an entry field an update message might be sent to a model object in order to give it its new value.
     If a value is needed for a display an enquiry message might be sent to a model object in order to get a value.

And here’s a whitepaper on the subject:

http://www.itu.dk/courses/VOP/E2005/VOP2005E/8_mvc_krasner_and_pope.pdf

To maximize data encapsulation and thus code reusability, views and controllers need to know about their model explicitly, but models should not know about their views and controllers.

You can’t replicate the MVC pattern properly on the web

I’d disagree on this point. There’s no reason you can’t keep the state of a model between pages, especially if the only thing the model needs to keep between pages is coming from the database anyway. The only thing that needs to change to accommodate for the web is the controller.

Tom is right, in terms of MVC proper, the view does have access to the model, but it’s a one way street - but…

“In others, the view is automatically notified by the model of changes in state (Observer) which require a screen update.”

It’s that reference to “state” that makes the web implementation of MVC slightly out of kilter with the proper definition - since the web is stateless (although you could probably accomplish this via AJAX (hmmm, interesting). I know you can emulate it, but MVC originates in a different environment, where the database can PUSH data into the view. Any updates to the Model on the web are applied in a new request, so the whole shebang is re-loaded anyway.

Winged Spider is arguing from the perspective of n-tier application design, which is more appropriate to the web - but is not MVC.

@kyberfabrikken - As I understand it - Active Record is one of the few patterns that allow this type of coupling, the exception rather than the rule.

Why not emulate it though? As long as the controller initiates the same things it’s not difficult and the benefits are the same as any other MVC

Take a simple form as an example:

-In model: create form object
-Populate form with existing record data from the database, unless postdata exists, in which case populate from that
-View gets form from model, checks if it’s been submitted and asks the model whether it’s valid
-View can then display a success message and tell the model to save the form data, or it can display the form again + validation errors

All using a controller which handles both requests using something as simple as:


public function edit($id = null) {
    $model = new Model($id, $_POST);
    $view = new View($model);
    return $view;
}

Why not emulate it? Why bother? What’s wrong with n-tier? Surely it’s more appropriate to the environment…

Even within the context of MVC, the View is a passive observer of the model. It shouldn’t tell the Model anything - but it can Observe it’s state. To emulate MVC, the model would have to initiate a new request, or use AJAX.

I really think this is a case of crossed wires. What you are saying is entirely workable (barring the statement above IMO), and is the closest match to true MVC. But most web based “MVC” frameworks are not actually MVC, they’re n-tier (principally Front Controller) - which is in itself a valid (though distinct) design pattern.

In conclusion, I believe you are right, the View should be granted direct one way access to the Model to render data from it. In Zend, that would have to be achieved with a View Helper or plugin, otherwise the variable pointing to the Model would have been setup in the Controller.

You’re correct, sending an update from the view directly to the model is wrong and part of the workaround of a single state application. A better solution is to add an extra call to the model in the controller on every request which, on reflection, may be superior.


public function edit($id = null) {
    $view = new View($model);
    $model->edit($id, $_POST); //checks if the form has been submitted and saves if needed
    $model = new Model();
    return $view;
} 

However, now you need the logic checking whether the form has been submitted in both the view and the model. Which is worse? Repeated code or the view issuing a state change to the model?

Or, another solution, where you’re assuming the form has been submitted in a second controller function may be equally feasible, if slightly more messy imho.

As for why to not use n-tier… MVC gives you much better reusability, seems silly to use an “MVC framework” which isn’t MVC.

edit: Whether you’re using AJAX or not is irrelevant imho, keeping states between pages or XHR is the same problem with the same solution.

matter of opinion really - depends if you’re a purist, or a pragmatist. In Zend you can pass the form object to the view from the Controller i.e:


$form = new Blah_Form;
if($_POST){
//validate, get messages etc etc.
}
$this->view->form = $form;

Changes to the form are updated dynamically in the view.

Yup, it’s just smoke and mirrors, that’s the problem with emulation…

Does that help though? You still need to check in the view whether the form is submitted and valid, and you still need to do it before you save the data from it.

As for “emulation”… that’s not really what’s happening. I’m not advocating storing the model in the session here or anything.

You don’t HAVE to do that in the view (in Zend):

http://framework.zend.com/manual/en/zend.form.quickstart.html - see Get Error Status

But then you have display logic in the controller and lose reusability.

Deciding which view to display is display logic in itself.

Here’s my completely reusable and extendible FormView class which handles all this and contains a switch for whether to display form fields or plain text.


interface FormModel {
	public function getForm();
	public function isValid(Form $form);
	public function isSubmitted(Form $form);
}

class FormView extends View {
	const EDIT = 1;
	const DISPLAY = 2;
	
	protected $submittedView;
	protected $form;
	protected $model;
	protected $mode;
	protected $appendSubmitted = false;

	public function __construct($template, View $submittedView, FormModel $model, $mode = self::EDIT) {
		parent::__construct($template);
		$this->addScript('js/form.js');
		//The view to use when the form has been submitted (and is valid!)
		$this->submittedView = $submittedView;
		$this->model = $model;
		$this->mode = $mode;
	}
	
	protected function run() {
		$this->form = $this->model->getForm(); 
		$this->template->addHook($this->hook->form($this->form, $this->mode));
		if (!$this->mode == self::DISPLAY && $this->model->isSubmitted($this->form) && !$this->model->isValid($this->form)) $this->template->showSection($this->form->name . '_errors');
		foreach ($this->form->getErrors() as $error) $this->template->appendSection($this->form->name . '_error', array('error' => $error));
	}
		
	public function output() {
		$this->run();
		$this->postProcess();
		if (!$this->mode == self::DISPLAY && $this->model->isSubmitted($this->form) && $this->form->isValid($this->form)) {
			if ($this->appendSubmitted) return $this->template->output() . $this->submittedView->output();
			return $this->submittedView->output();
		}
		else return $this->template->output();
	}
}

You can pass it any model along with any template and another view which is used when the form is submitted.

This handles 99% of forms used on all my projects, those which don’t are simple extensions of this class because they need to do something else for example add additional data to the view, in which case they extend the view and add more data to the template in the postProcess() method I have available in all views.

I have similar views for listing records and pagination.

This just demonstrates that there is more than one way to skin a cat. Just look at the different implementations of core design patterns in CodeIgniter, Zend, Cake and Symfony (to name a few).

Each method has consequences that are not always evident on first review.
These consequences are often discovered in the context of the actual project.

Should we always use an ORM for example, or is it simply a choice available to us? In some instances, Transaction Scripts are better than Rich Domain Models, in others, Active Record is more efficient to deploy, although it results in the tight coupling of Models and DAOs. Registry pattern is evil, but sometimes it’s a lifesaver. You pointed out yourself that querying the Model from the View was a workaround, but it increased productivity. Should I deploy a full stack MVC framework for a 5 page brochure site. When you have a hammer…

Design patterns ultimately should enable us to complete a task, not mire us in dogma that prevents us from doing so.

Of course, but design patterns are there and become accepted patterns because they are tried and tested. It also forms a sort of standard making it easier for other developers to pick up your code and work with it. All methods have advantages and disadvantages.

I’m only posting in detail about my own opinions here because several people basically told me I was wrong for giving the view access to the model, even though it’s standard practice in MVC. I just wanted to provide some examples so people can see the pros/cons of this method as many people here just dismissed it out of hand on no real basis (or even gave a real explanation why…) other than it not being what they’re used to.

I’m not saying it’s the best solution for every scenario, but that it does have some distinct advantages (mainly reusability) over other methods.

“I was wrong for giving the view access to the model”

In the context of the MVC pattern (as I understand it), granting two way access IS wrong. In the context of N-Tier, granting ANY access is wrong. In terms of reusability, it may not be. Should you honour the pattern at the expense of productivity?
Discuss…
:wink:

Here I thought that the view should accept the data that’s provided to it and only reach out and touch other view-related material.

2 way access was wrong, and I provided two alternative solutions :wink:

Passing the model to the view for read access is entirely correct in MVC.

I realize the thread has gone away from this, but I wanted to touch on this for just a moment, to perhaps clarify your confusion.

In this case, CustomerType (this looks like Java or C#) would likely be an Enum, which would be defined separately. For example:


public enum CustomerType {
        
    CORPORATE {
        @Override
        public int getOrderLimit(){
            return 1000;
        };
    };
    
    public abstract int getOrderLimit();
}

Would be a way to define the order limit without needing switch/if statements everywhere. It’s actually a much more elegant way to do it, though I don’t know that PHP has anything similar.

I think that’s where the MVC approach people are talking about here breaks down for me - since I would never put input handling in the view. For me, view is just there to SHOW things.

I can see how people coming from visual programming backgrounds could think that way - it’s probably part of why I can’t do visual programming (I can hand code x86 assembly, I can’t use visual programming to save my life) since I know how it ACTUALLY works under the hood - and while the visual interface may hide it from the people pretending to program by dragging stuff around, “view” is called by the controller under the hood, as is keyboard handling…

Take the Windows API for example - wm_actvate, wm_close, wm_create, wm_mousemove, wm_keydown - that’s all stuff I consider to be handled by the CONTROLLER, not the View. That’s user input. wm_paint is the view, and guess what it’s handled by? The controller loop - aka your WindowProc. I’m used to thinking of the loop or main input handler like WindowProc being the controller, since it’s controlling EVERYTHING - calling view OR data handling as appropriate to the user input. The data wants the view changed, it puts wm_paint on the control stack.

If you are just using the controller to set up values at startup, what the **** is it even CONTROLLING?!? That’s not a controller, that’s a LOADER. You have it not “controlling” a damned thing… hence why I’d have user input handled by the controller - makes even more sense in php since all user input occurs BEFORE the code even starts running - why would you even be sending it to the view first in the first place? Much less what the user sends for input could change what model AND what view is loaded - you put it in the view when user input can determine what view is loaded – that doesn’t make a hell of a lot of sense either.

Though I do a lot of programming where the two (view and model) are unchained, operating independantly of each-other for certain tasks…

Which for web development the three tier system is closer to what I’m saying - though inside the program presentation would go last since until you figure out what the user asked for and pull it up, the presentation has nothing to do.

Besides, putting presentation/view as the last thing called AFTER data/model makes more sense should your ‘model’ suddenly want to send cookies or response headers - since once your view starts output, it’s too late to send those.