首页 | PHP资讯 | 技术专栏 | 资源共享 | PHP培训 | PHP职场 | 图书 | PHP ON WIN | PHP圈子 | PHPer学习大本营
返回列表 回复 发帖

[组件][原创]Zend_View_Helper的使用

[组件][原创]Zend_View_Helper的使用

本帖最后由 七月十五 于 2009-5-16 15:11 编辑

Zend_View_Helper 是一个很不错的东西,
它可以让你将视图中一些零散的代码模块化,优点是:易于使用、便于维护
好像 有一个教程介绍过这个东西 ;看下面之前,可以先看看这个http://www.phpeye.com/article/view/id/47

Ps: 10.12 修改menu实例。menu数据保存在menu.xml内。

1、一个最简单的例子
一般情况下,在<head></head>中我们要载入一堆css文件或者js文件

<link rel='stylesheet' type='text/css' media='screen' href='/auction/public/styles/cssform.css' />
<link rel='stylesheet' type='text/css' media='screen' href='/auction/public/styles/admin/basic.css' />
<link rel='stylesheet' type='text/css' media='screen' href='/auction/public/styles/admin/table.css' />
<link rel='stylesheet' type='text/css' media='screen' href='/auction/public/styles/admin/topbar.css' />
<link rel='stylesheet' type='text/css' media='screen' href='/auction/public/styles/admin/leftcolumn.css' />
<link rel='stylesheet' type='text/css' media='screen' href='/auction/public/styles/admin/rightcolumn.css' />
<link rel='stylesheet' type='text/css' media='screen' href='/auction/public/styles/admin/middle.css' />
<link rel='stylesheet' type='text/css' media='screen' href='/auction/public/styles/admin/footer.css' />
<script language='javascript' src='/auction/public/scripts/jquery-1.2.1.pack.js'></script>
<script language='javascript' src='/auction/public/scripts/loading.js'></script>
<script language='javascript' src='/auction/public/scripts/jquery/jquery.ajax.js'></script>

在上面的例子里,我载入7个css(当然因为分成不同文件,每个css的确不大),有控制form 也有控制table 当然更多是layout的控制。
载入3个js文件。包括jquery基本文件以及基本的loading.js(控制动态载入css和js的文件)和一个ajax扩展


这样的代码 问题是肯定没有的;但是有一天,我们要修改其中一点怎么办?比如,我们的href目录不在/auction/public/下,而全部转移到/xxx/xxx/下。我们必须找到这个html文件,一条条修改。我举的例子很简单,的确一条条修改起来也不是很麻烦;但是实际上,zf给我们提供一个很好玩的方法。

以上的代码可以这么写:
首先在一个controller文件内定义要载入的文件(因为这是一个基本载入,一般情况下会在init()初始化定义)

<?php
     $this->view->loadCssArray =array('cssform','admin/basic','admin/table','admin/topbar','admin/leftcolumn','admin/rightcolumn','admin/middle','admin/footer');
     $this->view->loadJsArray = array('jquery-1.2.1.pack','loading','jquery/jquery.ajax');     
     $this->view->basePublicUrl = '/xx/xx';
?>   

然后在header.phtml文件内

//header.phtml文件内
<?php
        echo $this->loadCss($this->loadCssArray,$this->basePublicUrl);      
        echo $this->loadJs($this->loadJsArray,$this->basePublicUrl);               
?>   

如果做debug测试,发现$this 其实就是系统里的Zend_View实例。那么loadCss loadJs这个方法怎么来的呢?
其实添加方法,不是使用继承Zend_View,而是使用Zend_View_Helper

//LoadCss.php 文件
class Zend_View_Helper_LoadCss {
    public function loadCss($_loadCssArray,$baseUrl,$type = ''){
        $html = '';
        if(empty($type)){
            $type = 'screen';
        }
        foreach ($_loadCssArray as $_cssFile){
            $str ="<link rel='stylesheet' type='text/css' media='".$type."' href='".$baseUrl.".$_cssFile.".css' />";
            $html.= $str;
        }
        return $html;
    }
}


