今天在 CodeIgniter#irc.freenode.net 有位網友拋出了這篇文章討論 Extending the V in MVC
稍微看了一下,其實概念和 Ruby on Rails 的架構一樣,
主要是引進了 partial 以及 layout 的概念。
(原文用 layout,但我認為用format應該比較洽當。)
partial 就是是部份樣板,增加 view 的可重用性,這沒什麼特殊的。
而 format 的部份則是比較有趣的部份,
controller 只要負責丟出資料,而用什麼格式 (layout, format) 來呈現,
則交給 view 來做,讓「資料」和「畫面」分割的更徹底。
以實例說明,就是同樣的 controller ,url 加個不同的副檔名,就會用不同的 view 去呈現資料,
例如:
http://blog.hsatac.net/1/format.html 就是一般網頁;
http://blog.hsatac.net/1/format.xml 是xml;
http://blog.hsatac.net/1/format.rss 則是rss
概念雖非創新,但如此在 CodeIgniter 中實做出來,
也頗有可借鏡之處。
這邊把該文的實做貼出,由於文章有段時間了,可能視不同 CI 版本需稍加調整。
Controller:
uri->segment_array();
array_shift($lParams);array_shift($lParams);
$lMethod = $aMethod;
$lLayout = ’xhtml’;
if (strpos($lMethod, ’.’) !== False)
list($lMethod, $lLayout) = explode(’.’, $lMethod);
$this->load->setLayout($lLayout);
$lMethod = (empty($lMethod) ? ’index’ : $lMethod);
if (in_array($lMethod, get_class_methods(get_class($this)))) {
$this->load->setController(get_class($this), $lMethod);
call_user_func_array(array($this, $lMethod), $lParams);
}
else {
show_404($lMethod);
}
}
?>
Loader:
public function partial($aPartial, $aData=array(), $aLayout=null) {
$lLayout = (is_null($aLayout) ? $this->layout : $aLayout);
$lastItem = ’’;
$parts = array();
if (strpos($aPartial, ’/’) !== false) {
$parts = explode(’/’, $aPartial);
$lastItem = array_pop($parts);
}
else {
$lastItem = $aPartial;
}
if ($lastItem{0} !== ’_’) {
$lastItem = ’_’.$lastItem;
}
array_push($parts, $lastItem);
$this->view(implode(’/’, $parts), $aData, $aLayout);
}
public function setLayout($aLayout) {
if (is_dir(APPPATH.’/views/’.$aLayout)) {
$this->layout = $aLayout;
}
}
/**
* @param string $aView
*/
public function view($aView=null, $aData=array(), $aLayout=null) {
if (is_null($aView))
$aView = $this->controllerName.’/’.$this->controllerFunction;
$lLayout = (is_null($aLayout) ? $this->layout : $aLayout);
parent::view($lLayout.DIRECTORY_SEPARATOR.$aView, $aData);
}
public function setController($aControllerName, $aControllerFunction) {
$this->controllerName = $aControllerName;
$this->controllerFunction = $aControllerFunction;
}
?>
接著就可以用不同的 view 來對應同一個 contoller 了
http://someurl/blog/category/5 => APPPATH/xhtml/blog/category
partial(’header’, $data); ?>
partial(’blog/shortsummary’, array(’post’ => $post));
?>
partial(’footer’, $data); ?>
http://someurl/blog/category.rss/5 => APPPATH/views/rss/blog/summary.php
foreach ($posts as $post)
$this->partial(’blog/shortsummary’, array(’post’ => $post));
?>