BadHorsie
BadHorsie

Reputation: 14544

MVC in CakePHP 3 - Separation of concerns between Model and View

This is a general question about MVC, but the context is CakePHP.

The Cake documentation largely avoids discussing optimal placement of model-related code, such as queries. Perhaps for simplicity's sake, or to avoid imposing any ideas on how the developer wants to structure their app, they simply always document queries as being in the controller. Essentially, a Fat Controller pattern.

e.g.

The page requires 4 large queries to show different areas of data in the view "XYZ". The end result of the queries is a very specific set of data just for view XYZ.

Fat Controller

In this situation, the controller is doing all the work and is simply leveraging Cake's built-in model framework features to query the correct tables. The model layer itself contains no custom code.

So the alternative is to use a Fat Model pattern, but then I don't feel that's correct either, particularly where the model is determining which data will be sent to the view.

Fat Model

This keeps the controller nice and clean, and it only serves to handle the request, delegate the retrieval of the data it needs and then forward it to the view.

The problem with this, for me, is that the model layer (probably in table classes) now contains very specific queries which retrieve data specifically formatted for view XYZ. If I want to change the data shown in view XYZ I make those changes in the model layer by modifying the methods which return the fields the view needs.

This seems wrong, and leads to large models which are bloated with tons of very specific functionality.


Question

Controller

Model

Is there another layer which can bridge the gap between the controller and the model tables, or is it pointless? What would it be in a Cake context? Custom classes outside of Tables or Entities? I fully understand that the model layer does not just mean active records or database querying.

Upvotes: 2

Views: 668

Answers (2)

Ali Asgari
Ali Asgari

Reputation: 841

Also there are Components for collaborating controller codes in classes and helpers to collaborate view codes in classes. So to make your controller slim you can add components for each job and use them in controller instead of doing all the stuff in the controller actions.

It has another advantage. If you put repeatable code in components then you don't need to duplicate them in each view and you stay observing the DRY (don't repeat yourself) principle.

Upvotes: 0

floriank
floriank

Reputation: 25698

The Cake documentation largely avoids discussing optimal placement of model-related code, such as queries.

This is not required nor the duty of the framework to educate people about design patters - IMHO. The layers and their duties are explained here. For further information use Google or read Martin Fowlers publications about design patterns.

Perhaps for simplicity's sake, or to avoid imposing any ideas on how the developer wants to structure their app,

Yes. You're free to do whatever you want but it is expected that people are at least familiar with the basics of MVC, OOP and design patterns in general. It is not the job of the frameworks documentation to teach these topics.

they simply always document queries as being in the controller. Essentially, a Fat Controller pattern.

Who are "they"? I'm sure the documentation does't encourage bad practice or anti patterns.

The problem with this, for me, is that the model layer (probably in table classes) now contains very specific queries which retrieve data specifically formatted for view XYZ. If I want to change the data shown in view XYZ I make those changes in the model layer by modifying the methods which return the fields the view needs.

Your methods are very likely to fat then and to specific. You won't be able avoid specific methods (there is always something that can't be made generic) but you should compose what they do using many smaller methods that are generic. A method should always do just one thing and do it well and the best not longer than ~80 lines.

Custom finders in Cake3 are a great way to compose queries:

public function findIndex(Query $query, array $options = [])
    return $query->find('active')->find('index')->find('somethingElse');
}

We have a lot "active" checks in our app so I put the active finder into a trait and use it where I need it. The other two finders add additional stuff to the query. I'm combining three finds that can be used alone or combined differently for whatever is needed.

In your controller then just call $query = $this->Articles->find('index'); and pass it to your paginator.

Also never forget that "model" describes a complete layer and not just table objects. Cake2 probably caused that less experienced developers might have gotten the impression that model == table. We have several namespaces in App\Model that aren't related to DB actions at all or use table objects for something to get their task done.

Upvotes: 2

Related Questions