Magento开发文档(四Magento 布局、块 、模板

刚入门magento的开发者容易吧布局和视图给混淆. 本文将看看Magento的Layout/Block的做法,并告诉您如何将其融入Magento的MVC的世界观。

与许多流行的MVC系统相比,Magento的执行控制器不通过数据对象到视图或在视图对象中设置属性(只有少数例外)。相反,视图组件直接引用系统模型来获得它需要显示的信息。

这样的设计决策的后果之一是,视图分成块和模板。块是PHP对象,模板是包含HTML和PHP(在这里PHP作为模板语言)“原始”的PHP文件(带.phtml扩展名)的组合。每一个块都和一个唯一的模板文件绑定。在模板文件 phtml中,“$this”就是指该模板文件对应的块对象。

一个简单的例子

看一个默认的产品模板的文件

你会看到下面的PHP模板代码。

getLoadedProductCollection method方法可以在改模板的Block的class中找到。Mage_Catalog_Block_Product_List找到如图所示

1
2
3
4
5
6
.
public function )
{
return $ this _getProductCollection ;
}
块的_getProductCollection方法实例化模型,并读取它们的数据,其结果返回给模板。

嵌套块

Magento 把视图分离成块和模板的真正强大之处在于“getChildHtml”方法。这个方法可以让你实现在块中嵌套块的功能。顶层的块调用第二层的块,然后是第三层……这就是 Magento如何输出 HTML的。

块调用块调用块是如何为您的网页的整个HTML布局中创建的。看看一列布局模板。

page one - column

1
2
3
4
5
6
7
8
9
10
! 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" xml : lang "?php echo $this->getLang() ?>" "<?php echo $this->getLang() ?>" >
head >
getChildHtml 'head' ?>
/ head >
body "page-popup <?phpgetBodyClass)?):''>
'content' ?>
'before_body_end' ?>
getAbsoluteFooter ?>
body >

模板本身只有11行代码。然而,每次调用$此> getChildHtml(…)将包含和引入另一个块。使用getChildHtml将依次引入另外一个块的HTML 内容,直到最底层的块。

Magento布局文件

到这里,块和模板你大概已经熟悉了,但你可能有以下疑问

  1. Magento 怎么知道在一个页面上要用那些块?
  2. Magento 怎么知道哪一个块是顶层块?
  3. $this->getChildHtml(…)”里面的参数是什么意思?块的名字吗?

Magento 引入了布局对象(Layout Object)来解决上面的那些问题。布局对象(或者说布局文件)就是一个 XML文件,定义了一个页面包含了哪些块,并且定义了哪个块是顶层块。

上次我们是直接从我们的操作方法中输出内容。这一次,让我们为我们的Hello World模块,一个简单的HTML模板。

首先,创建一个文件:

layout local xml

包含以下内容

1
2
3
4
5
layout version "0.1.0" >
< default >
block type "page/html" name "root" output "toHtml" template "magentotutorial/helloworld/simple_page.phtml" / >
/ >
layout 创建模板文件

magentotutorial helloworld simple_page 加入以下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
"-//W3C//DTD XHTML 1.0 Strict//EN"
>
"http://www.w3.org/1999/xhtml" >
>
title > Hello World >
<style type ="text/css">
body {
background-color : #f00 ;
}
</style>
>
< >
>
html 最后,我们要在执行控制器里面调用布局文件,开始输出HTML。我们需要添加两个方法到操作方法。

1
2
3
4
5
6
public function indexAction ( ) {
//remove our previous echo
//echo 'Hello Index!';
$ this -> loadLayout ) ;
renderLayout ;
}

