1

我一直在尝试提交一个将 Question 对象添加到数据库中的表单。

但每次我这样做时,都会出现错误“CSRF 令牌无效。请尝试重新提交表单”。

在我的表单内容字段中,我附加了这个插件,它是一个与 Stack Overflow 相同的编辑器。

在我的表单标签字段中,我附上了这个标签自动完成。

这是我的控制器代码:

/**
 * Creates a new Question entity.
 *
 * @Route("/ask", name="question_create")
 * @Method("POST")
 * @Template("VerySoftAskMeBundle:Question:ask.html.twig")
 */
public function createAction(Request $request) {
    $entity = new Question();
    $form = $this->createCreateForm($entity);
    $tags = $this->getDoctrine()->getRepository('VerySoftAskMeBundle:Tag')->findAll();
    date_default_timezone_set('Asia/Manila');
    $entity->setDateOfPost(new \DateTime());

    $entity->setOwner($this->getUser());

        $form->handleRequest($request);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($entity);
            $em->flush();

            return $this->redirect($this->generateUrl('question_show', array('id' => $entity->getId())));
        }


    return array(
        'entity' => $entity,
        'form' => $form->createView(),
        'tags' => $tags
    );
}

/**
 * Creates a form to create a Question entity.
 *
 * @param Question $entity The entity
 *
 * @return Form The form
 */
private function createCreateForm(Question $entity) {
    $form = $this->createForm(new QuestionType(), $entity, array(
        'action' => $this->generateUrl('question_create'),
        'method' => 'POST',
        'em' => $this->getDoctrine()->getEntityManager()
    ));

    $form->add('submit', 'submit', array('label' => 'Ask'));

    return $form;
}

/**
     * 
     * @Route("/ask", name="ask")
     * @Security( "has_role( 'ROLE_USER' )" )
     * @Method("GET")
     * @Template
     */
    public function askAction() {

        $tags = $this->getDoctrine()->getRepository('VerySoftAskMeBundle:Tag')->findAll();
        $entity = new Question();
        $form = $this->createCreateForm($entity);

        return array(
            'entity' => $entity,
            'form' => $form->createView(),
            'tags' => $tags
        );
    }

我为我的标签字段制作了一个数据转换器,它将输入标签转换为标签对象。

class TagTransFormer implements DataTransformerInterface {

/**
 * @var ObjectManager
 */
private $om;

/**
 * @param ObjectManager $om
 */
public function __construct(ObjectManager $om) {
    $this->om = $om;
}

/**
 * Transforms an object (issue) to a string (number).
 *
 * @return ArrayCollection
 */
public function transform($tags) {

    return $tags;
}

/**
 * Transforms a string (number) to an object (issue).
 *
 * @param  string $number
 *
 * @return ArrayCollection
 *
 * @throws TransformationFailedException if object (issue) is not found.
 */
public function reverseTransform($ids) {

    $tags = array();

    if (!$ids) {
        return null;
    }

    $repo = $this->om
            ->getRepository('VerySoftAskMeBundle:Tag');

    $idsArray = explode(",", $ids);
    foreach ($idsArray as $id) {
        $tags[] = $repo->findOneByName($id);
    }
    return $tags;
}
}

这是我的表单类:

class QuestionType extends AbstractType {

/**
 * @param FormBuilderInterface $builder
 * @param array $options
 */
public function buildForm(FormBuilderInterface $builder, array $options) {

    $entityManager = $options['em'];
    $transformer = new TagTransFormer($entityManager);

    $builder
            ->add('title', 'text')
            ->add('content', 'textarea')
            ->add($builder->create('tags', 'text')
                    ->addModelTransformer($transformer)
    );
}

/**
 * @param OptionsResolverInterface $resolver
 */
public function setDefaultOptions(OptionsResolverInterface $resolver) {
    $resolver->setDefaults(array(
                'data_class' => 'VerySoft\AskMeBundle\Entity\Question'
            ))
            ->setRequired(array(
                'em',
            ))
            ->setAllowedTypes(array(
                'em' => 'Doctrine\Common\Persistence\ObjectManager',
    ));
}

/**
 * @return string
 */
public function getName() {
    return 'verysoft_askmebundle_question';
}
}

我的树枝模板:

<div id="askDiv" style="padding-bottom: 90px;">
        {{ form_start(form, { 'attr' : { 'novalidate' : 'novalidate', 'class' : 'col-md-offset-3 form-control-static col-md-7' } }) }}
<div class="col-lg-12" style="padding: 0px; margin-bottom: 30px;">
    <span class="askLabels col-lg-1 text-left">{{ form_label(form.title) }}</span>
            {{form_widget(form.title, { 'attr' : { 'class' : 'form-control col-lg-11' } })}}
</div>
        {{ form_widget(form.content, { 'attr' : { 'class' : 'col-lg-12' } }) }}
<div class="col-lg-12" style="padding: 0px; margin-top: 20px;">
    <label class="col-lg-1 text-left askLabels" for="tagField">Tags</label>

    <div class="col-lg-8">
        {{ form_widget(form.tags) }}
    </div>
    {% if app.user.reputation >= 100 %}
    <a id="addTag" title="Add New Tag" data-toggle="tooltip modal" data-placement="left" class="col-lg-3" href="#"><i class="fa fa-plus-circle"></i></a>
    <div id="mymodal" class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                    <h4 class="modal-title" id="myModalLabel">Add New Tag</h4>
                </div>
                <div class="modal-body">
                    <label for="tagName">Tag Name: </label>
                    <input id="tagName" class="form-control" type="text"/>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                    <button type="button" class="btn btn-primary">Add Tag</button>
                </div>
            </div>
        </div>
    </div>

    {% endif %}


</div>
<div style="margin-top: 20px; ">
        {{ form_widget(form.submit, { 'attr' : { 'class' : 'col-md-offset-4 col-md-4  btn btn-primary' } }) }}
</div>

<p>
    title error{{ form_errors(form.title) }}
</p>
<p>
    content error{{ form_errors(form.content) }}
</p>
<p>
    tag error{{ form_errors(form.tags) }}
</p>
<p>
    form error{{ form_errors(form) }}
</p>

脚本:

$(document).ready(function(){
$("textarea").pagedownBootstrap();

    var zeTags = ["{{ tags|join('", "')|raw }}"];
    $('#verysoft_askmebundle_question_tags').tagit({
        availableTags: zeTags,
        tagLimit: 5,
        beforeTagAdded: function(event, ui) {
            if ($.inArray(ui.tagLabel, zeTags) == -1)
                return false;
        }
    });
});
4

2 回答 2

5

你错过了

{{ form_rest(form) }}

Symfony2 有一种机制可以帮助防止跨站点脚本:它们生成一个 CSRF 令牌,该令牌必须用于表单验证。在这里,在您的示例中,您没有使用form_rest(form). 基本上form_rest(form)将“渲染”您之前未渲染但包含在您已传递给视图的表单对象中的每个字段。CSRF 令牌是这些值之一。

于 2014-03-30T08:15:49.487 回答
3

对于较新版本的 Symonfy,例如 2.4+,您将使用 newer form_end(form),它会自动呈现所有未呈现的字段以及 CSRF 令牌。

根据文档

form_end() - Renders the end tag of the form and any fields that have not yet been rendered. This is useful for rendering hidden fields and taking advantage of the automatic CSRF Protection.
于 2014-07-21T19:42:53.613 回答