Following this tutorial http://johnsquibb.com/tutorials/mvc-framework-in-1-hour-part-one Im trying to write my first MVC Blog.
遵循本教程http://johnsquibb.com/tutorials/mvc- frameworkin -1-hour-part-one我正在尝试编写我的第一个MVC博客。
I understood how it works, router.php Calls the suitable page controller. This controller calls the model, Then calls the View page with the returned value.
我理解它的工作原理,路由器。php调用合适的页面控制器。该控制器调用模型,然后调用返回值的视图页面。
My question is, What if I want to add to the same news.php page a header\footer. Normally I would write "include("header.php"). But now when using MVC, how could I implement that?
我的问题是,如果我想增加同样的新闻呢?php页面页眉、页脚。通常我会写“include(header.php)”。但是现在使用MVC时,我怎么实现它呢?
These are my files:
这些是我的文件:
router.php:
router.php:
<?php
/**
* This controller routes all incoming requests to the appropriate controller
*/
//Automatically includes files containing classes that are called
//fetch the passed request
$pageURL = $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
$path_parts = pathinfo($pageURL);
$page_name = $path_parts['filename'];
$parsed = explode('?' , $page_name);
//the page is the first element
$page = array_shift($parsed);
// If there is any variables, GET them.
if(!empty($parsed))
{
$parsed = explode('&' , $parsed[0]);
$getVars = array();
foreach ($parsed as $argument)
{
//explode GET vars along '=' symbol to separate variable, values
list($variable , $value) = explode('=' , $argument);
$getVars[$variable] = urldecode($value);
}
}
//compute the path to the suitable file
$target ='controllers/' . $page . '_controller.php';
//get target controller
if (file_exists($target))
{
include_once($target);
//modify page to fit naming convention
$class = ucfirst($page) . '_Controller';
//instantiate the appropriate class
if (class_exists($class))
{
$controller = new $class;
}
else
{
//did we name our class correctly?
die('class does not exist!');
}
}
else
{
//can't find the file in 'controllers'!
die('page does not exist!');
}
//once we have the controller instantiated, execute the default function
//pass any GET varaibles to the main method
$controller->main($getVars);
// AutoLoad
function __autoload($className)
{
// Parse out filename where class should be located
// This supports names like 'Example_Model' as well as 'Example_Two_Model'
list($suffix, $filename) = preg_split('/_/', strrev($className), 2);
$filename = strrev($filename);
$suffix = strrev($suffix);
//select the folder where class should be located based on suffix
switch (strtolower($suffix))
{
case 'model':
$folder = '/models/';
$filename = ($className);
break;
case 'library':
$folder = '/libraries/';
break;
case 'driver':
$folder = '/libraries/drivers/';
break;
}
//compose file name
$file = SERVER_ROOT . $folder . strtolower($filename) . '.php';
//fetch file
if (file_exists($file))
{
//get file
include_once($file);
}
else
{
//file does not exist!
die("File '$filename' containing class '$className' not found in
'$folder'.");
}
}
?>
post_controller.php
post_controller.php
<?php
/**
* This file handles the retrieval and serving of posts posts
*/
class Posts_Controller
{
/**
* This template variable will hold the 'view' portion of our MVC for this
* controller
*/
public $template = 'posts';
/**
* This is the default function that will be called by router.php
*
* @param array $getVars the GET variables posted to index.php
*/
public function main(array $getVars)
{
//$b_controller =new Bottom_Bar_Controller;
//$b_controller->main($getVars);
$postsModel = new Posts_Model;
//get an post
$post = $postsModel->get_post($getVars['id']);
//create a new view and pass it our template
$header = new View_Model('header_template');
$bottom_bar = new View_Model('bottom_bar');
$view = new View_Model($this->template);
//assign post data to view
$view->assign('header', $header->render(FALSE));
$view->assign('bottom', $bottom_bar->render(FALSE));
$view->assign('title' , $post['title']);
$view->assign('content' , $post['content']);
$view->assign('date' , $post['date']);
$view->assign('by' , $post['added_by']);
$view->render();
}
}
posts_model.php
posts_model.php
<?php
/**
* The Posts Model does the back-end heavy lifting for the Posts Controller
*/
class Posts_Model
{
/**
* Holds instance of database connection
*/
private $db;
public function __construct()
{
$this->db = new MysqlImproved_Driver;
}
/**
* Fetches article based on supplied name
*
* @param string $author
*
* @return array $article
*/
public function get_post($id)
{
//connect to database
$this->db->connect();
//sanitize data
$author = $this->db->escape($id);
//prepare query
$this->db->prepare
(
"
SELECT * FROM `posts`
WHERE
`id` = '$id'
LIMIT 1
;
"
);
//execute query
$this->db->query();
$article = $this->db->fetch('array');
return $article;
}
}
?>
view_model.php
view_model.php
<?php
/**
* Handles the view functionality of our MVC framework
*/
class View_Model
{
/**
* Holds variables assigned to template
*/
private $data = array();
/**
* Holds render status of view.
*/
private $render = FALSE;
/**
* Accept a template to load
*/
public function __construct($template)
{
//compose file name
$file = SERVER_ROOT . '/views/' . strtolower($template) . '.php';
if (file_exists($file))
{
/**
* trigger render to include file when this model is destroyed
* if we render it now, we wouldn't be able to assign variables
* to the view!
*/
$this->render = $file;
}
}
/**
* Receives assignments from controller and stores in local data array
*
* @param $variable
* @param $value
*/
public function assign($variable , $value)
{
$this->data[$variable] = $value;
}
/**
* Render the output directly to the page, or optionally, return the
* generated output to caller.
*
* @param $direct_output Set to any non-TRUE value to have the
* output returned rather than displayed directly.
*/
public function render($direct_output = TRUE)
{
// Turn output buffering on, capturing all output
if ($direct_output !== TRUE)
{
ob_start();
}
// Parse data variables into local variables
$data = $this->data;
// Get template
include($this->render);
// Get the contents of the buffer and return it
if ($direct_output !== TRUE)
{
return ob_get_clean();
}
}
public function __destruct()
{
}
}
posts.php
php
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link href="../style/style.css" rel="stylesheet" type="text/css" media="screen" />
<title> Posts (View)</title>
</head>
<body>
<div id="main">
<div class="container">
<?=$data['header'];?>
<div id="content">
<div class="content-background">
<h2> <?=$data['title'];?></h2>
<h4> <?=$data['date'];?> </h4>
<p><?=$data['content'];?></p>
</div>
</div>
</div>
</div>
</body>
</html>
2 个解决方案
#1
5
Part of the problem is, that your tutorial has a pretty primitive interpretation of MVC-inspired design pattern (you actually cannot implement classical MVC in PHP, but there are patterns, that are based on it).
问题的一部分是,您的教程对受MVC启发的设计模式有一种非常原始的解释(实际上您不能在PHP中实现经典的MVC,但是有一些模式是基于它的)。
View is not just a template. Views are supposed to be class instances, which contain all presentation logic and deal with multiple templates. What you actually have there is a layout
template which contains posts
template.
视图不仅仅是一个模板。视图应该是类实例,它包含所有的表示逻辑并处理多个模板。您实际拥有的是一个包含posts模板的布局模板。
// class \Application\View\Posts
public function render()
{
$layout = new Template( $this->defaultTemplateDirectory . 'layout.html');
$content = new Template( $this->defaultTemplateDirectory . 'posts.html' );
$layout->assign( 'content' , $content->render() );
return $layout->render();
}
Also, one of the things, that a view instance should do, is requesting information from the model layer.
另外,视图实例应该做的一件事是请求模型层的信息。
Few materials that you might find useful:
你可能会发现一些有用的材料:
- Model-View-Confusion part 1: Why the model is accessed by the view in MVC
- 模型-视图-混淆第1部分:为什么模型被MVC中的视图访问
- Simple PHP Template Engine
- 简单的PHP模板引擎
- How should a model be structured in MVC?
- 模型应该如何在MVC中进行结构化?
And if you want to expand you knowledge in OOP, this post contains a list of recommended lectures and books.
如果你想扩展你在OOP的知识,这篇文章包含了推荐的讲座和书籍列表。
#2
2
There is no good solution in the MVC structure for that. You can find a solution in every framework. In CakePHP for example you can use an AppController, a controller which is always called for every requests. Sort of base controller.
在MVC结构中没有好的解决方案。您可以在每个框架中找到解决方案。例如,在CakePHP中,您可以使用AppController,一个总是为每个请求调用的控制器。控制器的基础。
But no, not very nice to do.
但不,这样做不太好。
Most simple one is to ask the data directly from the view. That sounds weird but it is accepted in the MVC structure. So in your view you call $News->getLatestItems(10); and work with them.
最简单的方法是从视图中直接询问数据。这听起来很奇怪,但在MVC结构中是可以接受的。在你的视图中你调用$News->getLatestItems(10);并与他们一起工作。
I don't like it but it works.
我不喜欢,但它起作用了。
If you have lots of widgets and blocks MVC alone might just not be the right structure. Then you could take a look at things like: http://techportal.inviqa.com/2010/02/22/scaling-web-applications-with-hmvc/ which is a derivate of MVC.
如果您有很多小部件和模块,那么MVC本身可能不是正确的结构。然后您可以查看以下内容:http://techportal.inviqa.com/2010/02/22/scaling-web应用程序-with-hmvc/,这是MVC的派生。
Another solution which you see more and more: Request it via AJAX calls. So just load them after the page has loaded. That way you also solve the issue since one MVC request then becomes multiple MVC requests.
您会看到越来越多的另一个解决方案:通过AJAX调用请求它。所以只要在页面加载之后加载它们。这样也可以解决这个问题,因为一个MVC请求变成了多个MVC请求。
#1
5
Part of the problem is, that your tutorial has a pretty primitive interpretation of MVC-inspired design pattern (you actually cannot implement classical MVC in PHP, but there are patterns, that are based on it).
问题的一部分是,您的教程对受MVC启发的设计模式有一种非常原始的解释(实际上您不能在PHP中实现经典的MVC,但是有一些模式是基于它的)。
View is not just a template. Views are supposed to be class instances, which contain all presentation logic and deal with multiple templates. What you actually have there is a layout
template which contains posts
template.
视图不仅仅是一个模板。视图应该是类实例,它包含所有的表示逻辑并处理多个模板。您实际拥有的是一个包含posts模板的布局模板。
// class \Application\View\Posts
public function render()
{
$layout = new Template( $this->defaultTemplateDirectory . 'layout.html');
$content = new Template( $this->defaultTemplateDirectory . 'posts.html' );
$layout->assign( 'content' , $content->render() );
return $layout->render();
}
Also, one of the things, that a view instance should do, is requesting information from the model layer.
另外,视图实例应该做的一件事是请求模型层的信息。
Few materials that you might find useful:
你可能会发现一些有用的材料:
- Model-View-Confusion part 1: Why the model is accessed by the view in MVC
- 模型-视图-混淆第1部分:为什么模型被MVC中的视图访问
- Simple PHP Template Engine
- 简单的PHP模板引擎
- How should a model be structured in MVC?
- 模型应该如何在MVC中进行结构化?
And if you want to expand you knowledge in OOP, this post contains a list of recommended lectures and books.
如果你想扩展你在OOP的知识,这篇文章包含了推荐的讲座和书籍列表。
#2
2
There is no good solution in the MVC structure for that. You can find a solution in every framework. In CakePHP for example you can use an AppController, a controller which is always called for every requests. Sort of base controller.
在MVC结构中没有好的解决方案。您可以在每个框架中找到解决方案。例如,在CakePHP中,您可以使用AppController,一个总是为每个请求调用的控制器。控制器的基础。
But no, not very nice to do.
但不,这样做不太好。
Most simple one is to ask the data directly from the view. That sounds weird but it is accepted in the MVC structure. So in your view you call $News->getLatestItems(10); and work with them.
最简单的方法是从视图中直接询问数据。这听起来很奇怪,但在MVC结构中是可以接受的。在你的视图中你调用$News->getLatestItems(10);并与他们一起工作。
I don't like it but it works.
我不喜欢,但它起作用了。
If you have lots of widgets and blocks MVC alone might just not be the right structure. Then you could take a look at things like: http://techportal.inviqa.com/2010/02/22/scaling-web-applications-with-hmvc/ which is a derivate of MVC.
如果您有很多小部件和模块,那么MVC本身可能不是正确的结构。然后您可以查看以下内容:http://techportal.inviqa.com/2010/02/22/scaling-web应用程序-with-hmvc/,这是MVC的派生。
Another solution which you see more and more: Request it via AJAX calls. So just load them after the page has loaded. That way you also solve the issue since one MVC request then becomes multiple MVC requests.
您会看到越来越多的另一个解决方案:通过AJAX调用请求它。所以只要在页面加载之后加载它们。这样也可以解决这个问题,因为一个MVC请求变成了多个MVC请求。