After many hours of research and thinking I have found an understanding, then coming to question it again, I am struggling to find something concrete which I can grasp and apply to my code in a practical sense going forward.
I think I am referring to presentation logic and a domain model. I have read numerous articles such as Anemic Domain Model, but I still don't fully understand what the correct solution is. I will start with one actual scenario which is puzzling me.
Let's say I have a web form which requires data to be shown from 10 different models. From each model I need to get a specific set of data which is only useful to this particular view. For example, it might be a bunch of drop-down menus with certain options in them.
1. Let the Controller do it
Pseudo Code:
/**
* Controller action
*
* Process a request for the specific view.
*/
public function myView()
{
$options1 = $model1->query(
// Get fields A, B, C from the database
// Order the data by a certain field
// Exclude data which does not meet conditions
// Process the data some more
);
$options2 = $model2->query(
// Get fields X, Y, Z from the database
// Order the data by a certain field
// Exclude data which does not meet conditions
// Process the data some more
);
// ...repeat this sort of thing 8 more times
$this->sendToView($options1, $options2, ...);
}
So the controller asks different model entities for the data the view needs, in exactly the format the view needs.
In a sense, this seems nice to me because the model layer has no idea about the view, and the controller takes responsibility for bridging the gap between them. All the logic about what should be presented in the view is handled by the only method in the application which is directly coupled to that view.
However, this could easily be 200 lines in my controller, and this is just for one specific view. Soon all the controllers will be huge sprawling messes of dozens of calls to the models for specific data for each view. You could split the different calls up into other methods on the controller (e.g. private) to make it a little more modular/manageable but what's the point?
Conclusion: Keep the controller thin, and delegate this stuff elsewhere, I guess.
2. Let the Model layer do it
Pseudo Code:
/**
* Controller action
*
* Process a request for the specific view.
*/
public function myView()
{
$options1 = $model1->getOptionsForAbc();
$options2 = $model2->getOptionsForXyz();
// ...repeat for 8 more models
}
/**
* Model 1
*/
public function getOptionsForAbc()
{
$options = $this->query(
// Get fields A, B, C from an associated table
// Order the data by a certain field
// Exclude data which does not meet conditions
);
return $options;
}
// Each model has similar methods which retrieve specific sets of data
So now the controller is nice and thin, and is not concerned with any logic. It just asks the model for some stuff it needs, and the model knows how to get it.
I use the term "model" loosely here. I fully understand that the model is a layer comprised of many things.
The problem with this appears to be that models will end up having lots of functionality which is probably only useful for one particular view. It will not be used elsewhere because only that one view requires that particular subset of data. This seems incorrect to me.
3. Implement a Service/Business Logic layer
I believe all the business logic should really be in the model. For normal business logic, such as calculations, validation and other things which happen to data, I understand this.
However, what should happen with this particular example of a view requiring specific data? Should I be creating a service class which represents the form, which is capable of delivering all the data the view requires, in the correct format? That doesn't seem right.
Final Question: So where should I be storing this kind of data-related presentation logic which is only for the view?
ViewModel
objects. Have a looksie at those.