I haven't found too many taking the approach from the View site. So, working on an application, I managed to get a good separation between the model and controller classes, but I got in trouble dealing with the View. I'll just sum up the process I went through and the problems I encountered.
// PERSPECTIVE 1. How I started.
Code: Select all
<?php
// Controller
class ArtcilesController {
function View(){
$articles = new ArticleModel();
$maincontent = $articles->findAll();
$template = new A_Template_Include('templates/example1.php');
$template->set('title', 'Mysite - articles');
$template->set('stylesheet', 'main.css');
$template->set('content', $maincontent);
$content = $template->render();
$this->response->setContent($content);
}
}
// Template
?>
<html>
<head>
<title><?php echo $title; ?></title>
<link href="<?php echo $stylesheet; ?>" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="maincontent">
<?php echo $maincontent; ?>
</div>
</body>
</html>Code: Select all
<?php
class ArticlesController {
function View(){
// ...
}
function ViewSummeries(){
$articles = new ArticleModel();
$maincontent = $articles->findAllSummeries();
$template = new A_Template_Include('templates/example1.php');
$template->set('title', 'Mysite - articlessummeries');
$template->set('stylesheet', 'main.css');
$template->set('content', $maincontent);
$content = $template->render();
$this->response->setContent($content);
}
}
?>So we want to be able to reuse some components. A Composite pattern comes to mind.
Code: Select all
<?php
class ArtcilesController {
function View(){
$maincontent = new Template('tpl/body.php');
$maincontent->set('item','withthis');
$maincontent->set('item2','withthis');
$maincontent->set('item3','withthis');
$body = new Component('body', $maincontent);
$body->attach(new Component('menu', new Template('tpl/menu.php')));
$page = new Component('page', new Template('tpl/page.php'));
$page->attach($body);
$page->attach(new Component('footer', new Template('tpl/footer.php')));
$content = $page->render();
$this->response->setContent($content);
}
}
?>controller has to make sure all content (the variables) has been given to the different components of the view (the templates). For the specific content that action is responsible for, that's ok. But for most content, it's not the responsibility of that action to gather the data.
In my view, let's say the component Mainnavigation is itself responsible for gathering it's data needed to render well. And to complicate matters further, that data depends again on the action/request in some ways! Say you have a navigation list, and depening on which page you are on, one of the items is highlighted.
Another good example is a breadcrumb trail. used in all pages (so its a general element) but it also has to be aware of it's context.
Maybe I need some kind of ViewHelper. Or probably more of them. Then the ViewHelper is responsible for gathering all necessary data for the templates. Of course, I must be careful not to let the ViewHelper get too much responsibility, turning it into a controller. So, read-only for the ViewHelper.
Code: Select all
<?php
class ArtcilesController {
function View(){
$articles = new Article;
$maincontent = $articles->findAll();
$view = new ViewHelper;
$view->setContent($maincontent);
$content = $view->getContent();
$this->response->setContent($content);
}
}
class ViewHelper{
function getContent(){
// get together all components for the specific page, also depending on the specific request that's been made.
// get necessary data from the database
}
}
?>Maybe this will work. However, let's take a fresh view from another perspective. The designer/developer building the site, using templates.
In my ideal situation, the front-end developer would be able to do something like this:
Code: Select all
<?php
// Template: main.tpl.php
?>
<?php getHeader(); ?>
<div id="content">
<!-- more html here .. -->
<?php if(has_content()) : while (has_content()) : ?>
<div id="section"><?php the_content(); ?></div>
<?php endwhile; else: ?>
<p>Sorry, no content exists for the criteria you searched for</p>
<?php endif; ?>
<!-- more html -->
<!-- more html -->
<?php getSidebar(); ?>
<?php getFooter(); ?>
<?php
// template: header.tpl.php
?>
<html>
<title><?php the_title('optional','arguments'); ?></title>
<link href="<?php the_stylesheet(); ?>" rel="stylesheet" type="text/css" />
<!-- more html -->
</head>
<body>
<ul id="mainnav"><?php the_menu('some','arguments'); ?></ul>But, of course, depending on the request, the controllers should still do their job of putting together the correct response depending on the request. I think that you have two kinds of logic here: controller logic and view logic. Controller logic is "intelligent": deciding what to do depending on the request. View logic is "dumb": only deciding what to show depending on the request
Example controller logic:
GET: mysite/page
controller decides the view should display that page
POST: mysite/page
A form has been submitted to the page. The controller handles that POST request, maybe updating something in the db (done by the model of course), etc
GET: mysite/blog/
The View decides to show a list of recent posts
GET: mysite/blog/2006/10/
The View decides to show all posts from 2006/10.
All in all a long story and a lot of questions. I guess the main question is: how do you guys put together the View component (in MVC) in more complex websites?