PHP头条
热点:

Magento 开发笔记3


我们在这个部分关注一下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模块的效果了
 
 
 
 

www.phpzy.comtrue/phprm/13167.htmlTechArticleMagento 开发笔记3 我们在这个部分关注一下View里Layouts和Blocks。 跟其他主流PHPMVC架构不一样,magento 的ActionController不会把数据对象传给view,也不会设置View对象里的属性。View是通过系统模...

相关文章

    暂无相关文章
相关频道:

PHP之友评论

今天推荐