简介中我们提到过,布局视图在整个应用中是共享的,它包裹控制器视图。一个布局视图通常包含一些普通的页面元素,例如:头部、底部、导航、内容区(显示视图输出)。布局视图常常被分为独立的子视图。例如,页面头部可能就是一个子视图,全局的导航又是另一个,等等。主视图包含子视图的引用。你可以使用受保护属性$_layout_default来指定应用的主视图。
下面这张图显示了主视图文件和外部容器、黄色容器及每个子视图的关系。每个容器的定位是通过层叠样式表(CSS)完成的。
外部和黄色区域代表主视图。_head.php部分是页面源代码的一部分,但是它并不在屏幕上显示。
让我们把第一章创建的博客变成上图的样子。
我们要做的第一件事就是指定博客应用使用哪个布局。记住Acme_App_Blog应用类继承自Acme_Controller_Page类。
切换至SYSTEM/source/acme/Acme/Controller目录,编辑文件Page.php。
$ cd SYSTEM/source/acme/Acme/Controller/ $ vim Page.php
在类中加入以下代码,就像下面这样:
<?php abstract class Acme_Controller_Page extends Solar_Controller_Page { /** * * Sets up the Acme_App environment. * * @return void * */ protected function _setup() { parent::_setup(); // set the default layout for all applications that // extend Acme_Controller_Page $this->_layout_default = 'blog'; } } ?>
![]()  | Note | 
|---|---|
| 
                         你也可能通过定义保护属性 
  | 
这里,默认布局是blog.php,且位于SYSTEM/source/acme/Acme/Controller/Page/Layout目录。
$ cd SYSTEM/source/acme/Acme/Controller/Page/Layout $ vim blog.php
在默认布局中粘贴以下代码。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <?php // generate the <head> include $this->template('_head.php'); ?> <?php // generate the <body> include $this->template('_body.php'); ?> </html>
这是我们的主视图脚本。其中引用了2个子视图,分别是_head.php和_body.php。
现在我们要创建子视图_head.php。假设你仍然在SYSTEM/source/acme/Acme/Controller/Page/Layout目录下,创建_head.php文件。
$ vim _head.php
在文件中粘贴以下代码并保存文件。
<head>
    <?php 
    // use the Solar_View_Head::head() helper 
    // add a base stylesheet, then set any other head elements
    echo $this->head()->addStyleBase('Acme/Controller/Page/styles/blog.css')
                      ->fetch(); 
    ?>
</head>
                    这个视图脚本负责处理<head></head>标签的内容。它通过Solar_View_Helper_Head辅助类设置主样式表及添加其他头部元素。详情请查看Solar_View_Helper_Head辅助类的API文档。
假设你仍然在SYSTEM/source/acme/Acme/Controller/Page/Layout目录下,创建_body.php文件。
$ vim _body.php
在文件中粘贴以下代码并保存文件。
<?php // set the id of the body tag. Handy for css and javascript ?> <body id="<?php echo "{$this->controller}-page" ?>"> <div id="wrap"> <div id="header"> <?php include $this->template('_header.php'); ?> </div> <div id="nav"> <?php include $this->template('_nav.php'); ?> </div> <div id="main"> <?php // Add the content from the application controller ?> <?php echo $this->layout_content; ?> </div> <div id="footer"> <?php include $this->template('_footer.php'); ?> </div> </div> </body>
视图脚本定义了页面的结构。层叠样式表定义了每个页面元素的样式。页面的每一个元素,例如页面头部(header),都有自己的子视图脚本。应用程序的控制器动作输出通过$this->layout_content属性注入到视图中。
假设你仍然在SYSTEM/source/acme/Acme/Controller/Page/Layout目录下,创建_header.php文件。
$ vim _header.php
在文件中粘贴以下代码并保存文件。
<div id="branding">
    <h1>The Acme Blog</h1>
</div>
                    这个简单的子视图创建了页面顶部的横幅。
现在,仍然在这个目录下创建_footer.php文件。
$ vim _footer.php
在文件中粘贴以下代码并保存文件。
<div id="footer">
    <p>Copyright © 2010 Acme</p>
</div>
                    这个简单的子视图创建了页面底部的页脚。
接下来,我们要创建导航元素。假设你仍然在SYSTEM/source/acme/Acme/Controller/Page/Layout目录下,创建_nav.php文件。
$ vim _nav.php
在文件中粘贴以下代码并保存文件。
<div id="nav">
    <ul>
        <li><?php echo $this->action('blog', 'Blog Home'); ?></li>
        <li><?php echo $this->action('blog/add', 'ACTION_ADD'); ?></li>
        <li><?php echo $this->action('blog/drafts', 'View Drafts'); ?></li>
    </ul>
    <?php // allow for extra local navigation
    include $this->template('_local.php'); 
    ?>
</div>
                    注意对子视图_local.php的引用。添加此子视图让我们可以选择性地为每个控制器添加额外的导航。这将在本章后面变得更清晰。
![]()  | Note | 
|---|---|
| 
                         导航视图中的第二个列表项使用本地键作为链接文字。 <?php echo $this->action('blog/add', 'ACTION_ADD'); ?>
                        请参考Solar_View_Helper_Action辅助类的API文档和第一章对本地化的介绍。  | 
在同一个目录下创建_local.php文件。
$ vim _local.php
在文件中粘贴以下代码并保存文件。
<?php
// placeholder for local navigation
                所有的布局视图都建好了。现在,在SYSTEM/source/acme/Acme/Controller/Page/Layout目录下应该有这些文件:
Acme/Controller/Page/
    Layout/
        _body.php
        _footer.php
        _head.php
        _header.php
        _local.php
        _nav.php
        blog.php
                    ![]()  | Note | 
|---|---|
| 
                         尽管不是必须的,但是以下划线开始命名局部视图、嵌套视图或布局能让你迅速辨别它们。  | 
现在你去访问博客应用的话,视觉上肯定会让你很失望。在_head.php文件中,我们引用了样式表blog.css。这个样式表负责定位页面元素、设置字体及颜色。我们现在就来创建它。
首先,在SYSTEM/source/acme/Acme/Controller/Page/Public目录下创建子目录“styles”。
$ cd ../Public $ mkdir styles $ cd styles
接下来,在刚建的目录下创建CSS文件blog.css。
$ vim blog.css
在文件中粘贴以下代码并保存文件。
body, html {
    margin: 0;
    padding: 0;
    color: #000;
    background-color: #fff;
    font-family: sans-serif;
    font-size: 10pt;
}
#wrap {
    width: 750px;
    margin:0 auto;
    background-color: #ccc;
}
#header {
    background-color: #666;
    margin: 0px;
    color: #fff;
    margin-top: 10px;
}
#header h1 {
    margin: 0;
    padding: 10px;
}
#nav {
    background-color: #ccc;
    width: 150px;
    float: left;
}
#main {
    float: left;
    width: 580px;
    background-color: #efefef;
    padding: 10px;
    min-height: 400px;
}
#main h2 {
    margin-top: 0px;
    padding-top: 0px;
}
#footer {
    background-color: #000;
    color: #fff;
    font-weight: bold;
    clear: both;
    padding: 5px;
}
#footer p {
    padding: 0px;
    margin: 0px;
}
                    我们刚才做的事如下:
