Разбор шаблона Smarty без вызова пользовательских плагинов

Я пишу (Symfony2) расширение SmartyBundle для поддержки Assetic.

Для поддержки функции таблиц стилей я зарегистрировал блочный плагин под названием stylesheets:

{stylesheets
    assets='@SmartyBundle/Resources/public/css/*'
    debug=true}
    <a href="{$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