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

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
Controller handles request
Controller runs query on model 1
Controller runs query on model 2
Controller runs query on model 3
Controller runs query on model 4
Controller performs additional logic on data
Controller sends data to view XYZ
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
Controller handles request
Controller calls on model 1 to retrieve data
Model 1 queries and performs additional logic on data, sends back to Controller
Controller calls on model 2 to retrieve data
Model 2 queries and performs additional logic on data, sends back to Controller
Controller calls on model 3 ...
Controller calls on model 4 ...
Controller sends data to view XYZ
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
Which approach is better?
Is there a third solution to this which allows the following separation of concerns:
Controller
Handles the request
Decides which data the view will need, but delegates the job to the model
Forwards the data from the model to the view
Stays thin
Model
Handles all business logic and database querying
Database query logic is ignorant of what the view requires
Is not bloated with specific one-use functionality for specific views
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.

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.

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.

Related

CakePHP: Queries in Controller or Models?

If I really go through the MVC approach, then the queries should be in the Model, in CakePHP case the Table Classes, but when I go through the tutorials and documentation that Cake Provides they simply state that queries should be in the Controller.
As you can see in the example over here on Cake's websites: https://book.cakephp.org/3.0/en/tutorials-and-examples/blog/part-two.html
But if I go through this link or many other I have come across, the query part should be in the Models: https://www.toptal.com/cakephp/most-common-cakephp-mistakes#common-mistake-3-keeping-business-logic-in-controllers-instead-of-models
It is not just about what Cake displays in the examples or some developers opinion, but what should really be the genuine way to code in Cake when dealing with database queries. I have found almost 90% people doing query related tasks in Controllers only for Cake, as they quote "Cake mentions the same in their examples". But what about the MVC way, we create Table Classes just to mention the associations then? If Cake's own website does that, then somehow it means they have done it intentionally.
It's a good programming practice that to use your database queries in your Model because you can reuse these queries(In another controller) later by calling the method using the object of the model. However, you can also write your queries in your Controller.
For example:-
//Consider this code block is in Products Model
function totalActiveProduct(){
$totalProduct=$this->find('all', ['conditions'=>['is_active'=>'Y']]);
return $totalProduct;
}
If you want to get the total active product in any controller you can do this,
$this->Categories->Products->totalActiveProduct(); //Total procuct in category controller
$this->Products->totalActiveProduct(); //Total products in Product controller.
Actually, when you are writing the query in you controller, you have to use the object of your model(That means indirectly you are using your controller). You are thinking that you are writing this in your controller but actually, you are writing it in the model(Object of Model).
$this->Products->find('all');
Simply this means you are writing this in your model object(Where Products is the model object). Directly or indirectly you are doing your each and every database operation through the Model.

Issue with base class that gets extended by both Models and Controllers