Acme/Controller/Page/
    Public/
        styles/
            blog.css
                    ![]()  | Note | 
|---|---|
| 
                         
  | 
现在我们来看一下博客的首页(http://localhost/blog),应该和下图一样:

因为布局是共享的,它们极大地减少了代码的重复。但是有时候在某些特殊应用中,你可能想更换页面的某些元素。模块化方式布局和Solar的类栈(类层次)机制使这种任务非常简单。例如,如果我们想在主导航下面创建某个特殊应用的链接,我们只要简单的覆盖_local.php布局脚本即可。
在SYSTEM/source/acme/Acme/App/Blog/Layout目录下创建新文件_local.php。
$ cd SYSTEM/source/acme/Acme/App/Blog/Layout $ vim _local.php
在文件中粘贴以下代码并保存文件。
<ul>
    <li><a href="#">Local Item One</a></li>
    <li><a href="#">Local Item Two</a></li>
</ul>
                    现在,刷新浏览器,你将看到左边导航发生了变化。在这里,原先在SYSTEM/source/acme/Acme/Controller/Page/Layout目录下的_local.php文件被SYSTEM/source/acme/Acme/App/Blog/Layout目录下的_local.php文件覆盖。
Solar使用和应用相关度最大的文件。如果它没有找到它要找的信息,它将会继续在类栈(层次)中向上查找。
下面是一个布局类栈的示例:
Array
(
    [0] => Acme/App/Blog/Layout
    [1] => Acme/Controller/Page/Layout
    [2] => Solar/Controller/Page/Layout
)
                    注意到Acme_App_Blog继承自Acme_Controller_Page,而Acme_Controller_Page又继承自Solar_Controller_Page。知道这个将帮助你理解Solar的类栈是如何构建的。
![]()  | Note | 
|---|---|
| 
                         你可以在控制器中设置  | 

![[Note]](images/note.png)

