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.
Related
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.
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.
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.
OK I now basics of the MVC concept, and I know there are similar questions asked but still didn't find clear answer on this. Reading about MVC I found some contradictory examples, so I wanted to find out which concept is better.
Should I use my controller to load data from the model and than pass that data to the view or should I let the view to load data from the model and use controller just to select the appropriate view.
The more natural(right) way to me is that controller should load the model, but than again if I have require the same content that has 2 different views, for example:
view displays simple article text
view displays same article text but also displays box with article author info.
The thing that confuses me is I have single request, show me article with ID 33. In the first case everything is clear, but now my second view renders using different template that shows additional data (about the author), so should I let the view to request data from the model (about author) or that entire logic should be done by controller?
It's confusing because now the controller should request appropriate data from the model based on template the view should render.
Hope I make sense :)
Short answer: Pass the model to the controller and the view.
Long answer: In MVC, the controller does not "load data from the model then pass that data to the view". The view has a direct relationship with the model and requests data from it. See: How is MVC supposed to work in CodeIgniter and http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller : "A view requests from the model the information that it needs to generate an output representation."
As such, to enable loose coupling, initiate the model view and controller completely independently and pass them in to eachother.
This allows the strict separation of concerns MVC advocates and allows you to reuse any component with any other as nothing is hardcoded.
Something like:
$model = new Model;
$controller = new Controller($model);
$view = new View($model, $controller);
echo $view->output();
The controller should not select the view, nor should it select the model. By putting this responsibility in the controller, the controller is not reusable with other views or models.
Edit: I've updated this to answer tresko's comment about why the view needs to know about its controller.
The view needs the controller in order to avoid hardcoding controllers into views. This is so that a view knows which controller it's paired with in the current context and can post back to it.
Events (user actions) are fired in the view and need to be handled by controllers.
There are 3 ways of doing it:
1) Hardcode the view:controller relationship, on the web this is achieved by using <a href="/some/hardcoded/route"; or <a href="' . $this->router->create('someController, 'action') . '>' This removes the possibility to use the view with any other controller which isn't desirable.
2) Pass the controller to the view and let the view know which controller its events will be fired to. On the web, using this approach the view will also need a Router which will convert a controller action into a route. e.g. <a href="' . $this->router->getRoute($this->controller, 'action') . '>'
3) Pass the view to the controller and have the controller set actions on the view: (controller code) $this->view->setEvent('buttonClick', $this->router->getRoute($this, 'action'))... (view code) <a href="' . $this->getEvent('buttonClick') . '>'
Of these,
1) Is the least desirable as it heavily impacts flexibility. The view can only ever call actions on a very specific controller.
2) is the least amount of work for the developer but each controller needs a specific interface.
3) This offers the most technical flexibility but there's more work for the developer and the controller needs to know a lot about its view, beyond the API it must know what events are available in the view. If a view is updated and has a new action, each controller will need to be updated to account for it. This applies to 2) as well, but because 2 can easily be handled using interfaces it's far easier to track down every class which uses it.
In my opinion, 2 and 3 are both good approaches but 2 is superior because it allows for a much more robust system and allows the most re-use, the downside is that controllers must implement a specific interface. 3 allows the controller to have any interface but it must know quite a lot about its view.
CakePHP and other popular frameworks tend to hardcode the relationship (e.g. http://book.cakephp.org/2.0/en/views.html ) here in their example, echo $this->Html->link('edit', array( 'action' => 'edit', $post['Post']['id'])); ?> the link can only go to the "Edit" controller. This severely impacts reuse.
My suggestion is that the logic for combining data sources with views should happen entirely in the controller. Views should not be bound to specific data sources.
For example, if you had a view that used the Smarty syntax (or similar) with named placeholders, then you could use any data source, text, model, etc to provide information to render into the template. If the view is tied to a model, you'd need to modify the model and view with an awareness of the impact on the other.
Tight coupling like that leads to more problems by accidentally overlooking something than looser coupling, which gives you fewer chances of breaking something by accident.
EXAMPLE:
class Page_Controller extends Controller {
// __construct/__destruct/__callStatic/__call/etc, whatever you need in your implementation
// -------------------------------------------------------
// Adjust to suit your situation for passing data
// This controller doesn't care where objSource comes from
// -------------------------------------------------------
private function pageSpecificImplementation($objSource = null){
// using a factory class - but assume a view is created in whatever way works for you
// the key thing here is that the view could be anything that can be returned as a string - but use whatever works for you
$tplMain = make::view( 'template-url-or-path' )->assign(array(
'placeholder1' => $objSource->value1,
'placeholder2' => $objSource->value2
));
$tplSub = make::view( 'template-url-or-path' )->assign( $objSource );
$tplMain->assign('sub',$tplSub->render())->render();
// $tpl is some form of html? csv?, who knows - not relevant at THIS stage
// okay - now I know what I want to do!
// decide what to do with it here - output headers for html
// save to a file
// output and cache the output, whatever works for you here
// output to pdf?
// send as an email?
output::html( $tplMain, $cacheable, $cachetime... );
// output::email( $tplMain, $extra_params );
// output::pdf( $tplMain, $extra_params );
}
}
Here, you're using a view, without tightly coupling it to the output. Your controller can modify the output based on whatever business rules are in play when it's run, but the data source is not tied to the view and the output isn't tied to the view.
I'd suggest 'some' implementation that separates in a way that follows similar principles. YMMV depending on what you're doing and how you want to implement it, but try to keep each element separated in MVC.
In some implementations you'll see the logic for 'replacing' things in views done without mentioning 'what' view. This is commonly done in Smarty. The view can then be determined by the Controller's flow. Data can be pulled from multiple models or other sources, which may, or may not, affect which View is appropriate.
So, you should definitely separate loading of data from the view. Keep it in the controller, which is where decisions should be made. Views shouldn't connect with models unless you have a specific use case in mind, such as a theme model with a tightly coupled theme view where there's no additional business logic involved (unlikely but possible?).
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