George
George

Reputation: 47

PHP MVC Principles

I'm not using an off-the-shelf framework and don't particularly want to (nor d I want to go into the reasons why...). Anyway, onto my question(s), I hope it make sense....

I'm trying to get my head around what should go in the model and what should go in the controller. Originally I had the impression that a model class should represent an actual object (eg - a car from the cars table of a database) and model properties should mirror the database fields. However I'm now getting the feeling that I've got the wrong idea - should an instance of a model class represent an actual item, or should it contain a number of methods for doing stuff - sometimes to one car or sometimes to multiple cars based on my example earlier.

For example I want to get all the cars from a the database and show them in the view. Am I right in think it should be along the lines of this?

Controller File

function list() {
    $cars = $this->model->get_all();
    $this->view->add($cars);
    $this->view->render('cars-list');
}

Model File

function get_all() {
    // Use a database interaction class that I've written 
    $cars = Database::select();

    return $cars;
}

Now, if the car had a "status" field that was stored as an integer in the database and I wanted to change that to a string, where should that be done? By looping the SQL results array in the get_all() method in the model?

Also, where should form validation live? I have written a validation class that works a little like this:

$validator = new Validator();    
$validator->check('field_name', 'required');

If the check fails, it adds an error message to the array in the Validator. This array of error messages would then get passed to the view. Should the use of my validator class go in model or the controller?

Thanks in advance for for any help anyone can offer. If you know of any links to a simple MVC example / open source application that deals with basic CRUD, they would be much appreciated.

Upvotes: 3

Views: 804

Answers (4)

hafichuk
hafichuk

Reputation: 10781

I would highly recommend you take a look at "Patterns of Enterprise Application Architecture" by Martin Fowler. It has a good explanation of what each of the separation of responsibilities are for each of the MVC components (plus a lot of other useful patterns).

In a pinch, wikipedia has an okay explanation of MVC.

In short, the structure you've setup is correct. You're controller is informing the model that some event has occurred, the model is reacting to that event, then the view is using the model to represent the state of the system to the end user. The validation should be performed within your Model, since it is responsible for maintaining the correct state of the system. You may also have some client-side validation which is strictly there to reduce network traffic and provide a nicer interface for the user.

One thing to keep in mind is that you want to keep your business logic within the Model. You want to try to avoid what's called an anemic domain model. This is pretty typical when your model is just a thin veneer over a database.

Another book I would recommend is by "Domain-Driven Design: Tackling Complexity in Software" by Eric Evans. The focus with DDD is that "the primary focus should be on the domain and domain logic".

Upvotes: 4

GordonM
GordonM

Reputation: 31730

The general breakdown of responsibilities in MVC is generally as follows:

  • Model: Business logic. A lot of people think the model is simply an interface to the database, but this is incorrect. The models in your system should describe all the entities in your system, how they behave and how they interact. Data access is only a small part of this (and arguably should even be partitioned off into its own data-access layer separate from the model, view or controller). For example, in a blogging application, a blog will have a collection of posts, and each post may have (depending on the features the blogging app implements) a collection of comments. This would mean implementing a blog class, a post class and a comment class. Should you choose to delete a post, then it's the responsibility of the post to ensure it doesn't leave any orphan comments behind. You'd do this by having a method in the post class for deleting a post, and a similar method in the comment class. When the post gets sent the delete message, it will as part of the deletion process send a delete message to all the comments associated with the post being deleted.
  • View: Presentation logic. A view is basically a web page, an RSS feed, a CSV file, in fact any kind of data that your application might output to the end user. It should just display the variables that have been assigned to it. (It is okay to implement some logic in the view provided it's to do with outputting data. Views don't have to be completely dumb)
  • Controller: Glue logic. The controller has basically two jobs to do: 1) Take data from a model, inject it into a view and present it to the user. 2) Take input from the user, send it to the appropriate model for processing and present the results to the user. This means that the controller should contain very little code, just what's needed for achieving the two goals listed above.

As I already mentioned, many people think the model is little more than a data access layer. You can usually tell when people have followed this design philosophy because the result is models that don't do a lot, and controllers that do too much (the so called Fat Controller anti-pattern). The problem with this approach is that if you want to reuse portions of your codebase in some other project, then you can't take the model over to the new project without taking a big chunk of the controller along with it. Controllers are generally considered to be application-specific and therefore non-reusable. Models, on the other hand, embody entities in your application, and you might have several applications that require the use of the same type of entity (Blogging software, e-commerce storefronts and message boards are all very different applications, but they all need to implement users).

Generally, you want fat models (which can be easily reused without copying code not implemented in the model itself) and skinny controllers (that can easily be replaced when you need your model to do something else).

Validation kind of throws a spanner in the works though, as it's what's called a cross-cutting concern. The idea of MVC is one of separation of concerns as it aims to characterize code as falling into one of 3 major categories (business logic, presentation logic, glue logic), but validation doesn't easily fit into any of those. Good arguments can be made for it being both business and glue logic, and if you want to display validation errors to the user, then it's also got an element of presentation logic as well.

Generally, I implement a level of validation in my models, generally fairly basic sanity checks (such as requiring that integers are actually inter values and the like), and implementing a separate set of classes for doing full validation of input. I'll invoke the validation classes in my controller and if validation fails there I'll present the results to the view. If it succeeds then the data gets sent to the relevant model for processing. I suppose you could call validation "utility logic", something you need to do in a regular basis that you can't really tie to any one model, view, or controller.

Upvotes: 4

Uladzimir Pasvistselik
Uladzimir Pasvistselik

Reputation: 3921

First of all, if you don't want use any PHP framework, you can look at their sources and get good ideas about some features implementation.

What about a validation, I think that it is a business-logic feature, so it must be placed at the controller layer. (edited: that is bad idea)

Upvotes: 1

maraspin
maraspin

Reputation: 2393

If you want the status field to be treated as a string within your application, you don't want the persistence detail of having it as an integer in your db to creep out from the car class. In its interface it's a string and as such it should be treated.

So, I'd use a getStatus() method in the Car class, which you'd invoke AFTER the getAll(), whenever you'd need it. You'd be delegating the cast at item level. It's better not to let the rest of your application to know that you have an integer at the lowest level. Expose a string from car and live on with it within the rest of your application.

As for the validation, I'd do it in the controller. You get stuff from the view and make sure it's good enough for your model. Unless it's a check which specifically needs to be made within the model (IE business relate constraint).

Upvotes: 1

Related Questions