PHP MVC: Too many dependencies in controller? - php

I'm working on a personal HMVC project:
No service locators, no global state (like static or global), no singletons.
The model handling is encapsulated in services (service = domain objects + repositories + data mappers).
All controllers extend an abstract controller.
All project dependencies are injected through Auryn dependency injection container.
All needed dependencies are injected in the constructor of the abstract controller. If I want to override this constructor, then I have to pass all these dependencies in the child controller's constructor too.
class UsersController extends AbstractController {
private $authentication;
public function __construct(
Config $config
, Request $request
, Session $session
, View $view
, Response $response
, Logger $logger
, Authentication $authentication // Domain model service
) {
parent::__construct(/* All dependencies except authentication service */);
$this->authentication = $authentication;
}
// Id passed by routing.
public function authenticateUser($id) {
// Use the authentication service...
}
}
The dependencies list would further grow. This needs to change. So I was thinking about:
Totally separate controllers from views.
They would then share the service layer. The views wouldn't belong to controllers anymore and the Response would be a dependency of the views.
Use setter injection in controllersLike for Request, Session, Logger, etc;
Inject dependencies in the controller actionsOnly when needed.Like for Request, Session, Logger, etc;
Use decorator pattern.Like for logging after an action call.
Implement some factories.
To constructor inject only the needed dependencies only on child controllers.So not in AbstractController anymore.
I'm trying to find an elegant way to deal with this task and I'll appreciate any suggestions. Thank you.

