首页 文章

解析Smarty模板而不触发对用户插件的调用

提问于
浏览
0

我正在写一个(Symfony2)SmartyBundle扩展来支持Assetic .

为了支持stylesheets feature我已经注册了一个名为 stylesheets 的块插件:

{stylesheets
    assets='@SmartyBundle/Resources/public/css/*'
    debug=true}
    <a href="{$asset_url}">{$asset_url}</a>
{/stylesheets}

正确调用此插件,并且在创建Symfony / assetic缓存时,一切都按预期工作 .

问题出现当Symfony缓存为空并且Assetic加载每个模板文件资源并要求模板引擎检索带有stylesheets标记中找到的标记的PHP数组时 . 被调用以检索数组的类是 SmartyFormulaLoader .

<?php

class SmartyFormulaLoader implements \Assetic\Factory\Loader\FormulaLoaderInterface
{   
    public function load(ResourceInterface $resource)
    {
        // raw template content
        $content = $resource->getContent();

        // a FileLoaderImportCircularReferenceException is throw here
        $smartyParsed = $this->smarty->fetch('string: '.$content);

        // build an array with tokens extracted from the block function
        $formulae = $this->extractStylesheetsTokens($smartyParsed);

        return $formulae;
    }

load() 方法中调用 $smarty->fetch() 时,将引发异常: Symfony\Component\Config\Exception\FileLoaderImportCircularReferenceException: Circular reference detected in "." ("." > ".") .

这是由Smarty模板被解析/编译并再次调用 stylesheets 插件引起的 .

所以我问Smarty是否提供了一个模板解析器来提取块函数标记(不调用样式表插件),所以我可以提供Assetic . 或者我可能缺少任何其他解决方案来解决这个问题 .

谢谢 .

1 回答

  • 0

    在与Smarty dev @rodneyrehm聊了一会后,我们得出结论:

    • 应该解析原始模板源而不是编译模板并解析它

    • 应该编写我自己的解析器(而不是使用一些Smarty内部帮助器)

    因此,对于这个特殊情况,我们提出了这个实现:

    <?php
    
    class SmartyFormulaLoader
    {
        public function load(ResourceInterface $resource)
        {
            // template source
            $templateSource = $resource->getContent();
    
            // ask Smarty which delimiters to use
            $ldelim = $smarty->left_delimiter;
            $rdelim = $smarty->right_delimiter;
            $_ldelim = preg_quote($ldelim);
            $_rdelim = preg_quote($rdelim);
    
            // template block tags to look for
            $tags = implode('|', array('stylesheets', 'javascripts', 'image));
    
            // match every assetic tag
            if (preg_match_all('#'.$_ldelim.'(?<type>'.$tags.').*?'.$_rdelim.'#s', $templateSource, $matches, PREG_SET_ORDER)) {
                foreach ($matches as $match) {
                    // extract block attributes 
                    if (preg_match_all('#(?<key>[a-zA-Z0-9_]+)\s*=\s*(["\']?)(?<value>[^\2]*?)\2(\s|'.$_rdelim.')#s', $match[0], $_matches, PREG_SET_ORDER)) {
                        $t = array(
                            'type'          => $match['type'],
                            'attributes'    => array(),
                        );
    
                        foreach ($_matches as $_match) {
                            if (empty($_match[2])) {
                                // make eval a little bit safer
                                preg_match('#[^\w|^\.]#', $_match['value'], $evalMatches);
                                $_match['value'] = ($evalMatches) ? null : eval(sprintf('return %s;', $_match['value']));
                            }
                            $t['attributes'][$_match['key']] = $_match['value'];
                        }
    
                        // call some Assetic methods with the extracted attributes
                        $formulae += $this->buildFormula($match['type'], $t['attributes']);
                    }
                }
            }
    
            return $formulae;
        }
    }
    

    完整实施可在此处获取:https://github.com/noiselabs/SmartyBundle/blob/master/Assetic/SmartyFormulaLoader.php

相关问题