I've got a question regarding a conflict / conundrum I've run into with my application.
I want to make some common "stuff" available to all of my models and controllers, such as data from a cache, or session information, as well as the methods of my PDO wrapper.
Currently each individual feature controller and feature model extends a base controller and base model, which in turn extend a single object that does all of that common stuff.
A controller will get called by a router/dispatcher, and the controller will then call on a model to get some data. The problem with this is it means the main Object gets constructed twice: once when the feature controller is called, and again when the feature controller calls the feature model.
See the diagram below:
Obviously I'm doing something wrong, so I was wondering if there's some kind of best practice solution to this issue.
What I dont want is to have to pass the stuff the object loads, through the controller, to the model. That means any time I have to add a new common element to Object, I have to pass it through to the Model.
It's far simpler and easier for $this->cache or $this->db or $this->session to always be universally available in both controllers and models (as well as future helpers and misc classes).
How would I go about solving this issue?
Thanks :)
I think you are going in a wrong path about solving this issue.
If you are building an MVC application, you should separate concerns, thats why we use MVC. To separate Models, Controllers and Views.
You should define what do you need Model to do, what will Controller do, and use View only for presentation logic.
In proper MVC, Model is a layer that deals with business logic, database access, validation etc. So Model is not a one class. And you can use many models in one controller. And Controller is just... connection between Models and Views. Models should be fat, and Controllers should be light.
The way you are doing this is in my opinion wrong, since you can do the same stuff in both model and controller and that is not what MVC is for. Controller should not do any logic, thats why we use Models, controller only tells models what to do, and based on their reaction we tell other Models to do something else, or render View with success or error message or with posts from database etc.
The way you can do this is to once you have invoked appropriate controller, use it to get models you need. And again, model is composed of lots of classes, so your model folder can be fat. From Controller you should have only methods to access models so that models can do some actions, and report back to Controller what they did. And based on that returned value you do some more actions or call View to render.
So you should not have one object that can be extended by both models and controllers.
Your model folder can look like this:
Models
- Entities
- Forms
- Validators
- Services
...
And then you call any of them in your controller to do some action, and report back.
If you really need to have the same functionality in both controllers and models then this didnt answer your question, but I think its wrong to do it like you started.
Hope this helps you, interesting question Il try to help some more if I can.
I get a feeling, that the root of your problems is bad architecture.
The main thing you have to understand about MVC and MVC-inspired design patterns is that the pattern is made from two layers: presentation later and model layer. Those layers should not share common functionality. Controllers (as well as views and templates) are part of presentation layer.
When you have variables like $this->cache, $this->db or $this->session in the controller, it means that you have a severe leak of abstraction. These are storage structures, which should be hidden fairly deep in the model layer. If your controller is interaction with them directly, you do not have a controller.
Next problem is your base class (the one you call Object for some reason .. while objects kinda are instances of a class). It seems to be responsible for quite a lot, especially the instantiation of different abstraction for interaction with storage. If you controller needs a PDO instance (for some exceptionally bizarre reason), then it should be injected in the constructor. Same goes for cache and session management.
And then there is that small thing that model is not an object or a class. It is a layer. And just like presentation layer it is composed from different kinds of structures. Usually the recommendation is to have:
structures that deal with logical entities, which is usually what domain objects are for
one or more types of storage abstractions: data mapper, repository, unit of work, dao and/or some similar structures.
something, that controls the interaction between the above mentioned structures so that they do not leak in the presentation layer, commonly referred as services
And yes, you are correct assuming that using controller to pass along structures is a bad practice. It violates LoD. Instead you should be providing your controller with a factory, that instantiates your model layer structures and provides them with necessary dependencies .. this post might help.
my two cents on the subject .. for a more precise advice you would have to show some code

MVC models in PHP - Correct process order and separation

I need help clarifying the correct structure and process flow for an MVC application in PHP.
I think I've got the concept round the wrong way because currently most of my processing is done (or at least initiated by) the Views. -- I kind of inherited this way of thinking from the company I'm working for, but now I'm not sure that they are understanding the MVC model correctly!
Having looked at it again I think that the proccess should be as follows (very basicly):
The users actions are sent to the Controller
The Controller process those actions using any Models required
The Controller then instantiates the relevent View and passes the required data to it
The View renders the page to the user
I'm also having some difficulty deciding wether the view should even have any real functionality in it or not.
i.e. Is it just a wrapper to hold the page data and load the required template files (header, page, footer etc.), OR should any functions to do with rendering data (i.e. preparing HTML and outputting HTML) be in the View?
Another question is does the controller 'hand over' to the model and have nothing to do with the actual DBconn (so that the Model acts like a Bouncer on the doors of the DB nightclub, and we're not on the list) OR does the controller 'own' the DBconn and simply lends it to a model when it needs it?
I'd really appreciate any help and advice anyone can offer.
Thanks
edit -- I found this helpful!
I'll answyer to your two last questions:
1) The Views should have basic output capabilities, for example escaping values to avoid security issues or display a html table starting from a list of objects. Another responsibility could be the translation of labels and other constant values (for example you could have $this->_('Your label') where function _($val) is a function included in all your view classes that translates the strings starting from a csv file).
2) Depending on the complexity application, you could have two sub-layers in the model layer. The upper layer is the classic model with the functionality of your entities. The lower level is the resource model class associated that performs the db operations. You could also have a single layer with your models that implements the DAO pattern. Anyway, the controller shouldn't have nothing to do with db connection.
Your bulleted assumptions are correct :). The main idea behind MVC is loose-coupling and interchangeability between components.
To answer your questions:
The view should be presentational only, so iterating through a list of models in the view and outputting them there is fine, but processing data in the view is not.
The model should not assume anything about the controller and the view. It should be easy for you to switch between a model that draws data from a database to one that draws data from another type of data source and this should not determine changes in the Controller. Fabrizio is right, you should check out the DAO pattern for an example on how to do this.
I really recommend taking a look at frameworks that implement MVC to see how they do it. Especially Spring - even if you're not a Java person, the implementation is very clean -, Rails, Symfony. For something more exotic take a look at Django.