I'll answer to my own question. When I wrote it I already had a good overview of what many experienced developers recommend regarding dependency injection in MVC and MVC structure.
The constructor injection is the proper option. But it seemed to
me that, following this line, I'll end up with too many
dependencies/arguments in constructors. Therefore giving controllers
too many responsibilities (reading the requested values, changing the
state of the domain objects, logging operations, requesting the view
to load the templates and to render the data, etc).
Setter injection was also a solution to take in consideration. But, in the course of the developing time on my project, I realised
that this solution really didn't fit (at least) into the picture of
my controller-view relationships.
The injection of the dependencies directly into the controller
actions caused me hard-time (but great time) too, having in mind
that I already had the url values injected as action arguments and
that I didn't used any routing dispatchers.
Implementing factories was also a great idea, in order to be able
to have objects at my disposal within each controller action.
Factories are a great tool to use, but only going from the premise of
needed run-time objects, not of just reducing the number of
dependencies in constructors.
Decorator pattern is also a good alternative. But if, for example, you want to log something within a controller action, then
this is not a solution: you still have to pass a logger as dependency
(in constructor, setter or action).
I had a thought about injecting the needed dependencies only on
child controllers. But then the problem of multiple
responsibilities of the corresponding controllers remains the same.
So, none of this solutions seemed to entirely fit into the structure of my HMVC project, whatever I did. So, i dug further, until I realised what the missing link was. For this I give my whole appreciation to Tom Butler, the creator of the following great articles:
Model-View-Confusion part 1: The View gets its own data from the
Model
Model-View-Confusion part 2: MVC models are not domain
models
His works are based on an in-depth, well argumented analyse of the MVC concepts. They are not only very easy to follow, but also sustained by self-explanatory examples. In a word: a wonderful contribution to the MVC and developer community.
What I'll write further is meant to be just a presentation of his principles with my own words, having in mind to somehow complete them, to provide a compacter perspective of them and to show the steps followed by me when I implemented them in my project. All credit on the subject, ideas and principles and workflows depicted here goes to Tom Butler.
So, what was the missing link in my HMVC project? It's named SEPARATION OF CONCERNS.
For simplicity I'll try to explain this by referring myself to only one controller, one controller action, one view, one model (domain object) and one template (file), introducing them into a User context.
The MVC concept most described on web - and also implemented by some popular frameworks that I studied - is centered around the principle of giving the controller the control over the view and the model. In order to display something on screen you'll have to tell that to the controller - he further notifies the view to load and render the template. If this display process implies the use of some model data too, then the controller manipulates the model too.
In a classical way, the controller creation and action calling process involve two steps:
Create the controller - passing it all dependencies, view inclusive;
Call the controller action.
The code:
$controller = new UserController(/* Controller dependencies */);
$controller->{action}(/* Action dependencies */);
This implies, that the controller is responsible for, well, everything. So, no wonder why a controller must be injected with so many dependencies.
But should the controller be involved in, or responsible for effectively displaying any kind of information on the screen? No. This should be the responsibility of the view. In order to achieve this let's begin separating the view from the controller - going from the premise of not needing any model yet. The involved steps would be:
Define an output method for displaying information on screen in the
view.
Create the controller - passing it all dependencies, excepting the
view and its related dependencies (response, template object, etc).
Create the view - passing it the corresponding dependencies
(response, template object, etc).
Call the controller action.
Call the output method of the view:
And the code:
class UserView {
//....
// Display information on screen.
public function output () {
return $this
->load('<template-name>')
->render(array(<data-to-display>))
;
}
//....
}
$controller = new UserController(/* (less) controller dependencies */);
$view = new UserView(/* View dependencies */);
$controller->{action}(/* Action dependencies */);
echo $view->output();
By accomplishing the five upper steps we managed to completely decouple the controller from the view.
But, there is an aspect, that we hypothesised earlier: we did not made use of any model. So what's the role of the controller in this constellation then? The answer is: none. The controller should exist only as a middlemann between some storage place (database, file system, etc) and the view. Otherwise, e.g. only to output some information in a certain format on screen, is the output method of the view fully sufficient.
Things change if a model is beeing brought on the scene. But where should it be injected? In the controller or in the view? In both. They share the same model instance. In this moment the controller gains the role of the middleman - between storage and view - in his own right. A theoretical form would be:
$model = new UserModel;
$controller = new UserController($model, /* Other controller dependencies */);
$view = new UserView($model, /* Other view dependencies */);
$controller->{action}(/* Action dependencies */);
echo $view->output();
Doing so, the controller can change the state of the model and ensure that it's saved in the storage system. The same model instance, respective its state, is read by the view and displayed. The controller passes display logic informations to the view through the model. The problem is, that these informations don't belong to the business logic, which a model is supposed to exclusively have. They are only display logic participants.
In order to avoid giving display logic responsibilities to the model, we have to introduce a new component in the picture: the view-model. Instead of sharing a model object, the controller and the view will share a view-model instance. Only this one will receive the model as dependency. An implementation:
$model = new UserModel;
$viewModel = new UserViewModel($model, /* Other view-model dependencies */);
$controller = new UserController($viewModel /* Other controller dependencies */);
$view = new UserView($viewModel, /* Other view dependencies */);
$controller->{action}(/* Action dependencies */);
echo $view->output();
And the workflow can be described like this:
The request values are sent by the browser ("the user") to the
controller.
The controller stores them in the view-model instance as properties
(data members), therefore changing the display logic state of the
view-model.
Within its output method, the view reads the values from the
view-model and requests the model to query the storage on their
basis.
The model runs the corresponding query and passes the results back to
the view.
The view reads and passes them to the corresponding template.
After template rendering, the results are displayed on the screen.
The view-model does not belong to the domain model, where all domain objects reside and the real business logic takes place. It does also not belong to the service layer, which manipulates the domain objects, repositories and data mappers. It belongs to the application model, e.g to the place where the application logic takes place. The view-model obtains the sole responsibility of gaining display logic state from the controller and conducting it to the controller.
As can be seen, only the view-model "touches" the model. Both, the controller and the view were not only completely decoupled from each other, but also from the model. The most important aspect of this approach is, that each of all the components involved gains only the responsibilities, that it is supposed to gain.
By making use of this kind of component separation and of a dependency injection container, the problem of too many dependencies in controllers vanishes. And one can apply a combination of all options presented in my question in a really flexible manner. Without having in mind that one of the components (model, view or controller) gains too many responsibilities.

