PHP.MVC的模板标签系统(四)

  页面布局

  在这个单元中我们将看到如何使用模板标签系统构造一个标准的模板页面。这个例子我们使用了一个简单的HTML页面布局,请看下图:

PHP.MVC的模板标签系统(四)

  这个页面有多个标准单元组成,就像页面设计者和开发者熟悉的那样.这个页面的主体由3个包含的单元组成:页眉,页内容主体和页脚.我们现在就看看这些单元并且了解如何使用模板标签系统来实现.

  页主体

  下面的代码单元显示的是主体:

  The Page Body Layout

  1

  <@ saleMonth    = data.getValueBean('SALE_MONTH') @>

  <@ saleTitle    = data.getValueBean('SALE_TITLE') @>

  <@ dealHeading  = data.getValueBean('DEAL_HEADING') @>

  <@ salesAreaID  = "Central District" @>

  <html>

  <head>

  <link rel='stylesheet' type='text/CSS' href="./style/pageStyles.css"/>

  <title>

  2     <@ =viewConfig.getAppTitle @>

  </title>

  </head>

  <body>

  <table class='pageLayoutTable'>

  <!-- PAGE HEADER -->

  <tr>

  <td class='pageHeader'>

  <!-- including the page header component -->

  <!-- The base template base directory is "./tpl"  -->

  3        <@ include 'pageHeader.ssp' @>

  </td>

  </tr>

  <!-- PAGE CONTENTS -->

  <tr valign='top'>

  <td class='pageContent'>

  <!-- including the page contents component -->

  4        <@ include 'sale/pageContent.ssp' @>

  </td>

  </tr>

  <!-- PAGE FOOTER -->

  <tr>

  <td class='pageFooter'>

  <!-- including the page footer omponent -->

  5        <@ include 'pageFooter.ssp' @>

  </td>

  </tr>

  </table>

  </body>

  </html>

  1:页声明

  第一个有趣的条目是页顶部的页声明(1).我们在页面开始声明了这些变量,因此这些变量将能在下面的页面和像页眉那样的包含页所使用.

  2:页标题

  下一步我们使用表达式来初始化页面标题(2).这个值能够从配置文件中view-resources元素利用ViewResourcesConfig->getAppTitle来得到:

  <view-resources

  appTitle = "Flash Jacks' Sleek Tab Site"

  ...

  </view-resources>

  3:页眉

  页眉是下一个有趣的条目(3).在这里我们使用包含指令来插入页眉模板文件到页主体中.我们将在下一个子单元中来看一看页眉.

  我们仅仅使用了页面直接去读取页眉,不论页的组件存储在哪里.这是一个好机会来介绍模板标签系统的目录设置.默认情况下,模板目录布局如下所示(注意这些路径相对于我们的应用程序):

  The Default PhpMVC_Tags Template Directory Layout Paths (relative)

  The Template Files  './WEB-INF/tpl'

  The Compiled Template Files  './WEB-INF/tpl_C'

  如果需要的话我们可以在配置文件的view-resources结点来重新定义他们,就像这样:

  <view-resources

  ...

  tplDir   = "./WEB-INF/tpl-admin"

  tplDirC  = "./WEB-INF/tpl_admin_C"

  ...

  </view-resources>

  4:页内容主体

  这是另外一个包含指令被用来插入模板文件(4)到主体中.注意包含的文件位于模板目录的sales子目录中:

  "./WEB-INF/tpl/sale/pageContent.ssp"

  5:页脚

  又是一个包含指令,就像页眉一样.

  页眉单元

  在这个例子中页眉模板文件('pageHeader.ssp')只是一个简单的单元,就像这样:

  <!-- Page Header -->

  <span>

  <@ =viewConfig.getAppTitle @>

  </span>

  当主体页面(包括包含的页面)被编译的时候,页眉的表达式被转换成下面这样:

  <!-- Page Header -->

  <span>

  <?php print $viewConfig->getAppTitle(); ?>

  </span>

  被编译的页面被存储在编译模板目录中,就像上面所说的,默认的编译模板目录是:

  './WEB-INF/tpl_C'

  页内容主体单元

  页内容主体模板文件有一点复杂.文件('sale/pageContent.ssp')内容显示如下:

  ...

  1

  <@ item1=data->getValueBean("ITEM_1") @>

  <@ products=data->getValueBean("PRODUCTS_ARRAY") @>

  2

  <h4><@=dealHeading @> <@=saleMonth @></h4>

  3

  <b>Clearance deals</b>

  <table class='productsTable'>

  <tr>

  <td class='prodItemDesc'>

  <@ =item1.getName @>

  </td>

  <td class='prodItemValue'>

  <@ =item1.getCost @>

  </td>

  </tr>

  </table>

  4

  <b>Todays specials</b>

  <table class='productsTable'>

  <?php foreach($products as $item) { ?>

  <tr>

  <td class='prodItemDesc'>

  <@ =item.getName @>

  </td>

  <td class='prodItemValue'>

  <@ =item.getCost @>

  </td>

  </tr>

  <?php } ?>

  </table>

  <b>Our Staff at Your Service</b>

  ...

  5

  <table class='productsTable'>

  <tr>

  <td class='prodItemDesc'>

  <b>Area Manager: </b>

  </td>

  <td class='prodItemDesc'>

  <@ =viewConfig.getAreaManager @>

  </td>

  </tr>

  ...

  </table>

  1:一些更多的声明

  在页面顶部所显示的额外声明(1)能让我们声明页变量以便下面能够使用.在内容被处理之后,这些声明将在编译后像下面这样显示:

  <?php $item1=$data->getValueBean("ITEM_1"); ?>

  ...

  <?php $products=$data->getValueBean("PRODUCTS_ARRAY"); ?>

  2:使用表达式来显示内容单元标题

  现在我们使用两个表达式(2)来显示内容单元的标题.注意我们声明这些变量是"全局"变量在主页面的顶部.处理完后,表达式将转换这些代码,就像这样:

  <?php print $dealHeading; ?> <?php print $saleMonth; ?>

  当页面被显示到用户的浏览器中,内容单元的标题看起来就像这样:

  Jack's Super Deals for : May 2010.

  3:使用表达式来显示一些数据条目

  现在我们能显示一些实际的数据(3).在这个页内容主体单元中我们访问一些在PhpMVCTabAction类的ActionObject中的产品条目数据.一个简化版的PhpMVCTabAction类在下面展示:

  class PhpMVCTabAction extends Action {

  ...

  function execute($mapping, $form, &$request, &$response) {

  // Our value bean container

  $valueBeans =& new ValueBeans();

  // Define some strings we need on our View template page

  // These could be defined globally in the phpmvc-config.xml file.

  // See: ExtendedController example.

  $appTitle      = "Flash Jack's Include Page";

  $saleMonth     = "May 2010";

  $saleTitle     = "Flash Jack's Super Sale";

  $dealHeading   = "Jack's Super Deals for :";

  ...

  // Save the string variables to our Value object

  $valueBeans->addValueBean('APP_TITLE'     , $appTitle);

  $valueBeans->addValueBean('SALE_MONTH'    , $saleMonth);

  $valueBeans->addValueBean('SALE_TITLE'    , $saleTitle);

  $valueBeans->addValueBean('DEAL_HEADING'  , $dealHeading);

  ...

  // Some float values we could receive from a database query

  // Note: The prices are formatted in the Products class constructor.

  // Eg: "$ n,nnn.nn"

  $price1 =  125.00;

  ...

  // Setup some clearance deals (individual object instances):

  // Note: The Product class file was included in our local prepend.php file

  $item1 = new Product('Super Duper', $price1);

  ...

  $valueBeans->addValueBean('ITEM_1', $item1);

  ...

  // Todays specials (array of object instances)

  $products = array();

  $products[] = new Product('Gooses Bridle', $price3);

  ...

  $valueBeans->addValueBean('PRODUCTS_ARRAY', $products);

  // Our staff

  $staff1 =& new Staff('Bruce', 'Sales', 'Karate');

  ...

  $valueBeans->addValueBean('STAFF_1', $staff1);

  ...

  // Save the Value object

  $this->saveValueObject($request, $valueBeans);

  在上面的代码中,我们能看到$item1被创建并被保存成ActionObject的valueBeans条目.Bean数据条目现在能在模板页面中被重新获得:

  <@ item1=data->getValueBean("ITEM_1") @>

  我们可以像下面那样显示条目的值:

  <@ =item1.getName @>

  ...

  <@ =item1.getCost @>

  4:显示数组

  我们也可以直接使用一些PHP代码在我们的模板页上.在这个分离的MVC模式中,我们应该仅在这里编写代码去操纵这些通过ActionObject和ViewResourcesConfig实例(可能我们的自定义Bean也可以)提供的数据.在上面的也内容单元('sale/pageContent.ssp')中,我们使用一个PHP的foreach语法(4)来循环读取$products数组.我们能在上面的PhpMVCTabAction类中看到$products数组被创建并被保存在ActionObject中,就和上面的$item1 Bean相似.在foreach循环中我们能使用表达式来显示产品数据:

  <?php foreach($products as $item) { ?>

  <tr>

  <td class='prodItemDesc'>

  <@ =item.getName @>

  </td>

  <td class='prodItemValue'>

  <@ =item.getCost @>

  </td>

  </tr>

  <?php } ?>

  5:显示ViewResourcesConfig属性

  最后我们从view-resources元素所定义的ViewResourcesConfig属性来显示"Area Manager"(5)在我们的内容页:

  <view-resources

  appTitle    = "Flash Jacks' Sleek Tab Site"

  ...

  className   = "MyViewResourcesConfig">

  <!-- We can set some properties on our custom ViewResourcesConfig class        -->

  <set-property property="areaManager" value="Joe J. Blogs Esq."/>

  </view-resources>

  但是注意在这个例子中我们使用了一个继承ViewResourcesConfig类的对象(MyViewResourcesConfig)来设置一些自定义的属性.我们定义了一个扩展ViewResourcesConfig类的对象,在配置文件里使用className="MyViewResourcesConfig"属性,并且MyViewResourcesConfig类定义在文件"MyViewResourcesConfig.php"中.MyViewResourcesConfig类(classes/MyViewResourcesConfig.php)实现了setter/getter方法去处理自定义属性("areaManager"),这个属性我们在view-resources结点中定义:

  class MyViewResourcesConfig extends ViewResourcesConfig {

  // ----- Properties ----------------------------------------------------- //

  var $areaManager = '';

  function getAreaManager() {

  return $this->areaManager;

  }

  function setAreaManager($areaManager) {

  $this->areaManager = $areaManager;

  }

  我们现在能使用表达式在我们的页面上实现"Area Manager"了:

  <@ =viewConfig.getAreaManager @>

  注意:在真实的应用程序中数据能从关系型数据库中得到.

  页脚单元

  页脚单元和上面讨论过的页眉单元的处理相类似.页脚模板文件('tpl/pageFooter.ssp')就像这样:

  <!-- Page Footer -->

  <span>

  <@ =viewConfig.getCopyright @>

  </span>

  当主体页面(包括包含的页面)被编译,在页脚中的表达式被转换成下面这样:

  <!-- Page Footer -->

  <span>

  <?php print $viewConfig->getCopyright(); ?>

  </span>

  编译的页眉页面被存储在编译模板目录.默认的编译模板目录是:

  './WEB-INF/tpl_C'