Twig:将对象变量从页面拉到自定义标签

时间:2014-11-04 14:32:57

标签: php symfony twig

我制作了一个名为" story_get_adjacent"的自定义树枝标签。根据输入ID获取下一篇/上一篇文章。但是对于我的生活,我无法将对象的实际数据拉入标签中以便查找。它总是让我回到名字而不是数据。我知道这可以做到,因为我用set标签测试了它,它返回的数据不是名字。思考????

页面上的对象

Object >>
    Title = "This is a test story"
    StoryID = 1254
    Content ....

标签用法示例:

 {% story_get_adjacent Object.StoryID as adjacent %}

Twig Extension:

class Story_Get_Adjacent_TokenParser extends Twig_TokenParser
{
    public function parse(Twig_Token $token)
    {
        $parser = $this->parser; //story_get_adjacent
        $stream = $parser->getStream(); // space

        $value = $parser->getExpressionParser()->parseExpression(); //story id
        $names = array();
        try {
            $as = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); //as
            $ObjName = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); //object name
            array_push($names, $ObjName);
        } catch (Exception $e) {
            throw new Exception( 'error: ' . $e);
        }
        $stream->expect(Twig_Token::BLOCK_END_TYPE);
        return new Story_Get_Adjacent_Node($names, $value, $token->getLine(), $this->getTag());
    }

    public function getTag()
    {
        return 'story_get_adjacent';
    }
}

Twig Extension:

class Story_Get_Adjacent_Node extends Twig_Node
{
    public function __construct($name, Twig_Node_Expression $value, $line, $tag = null)
    {
        parent::__construct(array('value' => $value), array('name' => $name), $line, $tag);
    }

    public function compile (Twig_Compiler $compiler)
    {
        $Name     = $this->getAttribute('name')[0];
        $StoryAutoID    = $this->getNode('value')->getAttribute('value');

        $compiler->addDebugInfo($this);
        $compiler->write('$context[\''. $Name .'\'] = NewsController::TwigStoryGetAdjacent("'.$StoryAutoID.'");')->raw("\n");
    }
}

2 个答案:

答案 0 :(得分:3)

Alain Tiemblo解决了你的问题。但是,为什么你的生活如此艰难?为什么不简单地使用树枝功能呢?

{% set adjacent = story_get_adjacent(Object.StoryID) %}
class StoryExtension extends \Twig_Extension
{
    public function getFunctions()
    {
        return array(
            \Twig_SimpleFunction('story_get_adjacent', array($this, 'getAdjacent'), array('is_safe' => array('html'))),
        );
    }

    public function getAdjacent($storyId)
    {
        return NewsController::TwigStoryGetAdjacent($storyId);
    }

    public function getName()
    {
        return 'story';
    }
}

is_safe选项告诉twig它的安全HTML,因此您在使用{{ story_get_adjacent(Object.StoryID) }}时不必禁用转义。

答案 1 :(得分:2)

当您尝试访问表达式的value属性时,问题出在编译器中。

  1. 需要将表达式解析器子编译为PHP中的表达式。
  2. 由于编译后的表达式是未评估的表达式,因此在调用'时不应放置引号(TwigStoryGetAdjacent)。
  3. 尝试使用以下类:

    <?php
    
    class Story_Get_Adjacent_Node extends Twig_Node
    {
    
        public function __construct($name, Twig_Node_Expression $value, $line, $tag = null)
        {
            parent::__construct(array ('value' => $value), array ('name' => $name), $line, $tag);
        }
    
        public function compile(Twig_Compiler $compiler)
        {
            $Name = reset($this->getAttribute('name'));
    
            $compiler->addDebugInfo($this);
            $compiler
               ->write("\$context['$Name'] = NewsController::TwigStoryGetAdjacent(")
               ->subcompile($this->getNode('value'))
               ->write(");")
               ->raw("\n")
            ;
        }
    
    }
    

    工作演示

    test.php的

    <?php
    
    require(__DIR__ . '/vendor/autoload.php');
    
    require("TestExtension.php");
    require("TestTokenParser.php");
    require("TestNode.php");
    
    class NewsController
    {
    
        static public function TwigStoryGetAdjacent($id)
        {
            return "I return the story ID = {$id}.";
        }
    
    }
    
    $loader = new Twig_Loader_Filesystem('./');
    $twig = new Twig_Environment($loader, array (
            'cache' => __DIR__ . '/gen'
    ));
    
    $object = new \stdClass;
    $object->StoryID = 42;
    
    $twig->addExtension(new Test_Extension());
    echo $twig->render("test.twig", array ('Object' => $object));
    

    test.twig

    {% story_get_adjacent Object.StoryID as adjacent %}
    {{ adjacent }}
    

    TestExtension.php

    <?php
    
    class Test_Extension extends \Twig_Extension
    {
    
        public function getTokenParsers()
        {
            return array (
                    new Test_TokenParser(),
            );
        }
    
        public function getName()
        {
            return 'test';
        }
    
    }
    

    TestTokenParser.php

    <?php
    
    class Test_TokenParser extends Twig_TokenParser
    {
        public function parse(Twig_Token $token)
        {
            $parser = $this->parser; //story_get_adjacent
            $stream = $parser->getStream(); // space
    
            $value = $parser->getExpressionParser()->parseExpression(); //story id
            $names = array();
            try {
                $as = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); //as
                $ObjName = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); //object name
                array_push($names, $ObjName);
            } catch (Exception $e) {
                throw new Exception( 'error: ' . $e);
            }
            $stream->expect(Twig_Token::BLOCK_END_TYPE);
            return new Test_Node($names, $value, $token->getLine(), $this->getTag());
        }
    
        public function getTag()
        {
            return 'story_get_adjacent';
        }
    }
    

    TestNode.php

    <?php
    
    class Test_Node extends Twig_Node
    {
    
        public function __construct($name, Twig_Node_Expression $value, $line, $tag = null)
        {
            parent::__construct(array ('value' => $value), array ('name' => $name), $line, $tag);
        }
    
        public function compile(Twig_Compiler $compiler)
        {
            $Name = reset($this->getAttribute('name'));
    
            $compiler->addDebugInfo($this);
            $compiler
               ->write("\$context['$Name'] = NewsController::TwigStoryGetAdjacent(")
               ->subcompile($this->getNode('value'))
               ->write(");")
               ->raw("\n")
            ;
        }
    
    }
    

    运行

    $ composer require "twig/twig" "~1.0"
    $ php test.php
    

    结果

    I return the story ID = 42.
    

    奖金 与模板对应的已编译的doDisplay方法

        protected function doDisplay(array $context, array $blocks = array())
        {
            // line 1
            $context['adjacent'] = NewsController::TwigStoryGetAdjacent($this->getAttribute((isset($context["Object"]) ? $context["Object"] : null), "StoryID", array())        );
            // line 2
            echo twig_escape_filter($this->env, (isset($context["adjacent"]) ? $context["adjacent"] : null), "html", null, true);
        }