Related

PHP MVC structure where to put own classes

I just started taking a look at the MVC pattern.
My question is:
Where would I put my other class files (Database, User, Logger, Mailer, etc)? Should I create a new directory for them, e.g. libs?
Should I instantiate the classes in the Controller inside the model function?
<?php
class Controller {
protected function model($model) {
require_once('../app/models/'. $model .'.php');
return new $model();
}
protected function view($view, $data = []) {
require_once '../app/views/'. $view .'.php';
}
}
Where would I put my other class files (Database, User, Logger, Mailer, etc)? Should I create a new directory for them, e.g. libs?
Putting them in separate files since they all provide different functionality should be fine. There is no difference in your directory naming - as long as it matches the naming conventions of your project or general (probably, even better).
Should I instantiate the classes in the Controller inside the model function?
No. As far as I see it, the flow could be similar to:
The index file receives the request and initiates a new bootstrap instance
bootstrap sets the throwable handler and the router
router then calls the respective method basing on the request method and uri provided by matching against a set of routes
The matching route initializes all the components of the MVC triad and the callable method. The components (Model layer, View layer, and Controller layer) are passed to the method called by the router. In my case, I call the class FrontController, the method init.
Basically, the init is the place where the MVC triad is actually made. Model layer is responsible for business logic, persistence, etc. It is important to note that Model is not a single file or class (the same for View and Controller). Both View layer and Controller layer consult the Model layer to do the respective actions. View layer's mission is to manage the output, for example, decide wether the output will have Content-Type of application/json or text/plain, or which Template to render. Also, Views are not Templates, which are meant for displaying the data. Note here, Views ask the necessary data directly from the Model layer; there is no interaction with the Controller layer whatsoever. Finally, Controller layers steps in when there is a need for interaction, for example, a user submits a form, the respective Controller filter the input and calls the method from the Model layer.
As MVC has three major parts, I'd recommend (and noticed that almost all frameworks on the market do so) to create a directory of each of the three components, and place the classes in the appropriate directory.
As regarding the other components, Database is a utility and can be placed for example in a lib directory, User is a model and can go to the model folder, and Logger/Mailer can also go to the lib folder. These are examples and not something to strictly follow.
As for instantiation, each Controller can define the list of models and libraries it depends on and have the MVC framework handle the initialisation of those objects. You'd follow the dependency injection pattern this way.

How do you write your controller in MVC pattern without PHP frameworks?

