Where should a breadcrumbs path be declared (in other words, in which letter of MVC)? So far I've been declaring it in Controllers, but I've recently started to work with CakePHP, where it is all made in Views and it surprised me.
I'm going to throw an answer out here, because there's a lot of confusion about what should and shouldn't be done with breadcrumbs.
The Model
The Model is a layer that contains your business logic consisting of domain objects, data mappers and services. You can read more about the model here.
The Controller
Remember: fat model, skinny controllers. Your controller / method is accessed from your routing mechanism. Once you're in the controller, you want to get your model object, perform whatever logic is required in the model, have the result of this returned to a variable in your controller, and then you use this to display data in your view.
The Breadcrumbs
That being said, your breadcrumbs need different parts to work. Let's think about this:
They need the current page
They need a list of pages
They (may) need a custom "class=current" added
Breaking those down:
In my framework, the current controller is also the page name (login controller maps to /login). So, we already have the current page.
The list of pages.
If your parent/child relationship of the pages are tied directly to the datamodel, then in your controller you pull the list of pages from the model. So use the model if the breadcrumbs can be automatically generated.
If the framework you're using allows breadcrumbs created entirely by user choice, then you are just choosing what to put in the breadcrumbs manually. Either way, you state your breadcrumbs in the controller, and if you need to get them from somewhere, use the model.
Finally, the "class=current". Although you shouldn't really contain significant 'logic' in your view, small things like loops or if statements are pretty standard. Here, you would check your breadcrumbs for the title equalling the current controller name (passed through as a variable to the view), and add a class=current if found.
Code Example
Note: untested
/**
* So we're in the home controller, and index action
*
* #route localhost/home or localhost/home/index
* (depending on .htaccess, routing mechanism etc)
*/
class Home extends Controller
{
public function index()
{
// Get current class name, so we have the current page
$class = __CLASS__;
// Let's say the page heirachy is tied to the model, so get pages for current method, or however you want to implement it
$pages = $model->getPages($class);
// So the TEMPLATE handles the breadcrumbs creation, and the controller passes it the data that it needs, retrieved from the model
// (new Template) is PHP 5.4's constructor dereferencing, also included is some lovely method chaining
// setBreadcrumbs() would assign variables to the view
// Render would do just that
(new Template)->setBreadcrumbs($currentPage, $pages)->render();
}
}
And now, the view... note, I use PHP 5.4, so I can use short echos...
<body>
<?php foreach($breadcrumbs as $b) { ?>
<li <?=($b['current'])?'class="current"':''?>>
<a href="<?=$b['page']['url']?>">
<?=$b['page']['title']?>
</a>
</li>
<?php } ?>
</body>
And that's how I would do it. Some of this is down to personal preference, but I hope this shows one way of doing it and is at least a little useful.
I actually came across this answer googling "php mvc breadcrumbs", and writing out my brain has really helped me to figure this out too. So thanks!
Whenever you see words "logic" and "view" together you should start worrying. My vote is for Controller because breadcrumbs is typical example of application-level logic, so putting it to the view violates MVC in my opinion.
Breadcrumbs should be in the controller. I use CodeIgniter and do something like
$data['breadcrumb'][0] = array("title" => "Home", "alt" => "Home Page", "path" => "home/");
$data['breadcrumb'][1] = array("title" => "About", "alt" => "About Me", "path" => "home/about");
And then in the view loop through and display them as a list.
<ul class="breadcrumbs">
foreach($breadcrumb as $b)
{
?>
<li><?php echo $b['title']; ?></li>
<?php
}
</ul>
You can then also declare simple things like classes, current pages, etc. The only downside is you have to set the breadcrumbs in every page.
ALL logic should be in the controller. Access databases through the models, perform logic in the controller, and pass it to the view.
Simple stuff like
<?php echo ($loggedin)?"Logged in as" . $user->firstname:"Not logged in";?>
can be in the view. But you shouldn't be setting up complex flow patterns. Leave that to the controller. Views are cheap. You can have a half dozen slightly different views and no one will care. It's not like static HTML where you would have to maintain a half dozen pages.
Include common things in the views (like headers, footers, script files, javascript files, etc) and then let them be.
IMO, the breadcrumb relates to the set of controller actions taken to get to the current page or the action's place in the hierarchy of the site, depending on your interpretation. From that perspective, the controller seems the natural place to construct the data for it, though the rendering should occur in the view. In order for it to be completely generated in the view, you would need to either expose details about what controller action is being invoked by the view or have a fixed view-per-action model so that the breadcrumb for each could be precalculated. Moving the logic for computing the breadcrumb to the view itself seems to violate the separation of concerns in MVC and may preclude reusing views for different actions, which would violate DRY>
In my opinion, generating data for the breadcrumb is a cross-cutting concern in the controller, i.e., you have some shared code that runs regardless of the action that uses the url to construct the breadcrumb data. There is also some shared view code that takes the controller-supplied data and renders it consistent with the design.
Note that I'm speaking from a purely architectural perspective. I'm not familiar enough with CakePHP (or other PHP frameworks, for that matter) to even judge whether your observation about it is correct. From a pattern perspective, putting it in the controller seems like the right thing to do. In a given implementation, though, it might make sense to violate the pattern.
$this->Html->addCrumb('Home', '/pages/home');
$this->Html->addCrumb('Contacts', '/pages/contacts');
echo $this->Html->getCrumbs('»', 'StartText');
Related
In my previous company which had an all-ajax web ap, there was a from-scratch framework being used. The way page sections refreshed was that you'd call the controller with a string, and the controller would load one or more view files. The view file would almost always call a class or classes in the model. This was as it was when I got there.
I am now working with a new company to develop a new system and looking at framework candidate. A 30 minute tutorial on codeigniter shows the controller calling the model, and the model loading the view.
This is opposite to what I am used to from my experience, so I wanted to ask which strategy is more common. In my mind it seems more rational that the view is a "shell" or structure but which is restricted to needing the model to get to the business rules.
I'm not sure if I should share a link here, I am NOT trying to promote codeigniter, but the tutorial is located at https://www.youtube.com/watch?v=47VOtKiw9AQ at about 10:00. Thanks
tutorials. there are a lot of them.
controller calls the model and passes data to the view. thats the standard answer. however i'm now leaning towards - the controller assigns specific views, and then calls a template, passing $data.
and then in the template -- there are calls to a model to create the navigation bars for that template, and optionally a page display model.
otherwise -- either you have my_controller which everything passes through that could have calls to page display, navigation, etc.
Or you have to put page display details in every single controller. personally i'm not a big fan of the my_controller design pattern, and calls to a navbar in complex controllers are not optimal.
so in that case what might be considered a view -- a simple template file -- would be calling a model. but in this case its not really a "view" because its not displaying anything directly -- the template is calling the nav view, the header, the footer view, etc etc -- and then the actual page content is assigned by the controller.
this also gives you more portability - when you need to change details about the page display or navigation you only have to go to one place.
finally there's many php frameworks and many opinions. after a long dormant period the codeigniter framework is under active development. however if you are starting from square one take a look at Node as well, it has some compelling features depending on your use case.
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'm building a small PHP MVC, and I've hit a wall with a small area of the coding. I think I need "partial views", but I might be able to achieve something with the existing code.
My controller in it's simplest form currently:
Instantiates an object
Checks if a POST variable isset
Displays view 1 or displays view 2 as necessary
The view(s) currently:
Displays HTML markup
Use and echos the models get functions such as getUserInfo()
Everything is working great, however the code is now getting fairly large in both the controllers and views, and I've reached a situation where I need to include "modules" or sub views inside the main views (1 and 2).
For example if view2 is loaded, then I need to display (as part of the view2) another view, say a 3 part sign up registration form. This registration form comes with it's own controller file too.
I can do something like this, which will work and give you some idea of what I am trying to do, but I acknowledge this breaks MVC design patterns.
View
<div id="mydiv">Some content</div>
<div id="mysignup"> <?php include('controller_signup.php'); ?></div>
<div id="content"> The views main page content </div>
The view is then pulled in from the controller, in the right place.
As mentioned, I think I need to use partial views, however most of the info I've found is for ASP, and I'm slightly lost!
I would have thought this is a fairly common problem, so I assume there is an obvious solution!
Thanks!
The root of you problem is fact that you do not have views. What you call a "view" is a actually a template. This in turn forces the presentation logic in the controller.
In proper MVC views are instances, which contain all of presentation logic. They acquire information from model layer and then, based in data, choose how to display this information. Each view manipulates multiple templates.
Also, it seems that your controller has gained extra responsibilities. It is supposed to change the state of model layer and current view, instead of rendering templates.
Can't say I agree with tereško. Having the presentation logic in a separate view class might seem more proper, however it does add another layer of complexity. In many cases, this additional layer is not necessary - often a view can directly render whatever model or data you inject. So you end up with empty View classes that only pass the model from the controller to the template.
I'd say, Keep It Simple, you can do pretty complex (and maintainable) websites with simple MVC, without introducing the notion of templates.
To handle subviews, you can simply have the main view inject data into the subviews, this should be transparent to the controller (who just provide the main data without caring how it should be rendered). So in practice, you could have something like this:
Controller:
public function someAction() {
// ...
$view = new View('name');
$view->data = $someList;
}
View:
<?php foreach ($someList as $item): ?>
<?php echo (new View('subview', $item))->render();
<?php endforeach; ?>
I am not too technical but wanted to know since my tech team is implementing this way:
Do we need to create a 'controller' file for each set of views that we need to call on the website OR can we control ALL the views from 1 controller? It seems like more work to have multiple controllers control all the views. I would like to have 1 controller call all the views to cut down on project time but not sure if this is possible or even a good practice?
This is neither good nor bad practice. All that matters is that your code is clear and well structured. After that, Code Igniter gives you lots of flexibility on how you use controllers and views. Personally, I tend to use one view per action (so a controller often controls several views).
Yes, it's possibile; you can easily test it yourself:
class Customcontroller extends CI_Controller {
function index()
{
$data['test'] = 'test';
$this->load->view('header', $data);
$this->load->view('body');
$this->load->view('footer');
}
}
You'll notice that doing this way $data will be available to all views, even if not passed individually while loaded.
I find it a nice way to building pages, using views as blocks. So, you can also present views according to some constraints:
$this->load->view('header');
if($this->form_validation->run() == FALSE)
{
$this->load->view('display_form');
}
else
{
$this->load->view('form_sent');
}
$this->load->view('footer');
for example.
Although MVC stands for Model-View-Controller, and suggest a one-to-one correlation, using different views for a same controller I doubt it can be considered "bad practice"; as already being said, there's no really an ideal way of doing this, what's important is keeping the logic separated and making your code well-structured and organized, especially when working in a team.
It really depends on what your controller is supposed to do. If all you want to do is show blog posts or content pages, for example, you can just use one controller called 'blog' or 'pages'. Controllers handle the logic. If you have many features you'd like to run (such as accounts, events, photos, etc.) it's usually always wise to give each their own controller so they can handle operations suitably with their model.
If you use frameworks like CodeIgniter, you can use their routes feature to automatically route certain URLs through a particular controller. For example, if you wanted pages to have a URL of http://example.com/page/page-title - you'd need to use this line in your routes config file:
$route['page/(:any)'] = 'page/get_page';
Any URI request that contains 'page' will be handled by the 'page' controller and the 'get_page' method. You can they grab the page-title or page-id by using $this->uri->segment(2).
I will have a single controller using multiple views. Here is how. My webpages have common header, footer and navigational structure, so these views will be common to all the web page calls hence a controller may inherit a method that takes content and assembles a page using header/footer/common views. For displaying grids I may have a common grid view that I can keep using in multiple controllers for displaying tabular data. Different use cases can reuse some views. So it makes sense that you can use multiple views within one controller.
codeigniter itself does not restrict you on how many controllers you use.
but as a basic idea, i tend to seperate controllers into modules.
for example, if your site have a front end and a back end, i would separate them, so i got 2 controllers (each with their own views).
this way, if you have more than 1 person working on the site, you can assign 1 person with the front end, and the other with the back end.
further more, you can break them apart into smaller modules. for example, in the front end, there is a home page and an article page (certainly you have different views for those), you can also break them down if you feel they are complex enough. but if you think they are simple, then it is fine if you use 1 controller for those views.
Rather than use a full-blown PHP MVC, I'm designing one that will best-fit my uses. I have the basic framework done, and have coded the models and controllers I'll need to run my website.
Now I'm moving onto the Views, and I've encountered a small dilemma. My approach is working fine for me, but for future reference, I want to know if what I'm doing is a bad habit to get into.
What I'm trying to do:
In my View, I'm calling a Model that runs my authentication system, and requesting the login status of a user. I then use that boolean to decide whether to show certain elements within the view, and where to place others.
Should I be designing separate views for each login status, or is this approach fine? However, if I'm going to be implementing this MVC into the work I'm doing for my clients, I need to use the best practices.
Any advice would be appreciated!
Can I call the model from the View?
Yes, you can. As long as you maintain the separation of concerns between M,V and C, you are free to call upon the Model (or the Controller) from the View. Most MVC diagrams show a bidirectional connection at least between View and Model. What you don't want to do though, is place logic/code from the Model (or the controller) into the View and you don't want to modify the model from there.
For example, you might have a widget on your page that aggregates the latest ten blog posts headlines from your favorite blogs on each page of your website. You get the headlines by calling, say MyFavFeeds::getLatest(); in your model. What are your options now?
You could add the code to fetch the headlines into the controller, but that would require you to replicate it in each and every controller action, which is against the DRY principle. Also, the controller's concern is handling user input for specific actions and fetching the headlines on each call is likely not even related to these actions.
If your architecture supports it, you could fetch that data in some sort of preDispatch hook, that is, the headlines get loaded and injected into the View from a plugin or callback. That would be DRY, but a second developer might not be aware of that plugin and accidently overwrite the variable holding the headlines from his controller action. And there might be cases in which you wouldn't want to load the headlines, e.g. when just rendering confirmation pages for form submissions, so you'd have to have mechanism for disabling the plugin then. That's a lot to consider.
You place the call to (not the code of) MyFavFeeds::getLatest() into the View or Layout template or, better, a ViewHelper, that encapsulates the call to your model class and renders the widget. This way you don't have to worry about overwriting any variables or repetition. And when you don't need the headlines on your view, you simply don't include it.
About your other question:
In my View, I'm calling a Model that
runs my authentication system, and
requesting the login status of a user.
I then use that boolean to decide
whether to show certain elements
within the view, and where to place
others.
Authentication is something you will want to do early in the application flow, before any controller actions are called. Thus, you should not run your (entire) authentication system in the View. The actual authentication is not View-related logic. Just requesting the user status after authentication, on the other hand, is okay. For instance, if you want to render a widget showing the user name and giving a login/logout button, it would be fine to do something like
<?php //UserHelper
class UserMenuHelper
{
public function getUserMenu()
{
$link = 'Logout';
if(MyAuth::userHasIdentity()) {
$link = sprintf('Logout %s',
MyAuth::getUsername());
}
return $link;
}
}
If you got larger portions of your GUI to be modified by a User's role, you might want to break your View apart into partial blocks and include them based on the status, instead of writing all the HTML into a View Helper.
If you are only looking to render a navigation based on the user role, have a look at Zend Framework's Zend_Navigation and Zend_Acl to see how they do it.
You can, but you shouldn't. Except for a few extreme cases (and branching your view based on logged-in status is definitely not an "extreme case"), it's pretty much always A Bad Idea to call model stuff from a view.
What you probably want to do in your situation is pass the boolean to the view through the controller. That way, if you change something about the User model, the view doesn't have to know, so long as the controller keeps the behavior the same.
While I only know enough about MVC to get myself in trouble, I've always lived by the fact that unless your view is STRICTLY user interface, then it shouldn't be there.
Also, I've also ran with the idea of thin controllers, fat models.
Going off of these, I'd suggest adding a method to your authentication system model that returns the appropriate view to render and passes that to the view.
Okay, I would really try to keep my Views as logic-free as possible. If you need to switch anything based on e.g. the result of a model method, put a controller in place that delegates the rendering.
Just make sure you follow the basic idea: Do your stuff in the models, Tell your models what to do from your controllers and also tell your views what to show from your controllers.