//LoadJs.php 文件
class Zend_View_Helper_LoadJs {
    public function loadJs($_loadJsArray,$baseUrl){
        $html = '';
        foreach ($_loadJsArray as $_jsFile){
            $str ="<script language='javascript' src='".$baseUrl.".$_jsFile.".js'></script>";
            $html.= $str;
        }
        return $html;
    }
}

这两个文件,放的位置,是要看你的Zend_View基本路径的设定的;一般情况下,view文件下下存在三个文件夹,scripts就是我们一般的视图文件目录,而helper文件夹就是存放这些视图帮手的地方。

这样,如果要修改载入那些文件,就只需要修改controller.php内的设定即可。

以上只是一个简单的例子。因此也许有人觉得直接写在header.phtml内更直观,更简单。也许是的;但是对于更复杂的html结构,有时候这种模块化,还是很有效的。

2、一个Menu的例子
我再举一个menu菜单的例子。这个例子的实例可以参考 http://160.26.139.83/admin  用户名:yyy  密码:yyy

一个简单的菜单,一般情况有一个总标题,然后下面几个子菜单。
因为项目都是ajax实现,这个菜单要自动生成ajax连接,并且保证在ajax之前,必要的js文件和css文件载入成功。(动态载入js必须在页面也就是ajax提交前,文件载入成功,否则js不生效)

先介绍Controller下的Action
[php]
//10.15 修改该函数;菜单数据保存在 menu.xml内
public function menuAction(){      
       $type = 'admin';
       $xmlfile = CONFIG_DIR.DIRECTORY_SEPARATOR.'menu.xml';
       //这是一个读取xml文件类;如果cache已经保存该文件,从cache内读取
       $xmlObject = Htmlhelper_Xml::getLangXml('menu',$xmlfile);
        //实例为 管理界面的菜单,所以取管理端菜单数据
        $_menuArray = $xmlObject->$type->toArray();
       //获得菜单的css class设置数据
        $_classArray = $xmlObject->class->toArray();
       //获得菜单的ajax设定的基本数据
        $_ajaxArray = $xmlObject->ajax->toArray();   
        $_ajaxArray['baseurl'] = $this->_baseUrl;
        $this->view->menuArray = $_menuArray;
        $this->view->classArray = $_classArray;
        $this->view->ajaxArray = $_ajaxArray;
        $this->render();     
    }
[/php]

menu.xml 我就贴一部分。

<?xml version="1.0" encoding="utf8"?>
<configdata>
    //定义管理端菜单内容
    <admin>
        //标题为 usermenu -〉这个数值将会根据当前语言设定进行转化,比如中文的情况,显示‘用户操作’
        <usermenu>
          //usermenu下面的菜单
          <userlist>
             <href>#</href>
             <onclick>admin/user/index/ajaxid/mainbody/orderby/orders</onclick>
          </userlist>            
        </usermenu>
        <ordermenu>         
          <orderregister>
             <href>#</href>
             <onclick>admin/order/register/ajaxid/mainbody</onclick>
             //这个连接之前要载入的css和js文件
             <css>jquery/jquery.calendar</css>
             <js>jquery/jquery.calendar.pack</js>
          </orderregister>         
        </ordermenu>
    </admin>
    //用户端菜单示例
    <user>
        <usermenu>
          <useredit>
             <href>#</href>
             <onclick>user/edit/ajaxid/mainbody</onclick>
          </useredit>
        </usermenu>
    </user>
    //这个部分是菜单的css class设定
    <class>
        <title>titlebar</title>
        <title_style>MARGIN-TOP: 0px</title_style>   
        <ul>ddmarkermenu</ul>     
        <li></li>     
    </class>
    //ajax设定
    <ajax>
        <id>mainbody</id>
        <function>ajaxRequest</function>           
    </ajax>
</configdata>