How will you write your controller in MVC pattern without PHP frameworks?
This is the simplest version of my controller,
//Controller
class Controller
{
private $model;
public function __construct($model){
$this->model = $model;
}
public function clicked() {
$this->model->string = "Updated Data, thanks to MVC and PHP!";
}
}
As you can see that only model is passed into my controller as its dependency.
This is how I understand the controller in MVC pattern which can be referenced in these following articles,
https://r.je/views-are-not-templates.html
http://www.sitepoint.com/the-mvc-pattern-and-php-1/
PHP framework developers probably disagree with this, because as most frameworks seem to be MVC, but probably are Model 2.
In a Model 2 application, requests from the client browser are passed
to the controller. The controller performs any logic necessary to
obtain the correct content for display. It then places the content in
the request (commonly in the form of a JavaBean or POJO) and decides
which view it will pass the request to. The view then renders the
content passed by the controller.
So if we are going to put these frameworks aside, how do you do your controller then?
I've written a series of articles for writing MVC applications, inspired by one of the links you posted. Among those there is an article about Controllers:
Controllers are taking SRP seriously
Have a read at it first.
So if we are going to put these frameworks aside, how do you do your
controller then?
My controllers don't have a reference to the view. They only update the model as shown in your code sample, and I think that's the right way to do. Controllers shouldn't contain binding logic to the view. Instead, the view gets its data from the model (see The View gets its own data from the Model where I also explain the advantages of such a design).
Controllers can consume as many dependencies as they want (they might need more than just the model injected), but if you follow SRP closely, controllers won't need a lot of dependencies.
In most popular frameworks, you see a controller with a bunch of actions and binding logic for view rendering; I instead separate all these actions into separate controllers so that I have a 1:1 relationship between controller and view. This allows me to have controllers without binding logic to the view (see link above for detailed explanation on how I do that). My Controllers also follow SRP more closely this way.
When I said above, that the controller updates the model, beware that MVC Models are not just Domain Models. In addition to Domain Models, View Models store the state that the view needs for rendering, e.g.: the view allowing to update an entity like let's say a User, needs to know which user needs to be updated (again, read articles for more detailed explanations). My Controllers have thus in most cases at least two dependencies,
a domain model (most frequently an ORM instance) allowing me to update the datasource
a view model allowing me to update the application state (like which user is to be updated, search filters, ...) necessary for view rendering
I'd not seen Model 2 before this question, but as far as I can tell it is just a Java-specific approach to MVC, it isn't a separate design pattern as such.
You've not really explained why you think the PHP frameworks you mentioned aren't following MVC, in ZF at least it is quite common practice for dependencies to be passed in via. a controller's constructor as you have in the example from your own framework.
It's easy to fall down the rabbit hole with design patterns, really a lot of it is down to interpretation. Just because your implementation of a pattern isn't the same as another, doesn't necessarily mean the other implementation is wrong.

Is it bad to inject controller class into a controller class?

By trying to follow single responsibility principle, I decided that rendering form view I could move to another class. Also to render form I already am planning to use 5 dependencies. So the main controller which injects form will have less dependencies which is good.
I never injected controller classes into a controller class. What I usually do is I create the library. I have libraries folder made as sibling to controllers folder.
But now thinking - maybe better idea would be to have another controller injected into a controller?
Tried to search for this, but did not find any examples. But at the same time tried creating controller with just constructor function and echo a string. Then inject this controller into another. And string gets displayed.
So this means it is possible to inject controller into controller. So is it good? Or maybe this would be a must?
By default laravel do not even have libraries folder which is interesting, maybe creators assumes that it is not needed.
Yes it's bad. Controllers not only must have one single responsibility, but they are also a different kind of class that should have only one job: A controller is a proxy between the HTTP request and your application (models, repositories, views). So basically it should receive an HTTP request, get some data from your models and pass it away to a view.
Everything else should be done by your support classes (models, repositories, helpers, composers, etc.).
If you are in need to call a second controller class, it's probably because you need methods on that controller that should not be in that controller, because your controllers are doing more than what their job is.
This is one of my controllers:
class Connect extends BaseController {
public function index()
{
$connections = $this->execute(GetConnectionsCommand::class);
return View::make('connections.index')->with('connections', $connections);
}
}
There's a lot happening behind the scenes in that GetConnectionsCommand to get the information to show all connections, and my controller should not know any about it all.
There are some subviews on that ´connections.index´ view, but calling subviews are a view responsibility, my controller doesn't have to know that a particular view needs subviews to be rendered. I can have a master view and some #ifs inside it to render them all properly.
A controller returns data (a rendered view, rendered by another class) back to the response object (behind scenes in Laravel), which is the guy responsible for effectively rendering the data which will be passed back to your browser. So a controller is right in the middle of something, doing very little orquestration, because, the more it knows about your business logic, the more you'll feel it needs to ´talk´ to another controller. You can think of it as MVP if you like, but this is pure MVP using the Single Responsibility Principle as it should be. But in this case the Controller is not decoupled from the view, because there is no Interface between them, so it's not really MVP.

MVC. If the View does not know about the request how does it fetch data?