清空Magento缓存并加载你的Hello World器页面(URL“http://exmaple.com/helloworld/index/index”)。现在,你应该可以看到一个明显的红色背景,并且simple_page.phtml的HTML源代码和你打开网站的源码一样。

这是怎么回事呢?

也许你看到这里一头雾水,没关系,我们来慢慢解释

首先,你要安装一个Layout Viewer模块。这类似于你建的Hello World的文章,可以让我们看一些Magento的内部在Configviewer模块一个模块。

一旦你安装了这个模块(类似于你如何设置Configviewer模块),请访问以下网址

1
http : //example.com/helloworld/index/index?showLayout=page

这是你正在请求页面的布局XML文件,它由<block />,<reference /> 和 <remove />标签组成. 当你调用方法控制器中的loadLayout时,Magento 将

  1. 生成布局的XML文件
  2. 为每一个<block />标签生成一个Block类,查找使用标签的type属性的类作为一个全局性的配置路径,并将其保存在布局对象internal_blocks数组中,使用标签的name属性为数组的key。
  3. 如果<block />标签包含一个输出属性,它的值将被添加到布局对象的internal_output数组中。

然后,当你在你的动作控制器调用renderLayout方法是,Magento将在_output数组中遍历所有的块,使用输出属性的值作为一个回调方法。这始终是toHtml,以及起点输出将是块的模板。

以下各节将介绍如何块被实例化,这个布局文件是如何产生的,并且完成了输出过程。

Magento块实例化

在布局文件中,<block />和<reference />标签有一个“type”属性,这个属性其实是一个 URI

1
2
< block type = "page/html" . .
"page/template_links" .

Magento 就是通过这个URI是用来查找块对应的类名。这个 URI分为两部分,第一部分“page”是用来在全局配置中查找一个基本类名,第二部分“html”或者“template_link”将被添加到基本类名后面生成一个具体的将被实例化的类名。

我们以“page/html”为例。首先 Magento在全局配置中找到节点

找到

1
2
3
< >
< class > Mage_Page_Block < / >
>

这里我们拿到了一个基本类名“Mage_Page_Block”,然后添加“html”到基本类名后面,我们就得到最终的块对象的类名
“Mage_Page_Block_Html”。块的类名在 Magento中被称为(Grouped Class Names),这些类都用相似的方法被实例化。

如果我们创建一个已经存在的且具有相同名称的块的块,新的块实例将取代原来的实例。这时我们的引用(reference)文件从local.xom中。

//example.com/helloworld/index/index?showLayout=package

这可能需要一段时间来加载。如果您的浏览器呈现XML时卡死了,尝试文本格式(txt)

你应该可以看到一个非常大的XML文件。这是包布局。这个XML文件是通过结合所有的XML布局文件的内容形成当前的主题(或包)创建的。如果是默认安装,在以下目录

幕后有<frontend><layout><updates /><adminhtml><layout><updates />全局配置的区域包含所有文件名的节点加载相应区域。一旦在配置中列出的文件被合并,Magento的合并将在最后一个XML文件中,引用(reference)。在这里,你能够自定义添加到您的Magento安装文件。

结合句柄和包布局

所以,如果你看一下包布局,你会看到一些熟悉的标记,如<block /> and <reference />,但他们都被标签包围着,例如

1
2
3
default >
catalogsearch_advanced_index >
etc 这些就是操作标签。对于每个特定的请求来说,针对这个请求的布局文件是由包布局中所有和这个请求相关的操作标签组成的。比如我们上面的例子,和请求相关的操作标签如下

1
2
3
4
5
default / >
STORE_bare_us >
THEME_frontend_default_default >
helloworld_index_index >
customer_logged_out 有一个额外的标签,你需要注意包布局,<update />标签可以让你有另一个句柄的标签。例如

>
>
"magentotutorial/helloworld/simple_page.phtml" >
>
我们来看local.xml,我们已经用不同的块覆盖了“root”标签。把这个放在<default />句柄里,这个句柄是我们已经确保了在系统中每一个页面请求将被覆盖。这可能不是我们想要的。

如果你到你的Magento网站任何其他网页,你会发现他们要么空白,或具有相同的红色背景在你的hello world 页面。让我们改变你的文件local.xml,因此只适用于这个Hello World页面。我们将通过改变默认的,而使用完整的动作名称句柄(helloworld_index_index)做到这一点。

>
>
helloworld_index_goodbye >
update handle "helloworld_index_index" >
>
加载以下页面(清除Magento缓存后)现在应该产生相同的结果。

1
2
//example.com/helloworld/index/index
开始输出和getChildHtml

In a standard configuration,output starts on the Block named root (because it has an output attribute). We’ve overridden root’s Template with our own在标准配置中,输出开始于名为root块(因为它有一个output输出属性)。我们用我们自己的覆盖root模板

"magentotutorial/helloworld/simple_page.phtml"

模板是从当前主题的root文件夹引用的。在这种情况下,这是

所以我们需要深入到我们的自定义页面。大多数Magento模板存储在

templates

结合我们的完整路径

添加内容块

一个简单的红色的页面是很无聊的。让我们添加一些内容到这个网页。改变你的<helloworld_index_index/>在local.xml文件,所以它看起来像下面的