I'm about to do a PHP website using the MVC pattern. I am not using a framework as the site is fairly simple and I feel that this will give me a good opportunity to learn about the pattern directly. I have a couple questions.
Question 1: How should I organize my views? I'm thinking of having a Page view which will have the header and footer, and which will allow for a Content view to be nested between them.
Question 2: If I have 5 Content pages, should I make 5 different views that can be used as the content that is nested within the Page view? Or, should I make them all extend an abstract view called AbstractContent?
Question 3: What about controllers? I think there should be one main controller at least. But then where does the request go from there? To another controller? Or should I just call the Page view and leave it at that? I thought that controllers were supposed to handle input, possibly modify a model, and select a view. But what if one of the views nested within the view that a controller calls requires additional input to be parsed?
Question 4: Are controllers allowed to pass parameters into the view? Or should the controller simply modify the model, which will then affect the view? Or is the model only for DB access and other such things?
1 - This is a matter of preference. The simplest way would be to have a separate header and footer file. Then you could do something like this in your page controller
$title="Page Title";
$var1 = 'var1';
$var2 = 'var2';
$var3 = array("asdf","adsfasdf","234");
include(HEADER); //$title is in header
include(DIR_VIEWS . 'page.php'); //$var1/2/3 are in page.php
include(FOOTER);
// variable were created before pages were included so they will be set in the templates
If you were to go the nested route you would have to start fiddling with str_replace and that starts heading towards a template engine, out of scope for this answer.
2 - No need to make views objects. A "view" can just be a file on your filesytem that contains the html for that view. Like my example above. These pages can contain basic php to loop/echo variables as well.
3 - You are describing a front controller (sometimes called dispatcher or router). This is really the way to go. There are a couple methods for creating a front controller.
You can have an array of urls that point to controllers.
$routes = array (
'~^/home/$~' => 'home.php',
'~^/contact/$~' => 'contact.php',
'~^/blog/.*?$~' => 'blog.php'
);
or you can use the first "directory" in the url as the controller name and load that file form your controller directory.
4 - The entire point of the controller is to get info from the model and pass the data to the view.
Edited for comment
If you want a bunch of views to have a sidebar you just include that view in the other view. For example:
<div id="content">
<p>lorem ispum stuff</p>
</div>
<?php include(DIR_VIEWS . 'sidebar.php');
Just make sure that in controllers that "control" pages with sidebars you include some code for sidebar functions:
if ( $_GET['keywords'] ) {
$sidebar_search_results = get_search_results($_GET['keywords']);
}
// this code should be in a file that you include
$sidebar_search_results could be an array of results that your sidebar view parses and displays.
Think about what ways you'd want your HTTP responses to look like: full pages with/without nav, stripped pages for printing, JSON & XML responses, an index/sitemap. After you feel the site is forming, add more and more shortcuts for getting your response out there with as little code as possible.
If the page layout is similar, I would use the same view and load content into it from a model (possibly a database).
Check out the Front Controller pattern: you should always be able to intersect the request in a single point of entry. I would put something hierarchally in front of your controllers and then have one controller per "main page" (forum, blog, news). This is sufficient to control, but you'd have to decide what chunks are large/small enough for you.
Controllers are responsible for everything that gets passed into the views. Controllers should fetch data & settings & what-not from models and pass on to the views.
Question 1:
This is indeed a way to do this, and one which I allways use.
Question 2:
Just keep views as simple as possible. I tend to create just 5 separate views (plain php files).
Question 3:
In the normal mvc pattern, there is one front controller (which OS just a bootstrap file, the index.php) which executes one controller.
In HMVC, controllers can send additional request to other controllers.
Question 4:
The normal MVC pattern applies on normal apps, where views are persistent, and can observe the models. With web applications this is not possible, because every request everything is reloaded. So the most used pattern is to let the controller pass the parameters to the view.
Related
i know that this question already has been asked. But i still dont understand it.
Right now im trying to understand how to make use of the MVC Modell.
But i dont get how to integrate everything and right now I am hesitating to use a framework before i really get it.
What I try to achieve:
I want to have a header, a footer and a menu which remain the same all the time.
Like this:
HEADER
MENU
{CONTENT}
FOOTER
So my thinking is:
My Controller gets some Information, lets say its a User-ID.
Controller calls a method from the Model:
Get all DATA from USER with ID: 1
Then the controller passes the DATA into a view, lets say a list.
So where to go from here?
Should the controller pass this view into another view?
Like:
$site = new View(); <br>
$site->wholeSite($content);
and then site is something like:
HEADER
MENU
{$content}
FOOTER
Please excuse my simple approach, im just trying to get the basic idea behind it and i already read the first 20 pages of googling it.
Just cant get my head around it.....
It would be really nice if you would explain it for an Beginner :)
Thanks in advance!
you can call multiple views from the control like:
$this->load->view('header',$data);
$this->load->view('menu',$data);
$this->load->view('content',$data);
$this->load->view('footer',$data);
If you have a nested div then you can use regular include function like from a particular view file.
include('footer.php');
According to the path of the view file. The data also gets transferred from parent view to the included file.
Generally MVC apps have a universal layout view which contains the header, footer and menus. Sometimes data required for that is handled outside the controller, in say your init script or bootstrap.
An MVC purist might pass all data the layout requires from the controller, but that can be repetitive, although setting the data in an abstract controller construct might alleviate that.
On the question of views and sub-views there are generally two solutions:
A.) You have one principle view which all required data is passed to. In that view sub-views (partials) are called, and data is passed down into them.
B.) You instantiate all your views in the controller, passing all the data they need directly into the view, you would then pass views as parameters into other views.
Both methods have their pros and cons. I find the first option leads to less Fat Controllers, so I usually go with that.
I'd recommend you learn an existing MVC framework ( CodeIgniter, now defunct is basic enough to make it a good entry point), as that will show you how things are done.
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.
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.
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');