hSATAC

>> ('cat' + 'ash').reverse #=> "hsatac"

延伸 MVC 的 v - 以 CodeIgniter 為例

今天在 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));
 ?>
 
 

Comments