4

Question

What are the Best Practices on where place the ORM's implementation in a MVC like software application?


I'm using Laravel, with Eloquent, the default ORM.

The documentation alludes to the fact that ORM calls are fine in the Controller, but that doesn't sit right.

For example, let's say I want to get a User. User::findOrFail($id) is the code I need. The documentation has this inside the Controller (Latest version V.10 Basic Controllers.

Imagine I have this bit of code in 100 places throughout the project and I need to hang another check off it, perhaps to get the user who also has a flag against their account. This is a bit of a hassle, but were it in the model I would simply update the model method.

An example model method in this instance:

function get_user_by_id($id)
{
    return User::findOrFail($id);
}

The downside to this is that the models will soon become huge.

So, what is the best-practice here?

Federico Baù
  • 6,013
  • 5
  • 30
  • 38
Mike
  • 8,767
  • 8
  • 49
  • 103
  • 2
    There is an MVC-like mantra that you should aim for "thin controllers, fat models" - so if your database logic is going in the model, that is a good thing. ORM calls are OK in the controller, but I think Laravel (correctly) suggests putting business logic outside of the controller so it can be more easily tested (I think this is known as a Command in Laravel-land). – halfer Jul 06 '15 at 10:42
  • @halfer So you're saying there's a fourth layer? Controllers handle request, Commands handle business logic, Models handle data(base), Views handle presentation? – Mike Jul 06 '15 at 10:43
  • 1
    Yes, that's a good way of putting it. When people started using MVC-ish patterns for web apps, much of the logic would go into a controller class, which was often hard to decouple when it came to unit testing. Of course, the first solution is to make sure any specific functionality has its own class (e.g. an export screen might use a reusable `Export` class) but there is sometimes a "glue" layer that is nice to have in a command outside of the controller. This could return a success/failure bool and perhaps any UI messages for the controller to pass to the view. – halfer Jul 06 '15 at 10:53
  • (I don't know Laravel, but this is my understanding from a bit of reading about it, and from having experienced the problems related to stuffing excess business logic into a PHP MVC controller myself). – halfer Jul 06 '15 at 10:55
  • The glue layer (or Command) will also accept user input from the controller. A good test of whether you have a good glue layer is: "could you switch to Symfony/Zend/Cake/Slim easily?" – halfer Jul 06 '15 at 11:07
  • Have you considered mutators, accessors and scopes? They are in your model and makes such queries in controller much shorter. For much longer queries I suggest repositories. – CrackingTheCode Jul 06 '15 at 22:48

2 Answers2

0

Where should you put?

Ask yourself if you will need to encapsulate that piece of code ever. If you answer yes, put it in the model. Otherwise, go ahead and call it from the controller.

Will they get too big?

Eloquent models already include so much functionality since the ORM utilizes active records pattern, and not data mappers like Doctrine. So your models probably won't get too big since a lot of the functionality is already inherited, and you'll rarely need to write your own.

Will you be happier with more control over the structure?

If you're too worried about the database layer's structure and want to apply separation of concerns principle to the heart, use Doctrine instead. So you'd feel better. But I really think Eloquent should be fine for most cases.

Ilyas Serter
  • 810
  • 1
  • 8
  • 12
  • Advicing Eloquent over Doctrine , this or that I don't this is the problem or solves anything. A part that we are making assumptions here and maybe not even too correct. Why couldn't Eloquent have a huge model? I mean I saw it, off course it can grow :D The problem here is not really relative to a specific ORM or Framework (unless the framework is very opinioned and don't follow the standars) which is not the case with eloquent - laravel. Root question goes for any MVC architecture – Federico Baù Apr 26 '23 at 05:25
0

TL;DR

ORM sits better on the Model

This question is relative to PHP - Laravel, but really, it's a problem or any software that follows the MVC design. Laravel, is a quite opinioned Framework and the structure that it has by default is just better be followed, however it follows very well the MVC design.

Now, from the mdn docs above

  1. Model: Manages data and business logic.
  2. View: Handles layout and display.
  3. Controller: Routes commands to the model and view parts.

Already from this, we can understand that, the best place is the Model. Now, why does Laravel says that "ORM calls are fine in the Controller"?

My guess is because, to be more flexible for the users and for easier explanation on the documentation, Laravel is a great framework which is used by both experience and beginners (or comanies that don't work very well) so the documentation is very user friendly.

I saw companies putting more business logic on the controllers and models are simple opaque
Classes, using a combinations of DTO - Data transfer object and Domain Models and combinations of these:

I also saw companies where, the Model, is used as simple DTO (or call it whatever, just a class with no logic where has only fields that matches the sql table)!

Now, using a ORM, changes a bit the game, since, is a combination of the above plus, makes you able to perform sql queries on a Object Oriented approach.

You could decouple the Model from your actual ORM implementation as is suggest in here In MVC, does an ORM represent the model?:

ideally you'd want to decouple the shape of the Domain Model classes from the shape of the database tables.

However, putting on the Model, could be a good start, but on the Controller is a bad practice

In here, how to structure MVC models and ORM models, is quite interesting since they are talking about Entities which are DTO but with a cooler name.

Related

Federico Baù
  • 6,013
  • 5
  • 30
  • 38