然后是Zend_View_Helper_Menu;有了这个类,我们将在视图文件内直接使用$this->menu($array)即可生成菜单。
Ps: 10.15 该类进行修改,将原来代码分解。
[php]
class Zend_View_Helper_Menu {
    /**
         * 通过数组产生菜单
         * @param array $_basicLangMenuArray  语言包数据 比如将'usermenu' 显示为 '用户操作'
         * @param array $_menuArray 菜单数据  
         * @param array $_classArray css数据
         * @param array $_ajaxArray ajax数据
         * @throws Exception
         * @return string
        */
    public function menu($_basicLangMenuArray,$_menuArray,$_classArray,$_ajaxArray){
        $_titleClass = isset($_classArray['title'])?$_classArray['title']:'titlebar';
        $_titleStyle = isset($_classArray['title_style'])?$_classArray['title_style']:'MARGIN-TOP: 0px';
        $_ulClass = isset($_classArray['ul'])?$_classArray['ul']:'ddmarkermenu';
        $_liClass = isset($_classArray['li'])?$_classArray['li']:'';
        $html ='';
        if(!isset($_ajaxArray['id'])){
            $_ajaxArray['id'] = 'mainbody';
        }
        if(!isset($_ajaxArray['function'])){
            $_ajaxArray['function'] = 'ajaxRequest';
        }
        //产生标题前的img html代码
        $_menuImg = $this->getMenuImg($_ajaxArray);
        foreach ($_menuArray as $_menuName=>$_menuValue){
           //产生标题部分的代码,其中一个参数就前面产生的标题图标$_menuImg
            $html .= $this->getMenuTitle($_basicLangMenuArray,$_menuName,$_menuImg,$_titleClass,$_titleStyle);
            if(empty($_menuValue)){
                continue;
            }
            $liHtml ='';
            //生成 <ul>之后的<li>部分的html代码
            if(is_string($_menuValue)){               
                $liHtml .= $this->getMenuLiString($_basicLangMenuArray,$_menuValue,$_liClass);
            }elseif(is_array($_menuValue)){
                $liHtml .= $this->getMenuLiArray($_basicLangMenuArray,$_menuValue,$_liClass,$_ajaxArray);
            }
            //将刚才生成 的<li>全部放进<ul>内
            $html .= $this->getMenuUi($liHtml,$_ulClass);
        }
        return $html;
    }
}
[/php]
有了这个View_helper类,视图文件就变得很简单了。看看只有一行代码(js的不算)

    <?php  echo $this->menu($this->basicLangXml->menu->toArray(),$this->menuArray,$this->classArray,$this->ajaxArray);?>   
    <script type="text/javascript">        
    $(document).ready(function() {   
        $('#leftcolumn').myInitMenu();        
    });
    </script>   

注意,这里没有生成任何javascript的东西。而是将$_menuList数据都以属性的方式存在html内

<div class="titlebar" style="margin-top: 0px;" index="usermenu"><img border="0" src="/auction/public/images/arrow/down_sort_arrow.png"/>用户操作</div>
<ul class="ddmarkermenu" style="display: none;">    <li class="
"><a alt="userlist" ajaxid="mainbody" ajaxurl="admin/user/index/ajaxid/mainbody/orderby/orders" ajax="1" href="#">用户列表</a></li>
<li class="
"><a alt="userregister" ajaxid="mainbody" ajaxurl="admin/user/register/ajaxid/mainbody" ajax="1" href="#">用户注册</a></li>
<br/>
</ul>

