Анализирайте шаблона Smarty, без да задействате извиквания към потребителски добавки

Пиша разширение (Symfony2) SmartyBundle за поддръжка на Assetic.

За да поддържам функцията стилови таблици, регистрирах блокова добавка, наречена stylesheets:

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

Този плъгин се извиква правилно и всичко работи според очакванията, когато се създаде кешът на Symfony/assetic.

Проблемът възниква, когато кешът на Symfony е празен и Assetic зарежда всеки ресурс на шаблонен файл и иска от механизма на шаблона да извлече 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;
    }

Когато $smarty->fetch() се извика в метода load(), се хвърля изключение: Symfony\Component\Config\Exception\FileLoaderImportCircularReferenceException: Circular reference detected in "." ("." > ".").

Това е причинено от шаблона Smarty, който се анализира/компилира и плъгинът stylesheets се извиква отново.

Затова питам дали Smarty предоставя анализатор на шаблони, който извлича жетоните на блоковата функция (без да извиква приставката за таблици със стилове), за да мога да захранвам Assetic. Или всяко друго решение, което може да ми липсва, за да реша това.

Благодаря.


person noisebleed    schedule 21.03.2012    source източник


Отговори (1)


След кратък разговор със Smarty dev @rodneyrehm стигнахме до извода, че:

  1. Трябва да анализира необработен източник на шаблон, вместо да компилира шаблона и да го анализира
  2. Трябва да напиша собствен анализатор (вместо да използвам някакъв вътрешен помощник на 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

person noisebleed    schedule 31.03.2012
comment
Това звучи ужасно крехко (ами, ако има включвания? какво, ако има коментиран блок? какво, ако разделителят се променя в движение? и т.н.). Защо просто не събирате данни от вашите блокове, докато вървите и ги използвате, след като приключите с анализирането? - person Tgr; 07.06.2012
comment
Прав си, крехко е. Можем да увеличим устойчивостта чрез подобряване на анализатора. Поради ограниченията в 1) и 2) съм оставен сам да използвам моя собствен анализатор. Ако измислите работеща алтернатива, моля, уведомете ме! - person noisebleed; 11.07.2012