网站推广-网站优化-合肥久飞SEO论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 7582|回复: 0

改进Smarty以实现类似dede的标签风格

[复制链接]
笑一笑 该用户已被删除
发表于 2010-1-17 23:00:28 | 显示全部楼层 |阅读模式
DedeCms深受用户欢迎,很大的原因是因为模板标签调用的灵活性和系统的强大可伸缩性,如果用传统的Smarty开发,是不可能达到那种效果的,当然我们可以对其进行一下改进,从而实现这样的功能。

一、设计目标:实现类似
{dede:arclist row='10'}
    [field name=f1/] -- [field name=f2/]<br />
{/dede:arclist}
这样的风格的标签(注意:dede的标签是触发式的,因此我们不能简单的修改Smarty去实现,而是也要实现触发机制)

二、Smarty 的插件主要有下面几种:

1、block 块插件
用块插件参实现类似dede标签的效果,但在中间部份不能使用变量(那部份会被预先编译),只能使用简单的替换,因此块插件是并不适合我们要使用的方法,但是我们正是需要用与它类似的方法进行改进的。

2、compiler 插件
这种插件对属性里的变量不会预先编译,属于比较接近底层的一种插件,但它默认的情况是不能直接使用{tag}{/tag}这样的标签的,否则{/tag}这里会报错。

3、function 自由定义函数的插件
用{function att1=a att2=b ...}形式调用

4、modifier 输出内容修正插件
实际上这种插件和function是类似的,只是写法不同,它的写法即是
{$var|function}
其实和
{function att=$var}
是类似的,只是写法上更简单

三、使用Smarty要实现的风格

{mytag item='fields'}
    {$fields.f1} -- {$fields.f2} <br />
{/mytag}

要实现上面标签,关键是两点:
1、把 mytag 输出的数组输化为 foreach ($arr as $fields) {
2、把 {/mytag} 替换为 ' } '
{$fields.f1} -- {$fields.f2} 这部份任由默认的smarty编译,它实际上得到的源码应该是
<?php echo $this->_tpl_vars['fields']['f1']; ?> -- <?php echo $this->_tpl_vars['fields']['f2']; ?>
这里是不需要我们去理会的,因此关键还是在1、2两点。

由于这种标签是肯定和block相冲突的,所以这里用前缀对自定义标签分开,这里就用dd吧,不过不能用 dd: 而是用 dd_。

即是:
{dd_mytag item='fields'}
    {$fields.f1} -- {$fields.f2} <br />
{/dd_mytag}

首先我们打开 Smarty_Compiler.class.php
找到:function _compile_tag
关键部份是在
default:
    if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) {
        return $output;
    } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) {
        return $output;
    } else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) {
        return $output;                    
    } else {
        $this->_syntax_error("unrecognized tag '$tag_command'", E_USER_ERROR, __FILE__, __LINE__);
    }
这里首先对 dd_ 前缀的标签进行拦截
default:
    $first = substr($tag_command, 0, 4);
    if( preg_match('/^(dd|\/dd)_/', $first) && $this->_compile_myblock_tag($tag_command, $tag_args, $output) ) {
        return $output;
    } else if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) {
        return $output;
    } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) {
        return $output;
    } else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) {
        return $output;                    
    } else {
        $this->_syntax_error("unrecognized tag '$tag_command'", E_USER_ERROR, __FILE__, __LINE__);
    }

然后  $this->_compile_myblock_tag($tag_command, $tag_args, $output) 就是我们要实现的关键代码了

_compile_myblock_tag函数具体如下:

