Magento 开发笔记3

6 篇文章 0 订阅


原文参见http://alanstorm.com/layouts_blocks_and_templates

这篇文章还需要进一步整理~

Layouts, Blocks 和Templates (View部分)

我们在这个部分关注一下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="simple_page.phtml" />        

</reference>    

</default>

</layout>   

然后再创建一个文件

app/design/frontend/base/default/template/simple_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源码和simple_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”

URI会在全局配置文件指明一个地址。URI的第一个部分用来去查找全局配置文件,找到Page类名。第二部分跟在第一个部分后面成为新的类, 然后再实例化该类。

以page/html作为例子。首先Magento会在全局配置文件里查找下面的

/global/blocks/page

然后找到

<page>

            <class>

                        Mage_Page_Block

            </class>

</page>

这样我们就得到了MagePageBlock类。然后,URI的第二部分会加在它后面成为MagePageBlock_Html。这个类随后就会呗实例化。

Blocks也是Magento里的组类,所有的共享类似的实例化方法。后面会有该部分的详细介绍。

<block />和<reference />之间的不同

我们谈到了<blocks/>和<references />都可以实例化Block,那他们有什么不同呢。

先有

<blocktype="page/html" name="root" output="toHtml"template="page/2columns-left.phtml">     <!-- ... sub blocks ... --></block>

 

然后有

<layoutversion="0.1.0">   

 <default>        

<reference name="root">            

<block type="page/html"name="root" output="toHtml"template="simple_page.phtml" />        

</reference>    

</default>

</layout>   

<reference />里面的blocks不会替代blocks。相反,他们是增加,或者修改现有的blocks。上面的样例中,是插入了一个新的叫root的block到现有的rootblock中。这在Magento Layout中是未定义的。最终结果是老的被替换掉了,但是靠此来保证一致性是很糟的主意。

Layout 文件如何生成

到现在我们对Layout XML应该有比较清晰的认识了。但是Layout XML从何而来?要解答这个问题,我们需要引入两个新的概念,Handles和Package Layout。

Handles

Magento中的每个请求会生成几个不同的Handles。Layoutview 模块就可以给我们用URL展示这些

http://localhost/magento/helloworld/index/index?showLayout=handles

我们会看到类似

1.    默认

2.    STORE_bare_us

3.    THEME_frontend_default_default

4.    Helloworld_index_index

5.    Customer_logged_out

这些每个都是一个Handle。Handle在Magento的很多地方会被设置。我们需要关注其中两个地方:default和helloworld_index_index.。默认的Handle是每个请求都会出现的。而Helloworld_index_indexHandle是通过合并frontName(helloworld),Actioncontroller (index), 和Action Controller Action Method(index)而成。这意味这每个ActionController方法都可能对应一个Handle。

记住“index”是Magento对每个Action Controller和ActionMethods的默认,因此下面的请求

http://localhost/magento/helloworld/?showLayout=handles

同样会产生Handle的名字交helloworld_index_index

Package Layout

你可以认为PackageLayout等同于全局配置。他是一个大的XML文件,包含了Magento内每个可能的Layout配置。让我们看一下

http://localhost/magento/helloworld/index/index?showLayout=package

这个可能会加载一会。如果浏览器在xml下卡了,请换成text模式

http://localhost/magento/helloworld/index/index?showLayout=package&showLayoutFormat=text

你可以看到很大的XML文件。这就是Package Layout。它是综合了所有当前主题下XMLLayout的文件。默认的安装是

app/design/frontend/base/default/layout/

在全局文件里面有个<updates />部分,节点中包含了所有要加载的名字。一旦配置文件中给出的文件合并了,Magento会合并到上一个xml文件,local.xml。这个可增加你想要的功能。

合并Hanldes和Packge Layout

 如果你看到Package Layout, 你可以看到一些熟悉的标签,例如<block />和<reference/>, 但是他们都类似这样的标签覆盖

<default />

<catelogsearch_advanced_index/>

etc…

这些都是Handle标签。一个请求的Layout是由所有匹配请求的Handles的Package Layout生成。因此,在上面的例子中,我们的layout是在下面的部分中生成

<default />

<STORE_bare_us />

<THEME_frontend_default_default/>

