How complex should models be?
When implementing models using the MVC pattern, how complex should my models be?
Let's say I have got a few tables like so:
- User (id, password, created ...)
- Emails(user_id, email ...)
- Addresses (user_id, address ...)
I have got a controller called UserController. This controller should allow me to log users in, create users, etc.
<!-- language: php -->
class UserController{
public function create($array){
...
}
public function login($email, $password开发者_StackOverflow中文版){
...
}
}
Should my models be very primitive, implemeting only CRUD operations via ORM? This would result in code like:
<!-- language: php -->
class UserController{
public function create($array){
$userModel->username = 'blah';
$userModel->blah = 'blah';
$id = $userModel->save();
$emailModel->id = $id;
$emailModel->email = "emailhere";
$emailModel->save();
//Do the same for addresses
}
public function login($email, $password){
...
}
}
Or, alternatively, I could have models that are more complex:
<!-- language: php -->
UserModel{
public function login($email, $password){
//Do the joining and checking here, then return true or false to the controller
}
}
Then in my controller:
<!-- language: php -->
userModel->login($mail, $password);
So, which is the better way? To stuff all the logic into models, or should I have models doing only the basic CRUD operations? Finally, how do I deal with table joins? Should they be dealt within the model, or in the controller?
Cheers
Most people think of the "Fat Models, skinny controllers" paradigm, and it works better in the long run.
A great rule of thumb is to think about your Models as their own entity, in the sense that if you were to move your models to a different framework for example, they would still be functional.
A simple example would be saving information about an order on an e-commerce website. Let's say you want to save information about Tax, namely how much Tax is on the order. An abstract way of doing this is...
$tax_amount = $order_amount * (TAX_PERCENTAGE / 100);
Should we do this in the controller or the model? Suppose we did it in the controller, well... in our create action and our update action we would be calculating the tax, which makes for harder to maintain code and should the business rules of the e-commerce website change (say, we start selling to Tax exempt businesses or overseas business) then we would have to change any controller that saves order information.
If we were to calculate Tax in our Order model however, we would be doing it once in our save() method, which would be called when editing and adding orders.
public function save() {
//calculate tax first
$q = $this->db->query($sql);
}
Imo, it's better to enforce business rules in your model because it makes for more portable code and far less headaches when it comes to maintaining your code. Of course, there are people who will disagree, and this is a very subjective area.
EDIT:
Applying this to the specific question you asked, think about whether you would ever need the login()
method anywhere else but your User model? It's possible you might want to split your models into different, more specific ones. But you could extend from your User model in that case.
What about if you were to take away your controller completely? Or if you wanted to interface with your models in an entirely different way (say via a different framework in the future). Thinking in this way you would be far better off with your login method in your User model.
Personally, I would be creating a login method on my model because it is an operation on data and that is what our models are for. I would also be creating a loginAction()
method on my controller which would initiate the login()
method on our model and perform any other action (for example, log failed attempts/redirect) that has to happen on post-login, should it be successful or unsuccessful. An example loginAction()
may look as follows...
class UserController extends GenericController {
public function loginAction() {
$post = $this->form->getPost();
if(UserModel::login($post)) {
//do something
} else {
//do something else
}
}
}
All functionality which will or could be reused at different parts in the application should be accessbile globally, so that the coupling is low and there is no need to redeclare it.
I think you need an additional model for authorization and/or the current system parameters. The AuthModel could store information about the different authorization roles and the SysModel stores application parameters like the default login settings (e.g. use cookies yes or no).
The login method could be placed in the AuthModel then, which should be a good place in my opinion. Also the models are responsible to validate the inputted data, so the creation of new users should be in the UserModel.
精彩评论