通过清心醉

Magento开发实例:编写自己的视图-布局(Layout)、块(Block)和模板(Template)

上一篇开发实例中作者讲过了Magento的MVC分层中C(控制器)层的规则。Magento的M(模型)和V(视图)层和传统的MVC有很大的改进。

传统的MVC分层是通过执行控制器内的方法,控制器的方法内获取不同的模型数据,然后传递给视图。

Magento却不同了,Magento是从视图中直接引用模型中的数据,这样就导致视图被拆成块(Block)和模板(Template)两部分,块是PHP对象,而模板是原始PHP文件,混合了XHTML和PHP代码(也就是把PHP作为模板语言来使用了)。每一个块都和一个唯一的模板文件绑定。在模板文件phtml中,“$this”就是指该模板文件对应的块对象。

 

比如:app/design/frontend/base/default/template/catalog/product/list.phtml文件中的

<?php $_productCollection=$this->getLoadedProductCollection() ?>

这里“getLoadedProductCollection”方法可以在这个模板的块对象“Mage_Catalog_Block_Product_List”中找到

 

我们看看块(Block)文件

app/code/core/Mage/Catalog/Block/Product/List.php

public function getLoadedProductCollection()

{

return $this->_getProductCollection();

}

块的“_getProductCollection”方法会实例化模型,并读取数据然后返回给模板。

 

块的嵌套::

 

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

我们可以看到这个模板里面很多地调用了“$this->getChildHtml(…)”。每次调用都会引入另外一个块的HTML内容,直到最底层的块。

布局对象::

看到这里,你可能有这样的疑问

Magento怎么知道在一个页面上要用那些块?

Magento怎么知道哪一个块是顶层块?

“$this->getChildHtml(…)”里面的参数是什么意思?块的名字吗?

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

在上一节在执行方法(Action Method)里面直接输出了HTML内容。现在我们要为我们的Mymodule模块创建一个简单的HTML模板。首先我们要创建如下布局文件

app/design/frontend/default/default/layout/local.xml

<?xml version=”1.0″ encoding=”UTF-8″?>

<layout version=”0.1.0″>

<mymodule_index_index>

<reference name=”root”>

<block type=”page/html” name=”root” output=”toHtml” template=”mymodule/home.phtml”/>

</reference>

</mymodule_index_index>

</layout>

 

然后我们在模板内创建个mymodule模块(小写)的目录,新增一个home.phtml文件并且写入

<head>

<title>Untitled</title>

<style type=”text/css”>

body {

background-color:#f00;

}

</style>

</head>

<body>

<h4>Hello Word</h4>

</body>

</html>

最后,我们要在执行控制器里面调用布局文件,开始输出HTML。

app/code/local/Qxz/Mymodule/controllers/IndexContrllers.php

修改function indexAction()的方法:

$this->loadLayout();

$this->renderLayout();

 

清空缓存并刷新。访问127.0.0.1/mymodule,就可以看到纯红色背景的页面。

我们看到执行控制器的indexAction方法里调用了loadLayout和renderLayout

Magento是如何处理的呢?

首先调用“loadLayout”时,Magento会生成这个布局文件。

为每一个block和reference标签实例化一个块对象。

注:在local.xml的layout布局文件中

块对象的类名是通过标签的name属性来查找的。这些块对象被存储在布局对象的_blocks数组中

如果block标签包含了output属性,那么这个块的名字和output属性的值会被添加到布局对象的_output数组中

然后,当你在执行方法中调用“renderLayout”方法时,Magento会遍历_output数组中所有的块名字,从_blocks数组中获得该名字的块,并调用块对象中使用output属性的值作为名字的函数。这个函数往往是“toHtml”。这个output属性也告诉Magento这里就是输出HTML的起点,也就是顶层块。

#更多可以查看app/code/core/Mage/Core/Model/Layout.php文件

那么对象是如何被实例化的,这个布局文件时如何被生成的,最后我们来实践下。

实例化块对象

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

<block type=”page/html” …

<block type=”page/template_links”…

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

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

/global/blocks/page

有以下内容

<page>

<class>

Mage_Page_Block

</class>

</page>

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

block和reference的区别

我们上面提到block和reference都会实例化块对象,那么它们究竟有什么区别呢? reference在布局文件中是用来表示替换一个已经存在的块。

<block type=”page/html” name=”root” output=”toHtml” template=”page/one.phtml”>

</block>