<helloworld_index_index/>

<customer_logged_out/>

还有一个标签需要我们注意。<update />容许我们包含其他的Handle。例如

<customer_account_index>    

<!-- ... -->    

<update handle="customer_account"/>    

<!-- ... -->

</customer_account_index>

这意味这请求到customeraccountindex时,应该包含<customer_account>下面的<reference/>和<block />.

学以致用       

看够了理论,我们来回顾一下之前的工作。

<layoutversion="0.1.0">    

<default>        

<referencename="root">            

<blocktype="page/html" name="root" output="toHtml"template="simple_page.phtml" />        

</reference>    

</default>

</layout>

这个意味着我们重写了root标签。而<default/>部分保证了每次请求都会发生。这可能并不是我们想要的效果。

如果访问任意其他页面,我们同样是空白页面,或者是红色背景(之前helloworl页面的那样)。所以我们改进一下local.xml,确保它只用于helloworld页面。修改如下

<layout version="0.1.0">    

<helloworld_index_index>        

<referencename="root">            

<blocktype="page/html" name="root" output="toHtml"template="simple_page.phtml" />        

</reference>    

</helloworld_index_index>

</layout>

清除cache,这个时候你的其他页面应该恢复了。

然后应用到googbye Aciton Method

public function goodbyeAction() {     $this->loadLayout();     $this->renderLayout();           }     

这个时候加载http://localhost/magento/helloworld/index/goodbye

会发现还是blank页面。这个时候我们需要在local.xml增加一个actionname, 内容如下

<layout version="0.1.0">    

<!-- ... -->    

<helloworld_index_goodbye>        

<updatehandle="helloworld_index_index" />    

</helloworld_index_goodbye>

</layout>

清楚cache,这个时候,下面两个页面会有同样的效果了。

http://localhost/magento/helloworld/index/index

http://localhost/magento/helloworld/index/goodbye

开始输出并getChildHtml

在标准的配置中,输出的开始是root命名的Block(这个是输出的特性)。我们已经重写了root的模版 template=”simple_page.phtml”

模版会从当前或者base主题的主目录里得到,如

app/design/frontend/base/default/template

通常你可以添加模版到你自己的主题或者默认主题

app/design/frontend/default/default/template

app/design/frontend/default/custom/template

base目录是最后才会去查找的目录,如果magento在其他主题下找不到,才会回到base目录。可是,象之前提到的哪有,你不想加入到这样的目录,因为magento的更新会覆盖他们。

增加内容block

红色的悲剧很无聊。所以我们在页面上增加点内容。改变local.xml里的<helloworldindexindex />,如下

<helloworld_index_index>    

<reference name="root">        

<block type="page/html"name="root" template="simple_page.phtml">            

<blocktype="customer/form_register" name="customer_form_register"template="customer/form/register.phtml"/>        

</block>    

</reference>

</helloworld_index_index>

我在root里增加两个内嵌的Block。Magento会分配它,并且展示一个客户注册的页面。在root里内嵌这个Block,我们要在simple_page.html里面显式的调用。所以我们用Block的getChildHtml方法,如下

<body>

            <?php echo $this->getChildHtml(‘customr_form_register’); ?>

</body>

清除Cache,重新加载页面。这个时候我们看到了注册页面在红色的背景上。下面还有一个Block叫top.links。添加如下

<body>

            <h1>Links</ht>

            <?php echo $this->getChildHtml(‘top.links’); ?>

</body>

当我们重新加载页面,就看到Links被渲染了,但是top.links没有任何渲染。这是因为我们没有在local.xml里添加它。在Layout里,getChildHtml只能包含显示的作为子block的Blocks。这容许Magento实例化它想要的blocks,同时让我们可以根据显示内容为Block设置不同的模版

我们可以在local.xml里为top.links增加Block

<helloworld_index_index>    

<reference name="root">        

<block type="page/html" name="root"template="simple_page.phtml">

<blocktype="page/template_links" name="top.links"/>            

<block type="customer/form_register"name="customer_form_register"template="customer/form/register.phtml"/>        

</block>    

</reference>

</helloworld_index_index>

此时再清除cache,就可以看到top.links模块的效果了

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值