In a MVC application it is easy to understand how the Controller extracts data from the request and updates the Model layer but I am a bit confused as to how a View is supposed to retrieve data from the Model layer when the View does not know about the request?
For example if I go to
http://www.site.com/product/view/428
I route the URL and I dispatch the request and I end up in the Controller. Nothing needs to be done in the Controller(I think?) and when it gets to my View I need the product ID but the View should not be extracting data from the Request so what do I do?
Thanks.
There are two approaches for handling this and both actually would indicate that controller in this case a significant role to play.
The fabled ways of ancients ..
The first option for resolving this issue would be adhering to classical MVC as close as possible. This kinda relates to what people mean, when they say 'you cannot do classical MVC for web'. In classical MVC the view observes model layer. And that part can actually be implemented.
If that's the approach you want to take, then you will have to learn about Observer (1), (2) pattern and how to use it in PHP (1), (2). Though there has been some push for moving away from Observer pattern.
Since I have not explored this approach in any meaningful way, I will not give any examples.
The puny trail from this decade ..
If you read Fowler's "GUI Architectures" article, you might notice the part which state that views and controllers form pairs. When applying the ideas of MVC to context of web, there are ways to benefit from it in the bootstrapping stage of application.
FYI : I'm not anymore so sure, that you can call this way "Model2 MVC". There are some significant inconsistencies. I'm gonna poke more at this nagging suspicion some more, when I'm bored.
Consider this fragment:
$router->route( $request );
$resource = $request->getParameter('controller');
$view = new {'Views\\'.$resource}($serviceFactory);
$controller = new {'Controller\\'$resource}($serviceFactory, $view);
$method = $request->getMethod(); //post, get & etc.
$command = $request->getParameter('action');
$controller->{$command.$method}($request);
$view->{$command}();
echo $view->render();
The controller fragment in your example URL would be "product" and action would contain "list". I left those names instead of resource/command pair to make it less confusing.
If you start out with a premise that views and controllers are paired to some extent (whether the pairing is cohesive or not is debatable), then you can express it by using same names. This also lets you move the initialization of view out of controller.
Another aspect which is encapsulated in the fragment above is the fact that, due to the request-response nature of web, every operation in controller will require an accompanying one in the view. And similarly to how you have actions in controllers, you can also opt to call specific, route-related methods in the view. That would remove some boilerplate conditionals from views and let you better organize the whole thing (this is kinda the "highly subjective bit").
So .. how do you turn /product/view/428 request in something visible on site?
As you probably know, the responsibility of controller is to alter the state of model layer, which in this case might code something like this:
public function getView( $request )
{
$warehouse = $this->serviceFactory->provide('warehouse');
$warehouse->chooseItem( $request->getParameter('id') );
}
The your view instance uses the primed service from model layer to acquire data:
public function view()
{
$warehouse = $this->serviceFactory->provide('warehouse');
..
..
// retrieve data about sales for product with ID: 428
$something = $warehouse->getSalesFigures();
..
}
The exact implementation of view will depend on how far off deepend you are willing to go. Two most reasonable options would be:
fetch data, inspect it and if necessary choose templates and dump data into them
use a set of presentation objects to work with model layer and based on the result bind those presentation objects to ant number of templates
my 2 cents
In MVC, A controller "controls" the flow of information between the model, where the information is "stored," and the view, where it is displayed. Therefore, the controller handles all the changes of information and interaction with the models and then sends the necessary information to a view that then displays whatever information was requested/changed/etc.
MVC is all about the separation of responsibilities.
Models are responsible for storing and modeling the application's data.
Views are responsible for displaying information to the user.
Controllers actually have multiple responsibilities:
Deciding when to Create new instances of a Model.
Deciding which instances of Models to Read and passing them to the appropriate View.
Deciding which data in a Model instance needs to be Updated based on data passed back from a View.
Deciding when to Delete no longer needed instances of a Model.
In other words, Controllers sit between the Models and Views and do all the business logic for an application, including figuring out which CRUD operations need to happen... although the actual CRUD operations are usually part of the Model itself.
A better name for MVC would probably be MCV to stress how the Controller sits between the Model and View.

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

Categories