如果你使用firebug查看html代码,发现这里没有一句javascript;这个连接的onclick方法,还有标题点击颜色变化,都是在 $('#leftcolumn').myInitMenu(); 中定义的。
这是一个基本原则,html和js要尽量分开。
而myInitMenu()方法,是本人的一个jquery的简单插件。
[php]
//jquery.mymenu.js
(function($) {
    $.fn.myInitMenu = function(options) {
        return this.each(function() {
            options = $.extend({
                default_menu: 'usermenu',
                default_ul: 'userlist',
                div: $(this).attr('id'),
                title:  ".titlebar",
                link: "ul li a",
                link_ajaxAttr: "ajax",
                color: "#99CC33",
                down_img:_baseUrl+'/public/images/arrow/down_sort_arrow.png',
                right_img:_baseUrl+'/public/images/arrow/right_sort_arrow.png',
                img: _baseUrl+'/public/images/dynamicdrive/topgradient.jpg'
            }, options || {});
            $(this).find(options.title+"[@index!='"+options.default_menu+"']").next().hide().end().find("img").attr('src',options.down_img);
            $(this).find(options.title+"[@index='"+options.default_menu+"']").css('background','url('+options.img+') repeat-x center center').find("img").attr('src',options.right_img);
            $(this).find(options.link+"[@alt='"+options.default_ul+"']").css('color','red').css('background-color',options.color);            
            //titlebar操作
            $(this).find(options.title).click(function(){
                $('#'+options.div+' '+options.title).css('background','').next().hide().end().find("img").attr('src',options.down_img);
                $(this).css('background','url('+options.img+')  repeat-x center center').find("img").attr('src',options.right_img).end().next().slideToggle();
            });
            //如果不存在ajaxid 产生普通link;否则产生 ajax link
            $(this).find(options.link).click(function(){
                $('#'+options.div+' '+options.link).removeAttr('style');
                $(this).css('color','red').css('background-color',options.color).find("img[@alt='"+$(this).attr('alt')+"']").show();
                ajax = $(this).attr(options.link_ajaxAttr);
                if(ajax == '1'){
                    $(this).ajaxMyMenuLink();
                    return false;
                }
            });
        });
    };
    $.fn.ajaxMyMenuLink = function(options) {
        return this.each(function() {
            options = $.extend({
                cssAttr: 'cssfile',
                jsAttr:  'jsfile',
                ajaxAttr:  'ajaxid',
                ajaxUrl:  'ajaxurl',
                cssLoad: 'cssmenu',
                jsLoad : 'jsmenu'
            }, options || {});
            _cssfile = $(this).attr(options.cssAttr);
            _jsfile = $(this).attr(options.jsAttr);
            if(_cssfile == '' || typeof _cssfile != 'string'){
                _loadcss = 1;
            }else{
                _loadcss = loadCss(_cssfile,options.cssLoad);
            }
            if(_jsfile == '' || typeof _jsfile != 'string'){
                _loadjs = 1;
            }else{
                _loadjs = loadJs(_jsfile,options.jsLoad);
            }
            if(_loadjs == 1 && _loadcss == 1){
                ajaxRequest($(this).attr(options.ajaxAttr),$(this).attr(options.ajaxUrl),'','GET');
            }
        });
    }
})(jQuery);
[/php]
熟悉jquery的朋友,应该看起来没什么大问题。

基本上菜单完成了。

比如菜单再添加一项或者改变标题的css类,就在menu.xml去添加,代码部分甚至都可以不管了。
而如果要修改连接的细节,点击之后颜色的改变等,去修改jquery.mymenu.js 就可以了。

而且最重要的是,有了Zend_View_Helper_Menu和jquery.mymenu.js模块化之后 ,可以随地随时生成menu。
比如http://160.26.139.83/admin里你看到的是管理者菜单;http://160.26.139.83定义的就是普通用户的菜单。

到此,再重提上面说的Zend_View_Helper的好处:
1、易于使用
    写好的类,随时可以使用;相反死的html代码,只能从一个文件copy到另外一个文件

2、便于维护
    做好参数,很多值就只是参数传递的问题了。比如http://160.26.139.83/admin 中的菜单,很多js是动态载入的;尤其是Study Example的部分,可能一个子菜单就需要N多js支持。这些定义、修改,让我在30K的html页面里找出来,真的很麻烦。(http://160.26.139.83/admin 的菜单部分,如果真是原始的html实现,代码量肯定超过30K)
   
3、养眼,看起来更面向对象。
    赫赫,这个不是理由;但是在视图里看到<?php  echo $this->menu($this->menuArray,.....);?> ,肯定比看到一堆html舒服的多。

4、 结合jquery,是我的建议。
    最近使用jquery,很爽。几乎完全实现js和html的分离;重要的是利用jquery做到这种分离很简单。结合jquery和Zend_View_Helper 可以大大减少zend_view的代码量,而且模块化,可重用。
    在http://160.26.139.83/admin 里Study Example里有很多jquery的实例,也是我学习过程的一些测试。

