Fat Model Thin Controller

Hi everyone,

I am relatively new to web programming, PHP and MVC framework.

I came across an interesting concept in coding Models and Controllers.

It’s called FAT model and THIN controller.

The idea is to have business logic coded in model instead of controller.

Sounds like a good idea. Controller cant call another controller

but it can call multiple models.

To me, a system’s logic can be classified as application and business logic.

I think FAT model will contain business logic while THIN controller will contain application logic.

What do you think?

1 Like

This is also what Yii recommends.

I have done many applications with this style, and it really makes things expandable and portable.

One problem that I have found with this method is programmer stupidity, though. Some programmers do not have the ability to wrap their minds around a “Model” that is not just a wrapper of a database table. This concept is a little easier in Yii since the base class ‘CModel’ doesn’t have anything to do with the database.

For enterprise application, I try to separate my "Model" into 3 layers: Business Logic, Unit Logic, and Database Logic. The controller can only access the Business Logic layer, which can only access the Unit Logic, which can only access the Database Logic.

In this way, you can make generic functionality in the Business Logic, that then interfaces with the many different units in your system (users, business, etc), that then does whatever database interaction that is required.

For most projects, though, that approach is a little heavy.

I am, however, a fan of the Thin controller, Fat model concept.

Thanks for the reply. I am trying to implement this concept in my project now.

But I ran into some design dilemma.

I have a model that has a set of methods (like a mgr component).

getBooks(),

updateBook(),

newBook(),

deleteBook(),

Where should I validate and how should I pass my data to the model?

1. Inside controller.

I do a mass attributes assignment in my controller, call model->validate() and then updateBook() with no parameters pass in.

2. Inside the model by parameter.

I pass the data to the model via an array, Eg. updateBook(array(…)) and call $this->validate() in the model.

3. Inside the model by $_POST[].

I get data by getting $_POST[] in my model method, validate and save.

All 3 methods has it’s pros and cons.

method 1.

pros - easy assignment, and validations.

cons - if I share my model’s method, the other developer must know to do assignment and validations before calling my model’s method.

 - my controller is still quite fat.

method 2

pros - method signature is very clear.

cons - a problem if I have a huge attribute list to pass in as parameter.

method 3.

pros - easy assignment. no need to pass huge array to my model’s method.

cons - having $_POST in my model’s method will hinder code reusability.

Which method should I adopt to realize the Fat model Thin controller concept?

You could combine methods 2 and 3 by defining an optional parameter that defaults to using $_POST when unspecified.

Thanks Sander for your suggestion. That’s another new way by combining method 2 and 3.

But I really wish to know which method is the recommended practice.

Hi Qiang, you mentioned that Yii advocates Fat Model Thin Controller approach but so far the tutorials in Yii have all the logic coded into the controller. It would be great if the cookbook can showcase an example of Fat Model Thin Controller concept.

for me the generated files of yiic shell>> crud Model are reflecting this concept

A thin controller still needs code to "glue" together user requests, models and views, and that is the purpose of controller anyway.

Your approach 1 and 2 are both fine, approach 3 is in appropriate because the model should avoid dealing directly with user request data such as $_POST or $_GET (what if you want to use the same method in a console application to insert/update data?)

In general, the goal is to separate the responsibility of models and controllers and to maximize the reusability of your code while still maintaining sufficient flexibility.

Approach 1 does introduce certain degree of writing repetitive code in the controller (checking $_POST, assigning attributes, validating and saving). However, this redundancy is offset by the flexibility it offers, because you can freely combine all these steps in your controller to implement various actions. If you really feel like to remove this redundancy, you can also consider implementing them in a base controller class.

Approach 2 is nice because it further encapsulates the aforementioned steps. The drawback is that this encapsulation doesn’t do much and you are forced to write a new method in the model.

I agree with Qiang.

I think “FAT model and THIN controller” is a easy principle just when you can’t make a decision about responsibility of models and controllers.

Maybe "FAT model" make model class more reusable. But it will lost some flexibility and performance. It will be a heavy loading when you reuse a very FAT model class.

Hi mbi,

I think yiic shell>> crud Model doesnt generate codes that reflect Fat Model Thin Controller concept.

The generated codes in model are very thin and the generated codes in controller does all the logic and stuff.

I think Fat model means having all the DB codes in the model class. Controller just have to call the model methods to do it. Eg. Controller call $model->saveBook(array(…));

Hi Qiang,

For approach 1, it seems like I am implementing Fat model Thin controller for the sake of implementing.

Eg. MyController has a method call actionAddNewBook()

Hi Qiang,

For approach 1, it seems like I am implementing Fat model Thin controller for the sake of implementing.

Eg. MyController has a method actionAddNewBook()

public function actionAddNewBook()


{


  //check POST.


  //assignment of attributes to model.


  //validate model.


  $model->newBook();


}





MyModel has a method newBook();


public function newBook()


{


  $result = $this->save();


  return $result;


}

You can see that the newBook() method in MyModel class does minimal stuff. I could have implemented the save() in the MyController class.

For approach 1, the minimal code needed is as follows:




public function actionInsert()

{

    $model=new Post;

    if(isset($_POST['Post']))

    {

        $model->attributes=$_POST['Post'];

        if($model->save())

            // ....

    }   

    $this->render('insert',array('model'=>$model));

}



It’s certainly true that your newModel() method makes the above code one line less and probably a bit more readable. If you expect this newModel() method will be used in many places, it would make sense to implement this method. Otherwise, implementing newModel() doesn’t bring you much benefit because you end up writing a new method (more code) and the approach lacks certain flexibility (e.g. what if you want to implement the preview feature?) That is why I said both approach 1 and 2 are fine, depending on the need.

The so-called fat model has much more than newModel(). Following the fat model criteria, things like the validation rules, the logic to execute before and after save a record, the methods for data retrieval or saving (your newModel() method is an example) should all be placed in the model.

If you read the document of yii or read the source code of CActiveRecord, you will see the model created by yiic shell which can do the all thing. Not just you see in the code.

Your model class extend from CActiveRecord class. It will include all methods which defined in CActiveRecord.

You can do auto validation in model. Refer this document Creating Model

And check the source code in yii/db/ar/CActiveRecord.php