How do MVC components fit together?

I've seen a number of examples of ways MVC components fit together on the web.
The Controller retrives data from the Model and passes it to the View
This seems a bit verbose and messy.
$model = new Model;
$view = new View;
$view->set('foo', $model->getFoo());
$view->display();
The Controller passes the Model to the View
What if the View needs data from multiple Models?
$model = new Model;
$view = new View($model);
$view->display(); //View takes what is needed from the Model
The Controller passes the View to the Model
$view = new View;
$model = new Model($view);
$view->display(); //Model has told the View what is needed
Which of these is the "best" way to go about things? If none, what is?
The Controller retrives data from the Model and passes it to the View
As you said it's verbose and messy. But that's the most appropriate solution with the philosophy of MVC.
The Controller passes the Model to the View
Seems valid too. However it'll require for the view to ask for some model method. Which is not really in the spirit of MVC. Your view should only render the datas that are provided to it, without caring about the context.
The Controller passes the View to the Model
Forget that one. Here it is messy.
The answer is self evident if you consider that the 'model' is the central artifact (potentially used across applications), and that a 'view' may (or may not) be aware of the specific model but it is (by definition) a 'view' of a (potentially abstract) model and again, potentially usable across applications. The 'controller' is managing interactions and is the most application specific element of the pattern, so it definitively needs to know about model and view details.
If the view is specific to a given model, you can use option 2.
If the view is for an abstract model (and you can use it to display info from a set of models), you use option 1.
Option 3 is simply wrong.
The answer to the original question is:
The Controller retrives data from the Model and passes it to the View
MVC is actually very neat and clean. Remember what it is addressing:
Code reuse (Models do not rely on controllers or views. Views do not rely on controllers or models. Controllers are app specific.)
Separation of Logic (For instance changing an authentication backend from MySQL to LDAP require 0 change to a view. Changing a view's layout requires 0 change to model. Changing the database table structure requires 0 change to the controller or view).
Now IF you want your forms to be automatically generated from a table structure - the views are now tied to the table (tightly coupled). A change in the table require a change in the view (albeit potentially automatically). This may take less code - but the view is no longer dependable from a code-reuse stand point.
Similarly your views (in MVC) should be nothing more than templates. There should be no logic - just variables. All the "logic", aka business rules, reside in the controller. The models know how to get data and keep it normalized. The views know how to display data. The controller knows when to use the data and which views to apply the data to.
MVC is a strict 3-tier architecture. A two tiered architecture is valid for some applications. For quick mashups and "getting crap done" a one tied architecture can be appropriate (but you don't get style points).
Hope this helps.
IMHO, option 2 (the Controller passes the model to the view) best maintains the proper decoupling and separation of concerns. If the view needs multiple models, the model passed in should be a composite data type that contains each model needed by the view. "Each model needed by the view" is usually different from your entity model in that it is flattened and streamlined for display, often called a ViewModel.
Option 1 (the Controller retrives data from the Model and passes it to the View) is quite similar to option 2, but I contend option 2 is preferable because it places less logic in the controller. In MVC, as much logic as possible should be in the model, leaving your controllers and views as simple as possible.
I tend to agree with the second one. MVC on the web can't really be implemented as it can in more stateful applications. Most web MVC implementations have you put your logic in your controllers and use the model for raw data access. I think the more correct way is to put your logic in your model. There is almost an implied 4th layer in that raw data access is done within the model, however the model is also responsible for giving that data meaning and updating the view.
The wikipedia article explains it pretty good.

MVC, where do the classes go?

My understanding of the MVC is as follows (incase it's horribly wrong, I am afterall new to it)
Models are the things that interface with the database
Views are the design/layout of the page
Controllers are where everything starts and are essentially the page logic
I'm using CodeIgniter but I would hazard a guess it's not just limited to that or possibly even just to PHP frameworks.
Where do I put global classes?
I may have a model for Products and I then run a query that collects 20 products from the database. Do I now make 20 models or should I have a separate class for it, if the latter, where do I put this class (other controllers will need to use it too)
Model is the wrong word to use when discussing what to do with products: each product is a value object (VO) (or data transfer objet/DTO, whatever fits in your mouth better). Value objects generally have the same fields that a table contains. In your case ProductVO should have the fields that are in Products table.
Model is a Data Access Object (DAO) that has methods like
findByPk --> returns a single value object
findAll --> returns a collection of value objects (0-n)
etc.
In your case you would have a ProductDAO that has something like the above methods. This ProductDAO would then return ProductVO's and collections of them.
Data Access Objects can also return Business Objects (BO) which may contain multiple VO's and additional methods that are business case specific.
Addendum:
In your controller you call a ProductDAO to find the products you want.
The returned ProductVO(s) are then passed to the view (as request attributes in Java). The view then loops through/displays the data from the productVO's.
Model is part of your application where business logic happens. Model represents real life relations and dependencies between objects, like: Employee reports to a Manager, Manager supervises many Employees, Manager can assign Task to Employee, Task sends out notification when overdue. Model CAN and most often DO interface with database, but this is not a requirement.
View is basically everything that can be displayed or help in displaying. View contains templates, template objects, handles template composition and nesting, wraps with headers and footers, and produces output in one of well known formats (X/HTML, but also XML, RSS/Atom, CSV).
Controller is a translation layer that translates user actions to model operations. In other words, it tells model what to do and returns a response. Controller methods should be as small as possible and all business processing should be done in Model, and view logic processing should take place in View.
Now, back to your question. It really depends if you need separate class for each product. In most cases, one class will suffice and 20 instances of it should be created. As products represent business logic it should belong to Model part of your application.
In CakePHP there are 3 more "parts" :
Behaviors
Components
Helpers
Logic that are used by many models should be made as a behavior. I do not know if CodeIgniter have this logic or not, but if it doesnt, I would try to implement it as such. You can read about behaviors here.
(Components helps controller share logic and helpers help views in the same way).
The simplest way is to:
Have a model class per database table. In this case it would be an object that held all the Product details.
Put these classes into a package/namespace, e.g., com.company.model (Java / C#)
Put the DAO classes into a package like com.company.model.dao
Your view will consume data from the session/request/controller In this case I would have a List<Product>.
Oh, you're using PHP. Dunno how that changes things, but I imagine it has a Collections framework like any modern language.
#Alexander mentions CakePHPs Behaviors, Components and Helpers. These are excellent for abstracting out common functionality. I find the Behaviors particularly useful as of course the bulk of the business logic is carried in the models. I am currently working on a project where we have behaviors like:
Lockable
Publishable
Tagable
Rateable
Commentable
etc.
For code that transcends even the MVC framework i.e. code libraries that you use for various things that are not tied in to the particular framework you are using - in our case things like video encoding classes etc. CakePHP has the vendors folder.
Anything that effectively has nothing to do with CakePHP goes in there.
I suspect CodeIgniter doesn't have quite as flexible a structure, it's smaller and lighter than CakePHP, but a quick look at the CakePHP Manual to see how Behaviors, Components, Helpers, and the Vendors folder may be helpful.
It should be an easy matter to just include some common helper classes from your models keep nice and DRY

Categories