Ps:
http://160.26.139.83/admin 的一些说明
1、请不要在系统设定里,随意修改(不过,我现在也只开放了语言和log等级两项修改);修改成英文或者日语测试完,最好马上恢复到中文。
2、语言包设定里的内容最好不要修改。这里是所有视图显示的东西。
3、用户列表里的test用户,最好不要修改密码或者禁用。很多人在用户端,要用这个id登录的。

[ 本帖最后由 qqinxl 于 2007-10-12 13:59 编辑 ]

怪不得你先前提到 ViewHelper,原来发帖到这里了,呵呵。

我也建议你看看这个帖子:http://www.phpchina.com/bbs/thread-38334-1-1.html

TOP

千万别跟下一下口水仗;
我只是一个框架的使用者,一年前我还不认识ZendFramework。
我可犯不着为ZendFramework说好话,得罪一堆Phper。

有什么好的使用思路,多多跟贴。

我之前还发过两篇Zend_Controller_Action的使用帖子,可惜现在这种原创帖子基本一天就沉了。

[ 本帖最后由 qqinxl 于 2007-10-9 20:05 编辑 ]

TOP

哪有这么严重。只要能够理性的讨论问题就很好。

[ 本帖最后由 fleaphp 于 2007-10-9 20:15 编辑 ]

TOP

请都一个初手问题. 比如说新建了一个Helper, 那个Helper是要在每个页面里的Controller里声明后才能在View调用,还是可以直接在View里调用..? 谢谢.

TOP

直接使用。

当然前提是你建立的helper 符合命名规则。

http://www.phpeye.com/article/view/id/47

http://framework.zend.com/manual/zh/zend.view.helpers.html
编写自定义的Helper类很容易,只要遵循以下几个原则即可:

类名必须是 Zend_View_Helper_*,*是helper的名称。例如,你在写一个名为“specialPurpose”的类,类名将至少是"SpecialPurpose",另外你还应该给类名加上前缀,建议将“View_Helper”作为前缀的一部份:“My_View_Helper_SpecialPurpose”。(注意大小写)你将需要将前缀(不包含下划线)传递给addHelperPath() 或 setHelperPath()。

类中必须有一个public的方法,该方法名与helper类名相同。这个方法将在你的模板调用"$this->specialPurpose()"时执行。在我们的“specialPurpose”例子中,相应的方法声明可以是“public function specialPurpose()”。

一般来说,Helper类不应该echo或print或有其它形式的输出。它只需要返回值就可以了。返回的数据应当被转义。

类文件的命名应该是helper方法的名称,比如在"specialPurpose"例子中,文件要存为“SpecialPurpose.php”。

把helper类的文件放在你的helper路径下, Zend_View就会自动加载,实例化,持久化,并执行。

TOP

很不错,学习来了。顺便问下楼主几年php经验?

TOP

回复 #1 qqinxl 的帖子

很不错,但是单纯从MVC的角度来说,view这一层破坏掉了,然后,美工可能会很头疼,要在页面上修改一下东西估计还是要程序员来做的,呵呵个人观点,还是页面与代码分开, 业务逻辑与页面分发 action,controller,页面显示Smarty,html,业务逻辑问题找Contoller--action,页面问题找html.
记得以前公司有一个纯jsp写的程序,看完了代码眼镜也换了.:lol

TOP

这只是 一个Zend_View_Helper使用类的说明;
我也只是为了证明Zend_View_Helper的一些使用方法。

ls提到的问题的确是一个问题;
所以 View_Helper的使用不能过度,所有的view都封装起来,也没有这个必要;
我们只把试图部分中可能要常用的组件包装起来。

因此,也许我举的第二个例子menu,可能就有些过分;
在menu.phtml的文件里,只有寥寥几句代码。

Ps:php开发经验只有1年

Ps:10.15 我将部分代码修改。
主要的修改是 原来的菜单数据保存在一个menu.xml内,而不是action内定义数组。

[ 本帖最后由 qqinxl 于 2007-10-12 14:01 编辑 ]

TOP

谢谢好文
可惜演示的地址用户名和密码用什么呢?

TOP

返回列表