简介中我们提到过,布局视图在整个应用中是共享的,它包裹控制器视图。一个布局视图通常包含一些普通的页面元素,例如:头部、底部、导航、内容区(显示视图输出)。布局视图常常被分为独立的子视图。例如,页面头部可能就是一个子视图,全局的导航又是另一个,等等。主视图包含子视图的引用。你可以使用受保护属性$_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)

