Page 1 of 1

MVC practices

Posted: Mon Dec 03, 2007 7:04 am
by shiznatix
Ok this is not quite the typical question about MVC. I have made my own framework that uses MVC and runs perfectly fine. Due to silly bosses being influnced by even sillier Finns I have to chance frameworks to something that is more commercial "just because".

I chose Zend Framework because I want choice. I want to be able to do things the best way, not what I am told is the best way. Insert other arguments here.

Now the problem is that with my framework (NFW), I did things like this:

page: news.php
view: news.view.class.php
controller: news.controller.class.php
model: news.model.class.php

When you went to news.php, it would check if you have an "action" set or a "view" set. Actions are specifically reserved for things like updating the database, inserting new rows, deleting data, the kind of stuff that changes data. All actions are in the controller class so if you did news.php?_action=update&title=new_title&id=35 then you would hit the "update" method in the controller class and update the title to "new_title" where the id is 35. Then, if no view is specified, you are sent to the main() method of the news.view.class.php class (if you supplied a view, you are sent to that method).

In the view class I assign variables and everything that is going to be in the template. So I will set the page title, grab a list of the news (depending on the method i am in) and set all these variables to my templating class which is actually just PHPtal. Then PHPtal itself opens up the correct template file and throws the variables at it and everyones happy.

The model class just stores the table name and the table fields (and maybe what is the primary key and whatnot). Nothing big. I do use the model to execute all my queries though as every model is linked to my database class.

Fast-forward to me trying out Zend Framework!

It seams like they want to combine what I do in the view and in the controller all into the controller class. Then the "view" is only the template. This seams silly to me because I am used to separating my code to make it easier to maintain. If I want to change what happens when you click "submit", I change the controller. If I want to change what happens when you click on the news headline to read the whole article, I edit the view (and possibly the template).

Now, when I go to import everything over to the Zend Framework, I already have views that are about a thousand lines long and controllers that are the same. Does it make sense to combine my view and controllers together into 1 controller and just do it or am I missing something here? Should I move what I have currently in the view to the controller, and then what I have in the controller to the model? What would make sense here?

Posted: Mon Dec 03, 2007 8:07 am
by Maugrim_The_Reaper
I suppose the first observation is that in MVC the V and C are always going to be close relatives ;). Both your approach and Zends are equally valid - they separate Model from Presentation.

The problem is where the dividing line is between C and V. Zend pushes the View to be as limited as possible; literally a template engine and nothing more. That's changed recently (Zend_View Enhanced/Zend_Layout) but the changes are reasonably slight and just enough to decrease a lot of repitition in organising how Views are constructed.

The second observation is that gigantic controllers - whether in your MVC or Zends - are smelly. Any action over the typical 100 line limit should be considered suspect (maybe it should have code refactored to an application specific class library?).

From your description you see a View rendering a template, by assigning one or more Models. The Zend way it's slightly different in that the Controller handles the assignation of Models to the View (template). This can lead to a lot of duplication, which your own system probably avoids, but you can do things like View Helpers, Layouts and Composite Views to get around that (see the most recent View code for Zend in it's "Incubator").

I would probably start by moving some of your View logic (regarding setting template vars) to the controller, or (if it works; it works) just replacing Zend_View with your system and be done with it. You'd need to disable or subclass the ViewRenderer action plugin to shut down or replace the hooks into Zend_View but it's not that difficult. After that you should have a better idea of what to do - move controller logic to a class library where possible (less controller code to read now), move more to the Model (any sort of Model manipulation, searching, retrieving, business rules or rule validation, etc.), and hopefully that will leave only the hardcode can't be moved stuff a controller should contain.

Posted: Mon Dec 03, 2007 9:33 am
by shiznatix
I don't think I want to replace too many things from the Zend Framework to begin with. I already did replace the Database stuff because I could not get it to work (see my post in general discussion) but I am going to try to go back and fix that problem.

I suppose I should start moving everything from the NFW view to the Zend controller. This is not that big of a deal since the largest chunks of the code come from sql statements that i did not design my modelBase to be able to make for me automagically. I have all my "get all this data and put it into a neat array to send to phptal" in private functions in my view class so what do you suggest I do with those? just move the functions as-is or...?

The majority of my controller functions are error checking, the actual add or update methods are just like:

Code: Select all

$this->USERS->auto_set($_POST);
$this->_check_errors();

if (false == $this->is_errors())
{
    $this->USERS->save();
    //redirect
}

$this->set_view('add');//will show the views add method with all of the errors that where produced durring $this->_check_erorrs() such as "Invalid Username Supplied"
So I suppose I can keep the _check_errors() for each controller private still or is there a better way?

Posted: Mon Dec 03, 2007 2:22 pm
by Christopher
I would recommend against combining your Controllers and Views. From rereading your post, I think the reason that you are having problems is because your Models are not actually separated into a layer. It sounds like your "actions" are actually Models with some controller code leaking in. That is a Transaction Script, which is a design choice, but I think in the long run you will want to make that separation into a clearer layer separation.

My recommendations for how to proceed, both in your case and in general for building PHP web applications, is:

Step 1. Divide you code into at least a 3-Tier architecture. The lowest level is the for Data Sources (your current models) for connection level support. The middle layer is for Models and all the domain/business logic code. The top layer is the Presentation containing the code that gets the Request, decides what to do, and generates the Response (i.e., HTML, XML, JSON, whatever). Remember, lower layers cannot have any dependencies on upper layers (unless you are an expert and know the exceptions).

Step 2. Use a Front Controller to centralize common application code and use Action Controllers provide a common structure for the program flow logic of the website. The FC will help you with DRY and allow to do some good inversions/injections as you get into it. The ACs make the organization of your code match requests and therefore RESTful; it also allows you to focus on the page specific code by removing a lot of code that would be cut-and-pasted or included in every page.

Step 3: Find the line you want to draw between the program flow code (Controller) and the output generation code (View). It may not be in the same place in every application, or even in the same place in every module within you applications. Just be aware of where you have drawn the line and monitor it as you will want to adjust it as you learn more. That line is a powerful convention that helps you simplify things by letting the parts make some basic assumptions.