Magento 的布局(Layout),块(Block)和模板(Template)

什么是blcok

和之前将的magento mvc架构,我们接下来应该讲模型(model),但是我们跳过模型先来看布局块.和一些流行的php mvc架构不同的是,magento的控制器不直接将数据传输给视图,相反视图将直接引用模型,从模型读取数据.这样的设计就导致了视图被拆分成俩部分,块(Block)和模板(Template).块是php对象,而模板是原始php文件,混合了xhtml和php代码(也就把php作为模板语言来使用了.)每一个块和一个唯一的模板文件绑定在模板文件phtml中,$this就是指该模板文件对于的Block对象

什么是Block,block的基本格式如下

<block
    type="catalog/product_view"
    name="product.info"
    as="product-info"
    template="catalog/product/view.phtml"
    after="-"
/>
block块笔记元素
type是指teplate中将要调用的处理代码位置$this
name是当前给的block定一个名字,一般用在layout定义中进行引用
as可以认为是别名,主要定义在大的架构模板中调用时的名字
template指定当前block的模板文件路径
after指定当前block与同层次block之间的顺序,代表在xxx block之后
before制定当前block与同层次block之间的顺序,代表在xx block之前
outputtoHtml

举例

app/design/frontend/base/default/template/catalog/product/list.phtml

你将看到如下源码

<?php $_productCollection=$this->getLoadedProductCollection() ?>
<?php if(!$_productCollection->count()): ?>
<p class="note-msg"><?php echo $this->__('There are no products matching the selection.') ?></p>
<?php else: ?>

这里getLoadedProductCollection方法可以在这个模板对象Mage_catalog_Block_Product_List中找到

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

public function getLoadedProductCollection()
{
 return $this->_getProductCollection();
}

其中的_getProductCollection方法会实例化模型,并读取数据然后返回模板

嵌套块

magento把视图分离成块和模板的真正强大之处"getChildHtml"方法.这个方法.这个方法可以让你实现功能.顶层的块调用第二层的块,然后是第三层...这就是magento如何输出html的

app/design/frontend/base/default/template/page/1column.phtm
<?php
/**
* Template for Mage_Page_Block_Html
*/
?>
<!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() ?>" lang="<?php echo 
$this->getLang() ?>">
<head>
<?php echo $this->getChildHtml('head') ?>
</head>
<body<?php echo $this->getBodyClass()?' class="'.$this->getBodyClass().'"':'' ?>>
<?php echo $this->getChildHtml('after_body_start') ?>
<div class="wrapper">
 <?php echo $this->getChildHtml('global_notices') ?>
 <div class="page">
 <?php echo $this->getChildHtml('header') ?>
 <div class="main-container col1-layout">
 <div class="main">
 <?php echo $this->getChildHtml('breadcrumbs') ?>
 <div class="col-main">
 <?php echo $this->getChildHtml('global_messages') ?>
 <?php echo $this->getChildHtml('content') ?>
 </div>
 </div>
 </div>
 <?php echo $this->getChildHtml('footer') ?>
 <?php echo $this->getChildHtml('before_body_end') ?>
 </div>
</div>
<?php echo $this->getAbsoluteFooter() ?>
</body>
</html>

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

对象布局

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

1) Magento 怎么知道在一个页面上要用那些块?
2) Magento 怎么知道哪一个块是顶层块?

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

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

在第二章的时候我们在执行方法(Action Method)里面输出了html内容.现在我们要为我们的hello world模块创建一个简单的html模板

首先我们需要创建如下文件

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

包含以下内容

<?xml version="1.0" encoding="UTF-8"?>
<layout version="0.1.0">
    <helloworld_index_index>
        <reference name="root">
            <block type="page/html" name="root" output="tohtml" template="helloworld/simple_page.phtml"></block>
        </reference>
    </helloworld_index_index>
</layout>

再创建如下文件

