2010年8月1日 星期日

Zend Framework - Zend_Layout

過去寫網頁時,假設每個網頁的開頭及結尾部份圴是相同的,不論是CSS或HTML,常常將一個網頁分成header, wrapper及footer。這種方法固然好用,但每次新增一個網頁時,又得include header及footer。而現在使用Zend Framework的Zend_Layout之後,每當有需要修改時,僅需修改menun及所對應的content即可,如下圖:


如左圖,整個網頁就只有layout這個版面。當使用者在URL裡KEY上D.N. 後,系統即立刻執行menuAction, 將menu寫至menu區塊內;而一開始則將index.phtml(首頁)顯示在content的區域中。

當使用者點選menu裡的各項連結後,系統再依據controllerName及actionName,將指定的phtml顯示至content區域。

底下以一個簡單的範例來說明。而接著下圖則為整個專案的目錄結構:


index.php程式碼:

<?php
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 1);
date_default_timezone_set("Asia/Taipei");

$documentRoot = dirname(dirname(__FILE__));
define('DOCUMENTROOT', $documentRoot);
set_include_path(get_include_path()
    .PATH_SEPARATOR.DOCUMENTROOT.'/library/'
    .PATH_SEPARATOR.DOCUMENTROOT.'/application/models/'
);

//Load classes automatically.
require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->setFallbackAutoloader(true);

//Loads the configuration and designates the 'general' section to be loaded.
$config = new Zend_Config_Ini($documentRoot.'/application/configs/config.ini', 'general');
Zend_Registry::set('config', $config);

//Sets the MySQL PDO connection adapter.
$db = Zend_Db::factory($config->db);
Zend_Db_Table_Abstract::setDefaultAdapter($db);
Zend_Registry::set('db', $db);
$db->query("SET NAMES 'utf8'");

$frontController = Zend_Controller_Front::getInstance();
$frontController->setControllerDirectory(DOCUMENTROOT . '/application/controllers');

$frontController->registerPlugin(new TS_Controller_Plugin_ActionSetup());
$frontController->registerPlugin(new Ts_Controller_Plugin_ViewSetup(), 98);

//Sets the layout directory.
Zend_Layout::startMvc(
    array('layoutPath' => DOCUMENTROOT.'/application/views/layouts')
);

//Runs the application.
$frontController->dispatch();

config.ini設定:

[general]
db.adapter = PDO_MYSQL
db.params.host = localhost
db.params.username = root
db.params.password = 1234
db.params.dbname = ts
date_default_timezone = Asia/Taipei

layout.phtml程式碼:

<?php echo layout()->content;?>
<?php echo layout()->menu;?>

其中layout()->content即每次依據Controller及Action決定phtml要顯示的區域,而layout->menu則為稍後IndexController的menuAction指定$mainMenu要顯示的區域。

ActionSetup.php程式碼:

<?php
class TS_Controller_Plugin_ActionSetup extends Zend_Controller_Plugin_Abstract{
    public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request){
        $front = Zend_Controller_Front::getInstance();
        if(!$front->hasPlugin('Zend_Controller_Plugin_ActionStack')){
            $actionStack = new Zend_Controller_Plugin_ActionStack();
            $front->registerPlugin($actionStack, 97);
        }else{
            $actionStack = $front->getPlugin('Zend_Controller_Plugin_ActionStack');
        }
       
        $menuAction = clone($request);
        $menuAction->setActionName('menu')
                ->setControllerName('index');
        $actionStack->pushStack($menuAction);
    }
}

此為index.php指定執行的plugin,主要功能為使用者僅需在URL內key入DB,系統不只會執行index.php,亦會執行IndexController內的menuAction。而menuAction內則指定選單的名稱、對應的URL,並將Renderer指向layout.phtml的layout()->menu。

IndexController程式碼:

<?php
class IndexController extends Zend_Controller_Action
{

    public function init()
    {
        /* Initialize action controller here */
       
    }
   
    public function indexAction(){
        // action body
    }

    public function menuAction(){
        // action body
        $mainMenu = array(
            array('title' => 'Home',
                'url' => $this->view->url(array(), null, true)
            ),
            array('title' => 'db',
                'url' => $this->view->url(array('controller' => 'db', 'action' => 'call'), null, true)
            )
        );
       
        $this->view->menu = $mainMenu;
        $this->_helper->viewRenderer->setResponseSegment('menu');
    }
}

接下來在IndexController的MenuAction裡的超連結$mainMenu,則會在layout樣版上的menu區塊裡顯示。(若有其它需求,則自行套CSS即可)而每個menu的Controller, Action的執行結果,均會顯示在layout->content()區域。而首頁則是會將/view/script/index/index.phtml顯示於layout->content()區。

沒有留言:

張貼留言