Symfony 2:将自定义变量传递给twig表单模板

时间:2014-03-26 22:45:31

标签: php symfony

刚刚开始使用symfony,我正在尝试使用表单模板系统做一些非常简单的事情(对我而言似乎很简单),但我找不到办法。

我的目标是渲染一个"返回"按钮除了提交按钮。我知道如何设置表单模板以及如何覆盖submit_widget,但问题是:必须在调用表单的模板上定义后退按钮URL,所以我需要以某种方式将此作为变量传递给submit_widget,我无法找到办法。

理想情况下,它会像这样工作:

模板:

{% form_theme form 'TutsAdminBundle:Form:bootstrap-horizontal.html.twig' %}

{% block content %}
<h1>User creation</h1>

{{ form(form, { 'attr': {'role': 'form', 'class': 'form-horizontal'}, 'back': path('list_user') }) }}  
{% endblock %}

然后,在表单模板

{% block submit_widget %}
<div class="col-sm-6 col-sm-offset-1">
    <div class="pull-right">
        <a class="btn btn-warning" href="{{ back }}"> Back</a>
        <button type="submit" class="btn btn-success">Save</button>
    </div>
</div>
{% endblock submit_widget %}

但是我无法找到一种方法来访问我的&#34;返回&#34; submit_widget块内的变量。

我怎样才能做到这一点?

更新

我设法做了我想要的事情:

1-按照Chausser的建议创建一个自定义字段:

class SaveButtonType extends SubmitType
{
    public function __construct($router)
    {
        $this->_router = $router;
    }//constructor

    protected $_router;

    /* (non-PHPdoc)
     * @see \Symfony\Component\Form\AbstractType::buildForm()
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {

    }//buildForm

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $href = function(Options $options, $value){
            return array('href'=>$this->_router->generate($options['route'], $options['params']), 'class'=>'btm btn-warning');
        };

        $resolver->setDefaults(array('mapped'=>false))->setRequired(array('route', 'params'));

        $resolver->setNormalizers(array('attr'=>$href));
    }//setDefaultOptions

    public function getName()
    {
        return 'save_button';
    }//getName
}//SaveButtonType

我已经使它扩展了SubmitType,否则它将在form_row中呈现。

services.yml

tuts_admin.form.field.type.save_button:
    class: Tuts\AdminBundle\Form\Field\SaveButtonType
    arguments: ["@router"]
    tags:
        - {name: "form.type", alias: "save_button"}

2-然后我定义了它的模板(在同一个文件中我使用覆盖表单主题

{% block save_button_widget %}
    <div class="col-sm-6 col-sm-offset-1">
        <div class="pull-right marginL25">
            <button type="submit" class="btn btn-success">Save</button>
        </div>
        <div class="pull-right">
            <a href="{{ attr.href }}" class="btn btn-warning">Back</a>
        </div>
    </div>
{% endblock %}

此类型立即呈现提交和后退按钮。

3-最后,由于我找不到阻止渲染另一个提交按钮的方法,我覆盖了submit_widget:

{% block submit_widget %}
{% endblock submit_widget %}

比我预期的要复杂得多,但确实有效。

感谢Chausser的所有帮助。

2 个答案:

答案 0 :(得分:3)

我个人会写一个自定义字段类型,并为后退按钮创建。接受路线名称和路线参数的东西。

//Acme/DemoBundle/Form/Type/BackButtonType
<?php
namespace Acme\DemoBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\OptionsResolver\Options;

class BackButtonType extends AbstractType
{
    protected $router;

    public function __construct($router)
    {
        $this->router = $router;
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $attr = function(Options $options, $value){ 
            return array(
                'href'=>$this->_router->generate($options['route'], $options['params']),                
                'class'=>'btn btn-warning'
            ); 
        };

        $resolver
            ->setDefaults(array(
                'attr' => $attr,
                'mapped' => false
                'params' => array(),
            ))
            ->setRequired(array(
                'route',
            ))
            ->setNormalizers(array(
                'attr'=>$attr
            ));
    }

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

}

然后您需要将其注册为新的表单类型:

parameters:
    acme_demo.form.type.back_button.class: Acme\DemoBundle\Form\Type\BackButtonType

services:
    acme_demo.form.type.back_button:
        class: %acme_demo.form.type.back_button.class%
        arguments: ["@router"]
        tags:
            - { name: "form.type", alias: "back_button" }

现在您可以在正常形式中使用它。最后一步是创建树枝块以渲染此表单。

//Acme/DemoBundle/Resources/Twig/fields.html.twig
{% block back_button_widget %}
    <a {{block('widget_attributes')}}>{{block('form_label')}}</a>
{% endblock %}

然后,您需要将此文件添加到树枝的表单资源中:

//app/config/config.yml
twig:
    debug:            %kernel.debug%
    strict_variables: %kernel.debug%
    form:
        resources:
            - 'AcmeDemoBunlde:Twig:fields.html.twig'

完成后,您需要清除缓存:

php app/console cache:clear --env=dev
php app/console cache:clear --env=prod

现在该如何使用:

//In your Form
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
       // Add other fields
       ->add('back', 'back_button',array('route'=>'my_custom_route_name','params'=>array('user_id'=>$this->getUser()->getUserId())))
       ->add('submit','submit',array('attr'=>array('class'=>'btn btn-primary')));
}

这应该有效。尚未经过全面测试,但如果您有任何问题请告诉我。

答案 1 :(得分:1)

我相信你不需要传递变量,但只能使它(已知)到Twig,因为表单渲染(而不是扩展和包含其他模板)只是块渲染。也就是说,这些变量属于同一范围。

所以:

父模板

{% set back = "MyFooValue" %}

表单模板:

<div class="{{ back }}">Some content</div>

另外,我喜欢将default定义为后备,以防我忘记(或根本不)定义变量:

<div class="{{ back|default("") }}">Some content</div>

希望这会有所帮助......