app/design/frontend/default/teplate/helloworld/simple_page.phtml

包含以下内容

<!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">
<head>
    <title>Untitled</title>
    <style type="text/css">
        body {
            background-color:#f00;
        }
    </style>
</head>
<body>
<h4>Links</h4>
<?php echo $this->getChildHtml('top.links'); ?>
<?php echo $this->getChildHtml('customer_form_register'); ?>
</body>
</html>

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

<!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">
<head>
 <title>Untitled</title>
 <style type="text/css">
 body {
 background-color:#f00;
 }
 </style>
</head>
<body>
<h4>Links</h4>
<?php echo $this->getChildHtml('top.links'); ?>
<?php echo $this->getChildHtml('customer_form_register'); ?>
</body>
</html>

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

修改执行方法如下

public function indexAction() {
 //remove our previous echo
 //echo 'Hello Index!';
 $this->loadLayout();
 $this->renderLayout();
}

清空magento缓存,访问 URL “http://exmaple.com/helloworld/index/index”。你应该看到一个纯红色背景的页面。

这个页面的源代码应该和我们创建的文件“simple_page.phtml”一模一样

也许你看到这里一头雾水,没关系,我们来慢慢解释.首先你得安装一个layout Viewr模块,这和我们第一章将的config viewer模块很相似,都是查看magento的内部信息.安装完这个模块之后

打开如下url

http://example.com/helloworld/index/index?showLayout=pag

你看到的是你正在请求的页面的布局文件。它是由 block,reference 和 remove 组成的。当你在执行方法中调用

“loadLayout”时,Magento 会做如下处理:

生成这个布局文件

为每一个block和reference标签实例化一个块对象.快对象的类名是通过标签的name属性来茶查找的.这些对象被存储在布局对象的_blocks数组中.

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

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

实例化快对象

在布局文件中,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中被称为分组类名,这些类都用相似的方法被实例化.我们将在以后的章节介绍这个概念

block和reference的区别

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

<block type="page/html" name="root" output="toHtml" template="page/2columns-left.phtml">
<!-- ... sub blocks ... -->
</block>
<!-- ... -->
<reference name="root">
 <block type="page/someothertype" name="root" template="path/to/some/other/template" />
 <!-- ... sub blocks ... -->
</reference>

magento首先创建了一个名叫root的块。然后又发现了一个引用reference的名字也叫root,Magento会把原来那个“root“块替换成reference标签里面的那个块

再来看看我们之前创建的那个local.xml

<layout version="0.1.0">
 <default>
 <reference name="root">
 <block type="page/html" name="root" output="toHtml" template="helloworld/simple_page.phtml" />
 </reference>
 </default>
</layout>

在这里,块root被我妈用reference替换了,指向了一个不同的模板文件

布局文件是如何生成的

操作

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

操作

magento会为每一个页面请求生成几个不同的操作.我们的layoutview模块可以显示这些处理器

http://example.com/helloworld/index/index?showLayout=handles

你应该看到类似如下的列表(和你的配置有关):

Handles For This Request

1. default

2. STORE_default

3. THEME_frontend_default_gap

4. helloworld_index_index

5. customer_logged_out

它们每一个都是一个操作的名字。我们可以在 Magento 系统的不同的地方配置操作。在这里我们需要关注两个操作

“default” 和 “helloworld_index_index”。“default”处理器是 Magento 的默认处理器,参与每一个请求的处理。

“helloworld_index_index”处理器的名字是 frontname “helloworld”加上控制器的名字“index”再加上执行方法的名字

“index”。这说明控制器的每一个执行方法都有一个相应的操作。

我们说过 “ index ” 是 Magento 默认的 控制器 和执行方法的名字,所以以下请求的操作名字也是

“helloworld_index_index”。

http://example.com/helloworld/?showLayout=handles

包布局

Last modification:April 20, 2022
如果觉得我的文章对你有用,请随意赞赏