/**
     * 类似dede风格的块标签(块名称需要用 dd_ 开头)
     *
     * sets $output to the compiled custom compiler tag
     * @param string $tag_command
     * @param string $tag_args
     * @param string $output
     * @return boolean
     */
    function _compile_myblock_tag($tag_command, $tag_args, &$output)
    {
        
        if( substr($tag_command, 0, 1) == '/' )
        {
            $output = '<?php  }  ?>';
            return true;
        }
        
        $found = false;
        $have_function = true;

        if (isset($this->_plugins['myblock'][$tag_command]))
        {
            $found = true;
            $plugin_func = $this->_plugins['myblock'][$tag_command][0];
            if (!is_callable($plugin_func)) {
                $message = "compiler function '$tag_command' is not implemented";
                $have_function = false;
            }
        }
        else if ($plugin_file = $this->_get_plugin_filepath('myblock', $tag_command))
        {
            $found = true;
            include_once $plugin_file;
            $plugin_func = 'smarty_myblock_' . $tag_command;
            if (!is_callable($plugin_func)) {
                $message = "plugin function $plugin_func() not found in $plugin_file\n";
                $have_function = false;
            } else {
                $this->_plugins['myblock'][$tag_command] = array($plugin_func, null, null, null, true);
            }
        }

        if ($found)
        {
            if ($have_function)
            {
                $this->_add_plugin('myblock', $tag_command);
                $attrs = $this->_parse_attrs($tag_args);
                $_cache_attrs = '';
                $arg_list = $this->_compile_arg_list('myblock', $tag_command, $attrs, $_cache_attrs);
                $output  = '<?php '." \${$tag_command} = smarty_myblock_{$tag_command}(array(".implode(',', $arg_list)."), \$this);\n";
                $fieldname = empty($attrs['item']) ? 'field' : $attrs['item'];
                $fieldname = preg_replace('/["\']/', '', $fieldname);
                $output .= "foreach( \${$tag_command} as \$this->_tpl_vars['key']=>\$this->_tpl_vars['".$fieldname."'] )\n{\n";
                $output .= '?>';
            } else {
                $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
            }
            return true;
        } else {
            return false;
        }
    }

四、新建一个插件进行测试

我们写插件的时候是用 myblock.dd_mytag.php 这样的名称的来命名,里面的函数命名为 smarty_myblock_dd_mytag

例如:
function smarty_myblock_dd_test($_params, &$compiler)
{
    $f1 = empty($_params['att2']) ? '' : $_params['att2'];
    $f2 = empty($_params['att1']) ? '' : $_params['att1'];
   
    ${$_params['item']}[0]['f1'] = $f1;
    ${$_params['item']}[0]['f2'] = $f1;
   
    ${$_params['item']}[1]['f1'] = 'aaa';
    ${$_params['item']}[1]['f2'] = 'bbb';
   
    return ${$_params['item']};
}

这个函数返回的必须是一个二维数组,当然多更多维也是可以的,前提是你在里面懂得调用它。
把上面文件保存为:plugins/myblock.dd_test.php

OK
在模板写个标签测试一下:
{dd_test item="field" att1='111' att2='222' }
    {$field.f1} -- {$field.f2}<br />
{/dd_test}

看到结果:
222--222
aaa--bbb

了吧,呵呵,这正是我们想要的效果。

当然,要在你的项目中实用任意标签调用,就直接写这种形式的插件即可,dedecms的模板引擎是和文档类有关连的,因此它可以在插件里直接调用文档类的一些环境变量,在我们的工程中,如果类写得比较合理的,可以给Smarty增加一个属性,如:var $doc; 把它和文档类关连起来,这样也能从插件里通过 $compiler->doc 来获取文档的相关特性了(如栏目id、文档id等),如果你的类不是那么规范,办法还是用的,可以用静态类来做一个工厂的方法,然后插件里用autoload的方式获得这个类也是可以的,不过你也可以直接用global从外部获取一些参数,但从MVC角度考虑,这样是不科学的,也不得于安全。

本文地址: https://jiufei.net/bbs/thread-1671-1-1.html
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|合肥网站优化,合肥百度优化,合肥网络推广,合肥SEO优化论坛 ( 皖ICP备2022014487号-2 )

GMT+8, 2025-1-31 11:09 , Processed in 0.180969 second(s), 16 queries , File On.

Powered by jiufei X3.4

© 2008-2020 www.jiufei.net

快速回复 返回顶部 返回列表