我们在这个部分关注一下View里Layouts和Blocks。
跟其他主流PHPMVC架构不一样,magento 的ActionController不会把数据对象传给view,也不会设置View对象里的属性。View是通过系统模块去获取它所需要的信息。
这个设计的结果是View被分为Blocks 和Templates。Blocks是PHP对象,Templates是PHP代码和HTML的混合(也可以认为是PHP作为了模版语言)。每个Block绑定到一个Template文件。在一个Phtml文件里,PHP的关键字$this会包含了对Temeplate对应Block的引用。
下面是一个快速的例子。查看模版文件app/design/frontend/base/default/template/catalog/product/list.phtml
会看到如下的代码
<?php$_productCollection=$this->getLoadedProductCollection() ?>
<?phpif(!$_productCollection->count()): ?>
<divclass="note-msg">
<?php echo$this->__("There are no products matching the selection.")?>
</div>
<?php else: ?>
其中的getLoadedProudctController可以在对应的block文件找到
app/code/core/Mage/Catalog/Block/Product/List.php
public functiongetLoadedProductCollection()
{
return$this->_getProductCollection();
}
其中的_getProductCollection会实例化models,并取到数据给对应template。
内嵌Block
Blocks/Templates真正的强大的地方是getChildHtml方法。这可以让我们包含次一级的Block/Template在主的Block/Template里面(xml的格式)
Blocks调用Blocks是会组成我们整个HTMLlayout。看一个例子
App/design/frotend/base/default/template/page/1column.phtml
<!DOCTYPE htmlPUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <htmlxmlns="http://www.w3.org/1999/xhtml" xml:lang="?php echo$this->getLang() ?>" lang="<?php echo $this->getLang()?>"> <head> <?php echo $this->getChildHtml('head') ?></head> <body class="page-popup <?php echo$this->getBodyClass()?$this->getBodyClass():'' ?>"> <?php echo$this->getChildHtml('content') ?> <?php echo $this->getChildHtml('before_body_end') ?>
<?php echo$this->getAbsoluteFooter() ?> </body> </html>
该文件不长,但是每个调用都是$this->getChildHtml(…),这会包含并渲染其他的block。这些block也可能会调用其他block 。
Layout
尽管Block和Template很好,但是你可能会有下面的疑问
1. 我怎么告诉Magento哪个Block在页面中使用?
2. 我们怎么告诉Magento是初始的
3. 我怎么告诉每个Block去调用下面的block
这时候就需要Layout对象了。Layout对象是Xml格式,定义一个页面里包含哪些Blocks,并且哪些Blocks负责渲染页面。
之前的Hello World项目我们直接在Action Method上做的。这次我们创建一个简单的HTMLtemplate来为该模块服务。
首先创建一个文件
App/design/frontend/base/default/layout/local.xml
然后写入下面的内容
<layoutversion="0.1.0">
<default>
<reference name="root">
<block type="page/html"name="root" output="toHtml"template="易做图_page.phtml" />
</reference>
</default>
</layout>
然后再创建一个文件
app/design/frontend/base/default/template/易做图_page.phtml(注意和配置里的template一致)
写入以下内容
<!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<htmlxmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Untitled</title>
<metaname="generator" content="BBEdit 9.2" />
<styletype="text/css">
body { background-color:#f00; }
</style>
</head>
<body>
</body>
</html>
最后在Aciton Controller里负责启动layout过程。增加下面两行代码
public functionindexAction() {
//remove our previous echo
//echo'Hello Index!';
$this->loadLayout();
$this->renderLayout();
}
清除缓存,重新加载Hello World controller页面,可以看到页面的背景hi红色,并且Html源码和易做图_page.phtml也是对应的。
发生了什么?
刚才的一切看上去很神秘。我们来仔细的看看这个过程。首先,我们想安装Layoutviewer模块。这个模块和Configviewer很像。
一旦装好了,就可以用下面的URL
http://localhost/magento/helloworld/index/index?showLayout=page
这个是一个layout xml对应于请求的页面。由<block /> <refenece /> 和 <remove />标签组成。当你调用loadLaout方法时,
1. 生成一个Layout xml
2. 实例化<block/> 和<reference />下面的Block类。查找用标签name属性的,在全局配置文件里找到对应的,并储存在Layout对象的internal_blocks数组里。
3. 如果<block />标签包含了输出属性,它的值也加入到Layout对象的internal_blocks数组里。
这样一来,当我们在Action Controller里调用renderLayout时,Mageno 会迭代_blocks数组里所有的Blocks, 并把它对应的输出属性作为回调函数。这相当于是向Html的转化,意味着Block的Template就是输出的起点。
下面的部分涉及到Block如何实例化,Layout文件如何生成,还有output的结束。
Block实例化
在LayoutXml里,<block/>或者<reference/>有个类型相当于是URI
<block type=”page/html” …
<block type=”page/template_links”