<reference name=”root”>

<block type=”page/someothertype” name=”root” template=”page/two.phtml” />

</reference>

Magento首先创建了一个名叫“root”的块。然后,它有发现了一个引用(reference)的名字也叫“root”,Magento会把原来那个“root”块替换成reference标签里面的那个快。在这里,块“root”被我们用reference替换了,指向了一个不同的模板文件。

 

布局文件是如何生成的

现在我们对布局文件已经有所了解了,但是这个布局文件是那里来的呢?要回答这个问题,我们得引入Magento中的另外两个概念,操作(Handle)和包布局(Package Layout)。

 

我们来试下给Mymodule模块的IndexController.php文件增加个blog的方法

function blogAction()

{

$this->loadLayout();

$this->renderLayout();

}

同样我们调用布局

 

然后修改local.xml文件

红色为新加的,注意书写方法包含在<layout>里,对称包含。

<?xml version=”1.0″ encoding=”UTF-8″?>

<layout version=”0.1.0″>

<mymodule_index_index>

<reference name=”root”>

<block type=”page/html” name=”root” output=”toHtml” template=”mymodule/home.phtml”/>

</reference>

</mymodule_index_index>

<mymodule_index_blog>

<reference name=”root”>

<block type=”page/html” name=”root” output=”toHtml” template=”mymodule/blog.phtml”/>

</reference>

</mymodule_index_blog>

</layout>

这时候我们如果访问

127.0.0.1/mymodule/index/index

127.0.0.1/mymodule/index/blog

会输出不同的视图页面。

 

 

开始输出和getChildHtml方法

在Magento默认的配置下,HTML输出是从名为“root”的块开始(其实是因为这个块拥有output属性

注:任何一个拥有output属性的块都是顶层块,在拥有多个顶层块的情况下Magento将按照块定义的先后顺序输出HTML。

我们覆盖了“root”块的模板template=”mymodule/home.phtml”

模板文件的查找路径是当前主题(theme)的根目录,Magento默认设置是在

app/design/frontend/base/default 目录里的template目录

1.9后的版本为app/design/frontend/rwd/default

 

我们为执行控制器IndexController.php增加一个注册的方法;

function registerAction() #注册方法

{

$this->loadLayout();

$this->renderLayout();

}

既然用到了布局,布局文件肯定也要修改了,修改local.xml,添加个mymodule_index_register块

<mymodule_index_register>

<reference name=”root”>

<block type=”customer/form_register” name=”register” output=”toHtml” template=”customer/form/register.phtml”/>

</reference>

</mymodule_index_register> </mymodule_index_register>然后我们在mymodule模板目录里增加个register.phtml文件哦

写入下面代码:

<?php

echo $this->getChildHtml(‘register’);

#在这里会直接调用block块的name=register的模板

?>

 

这里“getChildHtml”的参数就是要引入的块的名字,使用起来相当方便。

清空Magento缓存并刷新,重新访问127.0.0.1/mymodule/index/register就可以看到:

2-1

“getChildHtml”的参数一定要是当前页面的布局文件中声明过的块。这样的话Magento就可以只实例化需要用到的块,节省了资源,我们也可以根据需要为块设置不同的模板文件。

布局,块和模板构成了Magento MVC架构中的View,这是Magento的特色。

 

针对部分块没有template模板属性的,可能是块的类中定义了默认的模板

比如$this->setTemplate(‘page/template/links.phtml’);

 

总结:

我们看看coloa.xml布局文件的数据:

<?xml version=”1.0″ encoding=”UTF-8″?>

<layout version=”0.1.0″>

<mymodule_index_index>

<reference name=”root”>

<block type=”page/html” name=”root” output=”toHtml” template=”mymodule/home.phtml”/>

</reference>

</mymodule_index_index>

<mymodule_index_blog>

<reference name=”root”>

<block type=”page/html” name=”root” output=”toHtml” template=”mymodule/blog.phtml”/>

</reference>

</mymodule_index_blog>

<mymodule_index_register>

<reference name=”root”>

<block type=”customer/form_register” name=”register” output=”toHtml” template=”customer/form/register.phtml”/>

</reference>

</mymodule_index_register>

</layout>

作者用3种不同的颜色来区分了。至于这里的type=”customer/form_register”,应该是引用客户的注册表单吧。作者也是自学开发,以后更精通了再跟进。

 

关于作者

清心醉 administrator

发表评论

请输入验证码: