Symfony 3表单+ Aurelia

4

我一直在使用Symfony 3构建Web应用程序,使用表单类型并在页面上呈现表单。我正在尝试使用Aurelia自定义元素在页面上呈现Symfony表单,然后将表单提交回Symfony。我已经到达了验证提交表单的阶段,但它从未通过验证。有人可以看一下以下代码并查看是否遗漏了什么吗?

表单类型:

<?php

namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use AppBundle\Service\PayeeService;

class PayeeType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', TextType::class)
            ->add('category', ChoiceType::class, [
                'choices' => [
                    'Uncategorized' => PayeeService::CATEGORY_UNCATEGORIZED,
                    'Installment Loan' => PayeeService::CATEGORY_INSTALLMENT_LOAN,
                    'Credit Card' => PayeeService::CATEGORY_CREDIT_CARD,
                    'Utility' => PayeeService::CATEGORY_UTILITY,
                    'Mortgage' => PayeeService::CATEGORY_MORTGAGE,
                    'Entertainment' => PayeeService::CATEGORY_ENTERTAINMENT
                ],
                'choices_as_values' => true
                ])
            ->add('amount', MoneyType::class, ['currency' => 'USD', 'grouping' => true])
            ->add('frequency', ChoiceType::class, [
                'choices' => [
                    'Recurring' => PayeeService::FREQUENCY_RECURRING,
                    'One-time' => PayeeService::FREQUENCY_ONETIME
                ],
                'choices_as_values' => true
                ])
            ->add('method', ChoiceType::class, [
                'choices' => [
                    'ACH' => PayeeService::PAY_METHOD_ACH,
                    'Check' => PayeeService::PAY_METHOD_CHECK
                ],
                'choices_as_values' => true
                ])
            ->add('dateLastPaid', DateType::class)
            ->add('dueDate', DateType::class)
            ->add('gracePeriod', IntegerType::class)
            ->add('balance', MoneyType::class, ['currency' => 'USD', 'grouping' => true])
            ->add('active', CheckboxType::class, ['label' => 'Active', 'data' => true])
            ->add('save', SubmitType::class, ['label' => 'Save Payee'])
        ;
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\Payee'
        ));
    }
}

控制器:


<?php

namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;

class FormController extends Controller
{
    /**
     * @Route("/_form/entity/{entity}", name="new_entity_form")
     * @Method("GET")
     */
    public function getFormForNewEntity(Request $request)
    {
        $rawName = $request->get('entity');
        $content = $request->getContent();
        $data = json_decode($content, true);
        $formName = strtolower($rawName) . "_form";
        $submitFunction = $data['submitFunction'];
        $entityName = "AppBundle\Entity\\" . $rawName;
        $entity = new $entityName();
        $form = $this->createForm("\AppBundle\Form\\{$rawName}Type", $entity);
        return $this->render('form/form.html.twig', [
            'name' => $formName,
            'form' => $form->createView(),
            'submitFunction' => $submitFunction]);
    }

    /**
     * @Route("/_form/entity/{entity}", name="new_entity_create")
     * @Method("POST")
     */
    public function saveFormForNewEntity(Request $request)
    {
        $em = $this->getDoctrine()->getManager();
        $rawName = $request->get('entity');
        $entityName = "AppBundle\Entity\\" . $rawName;
        $entity = new $entityName();
        $form = $this->createForm("\AppBundle\Form\\{$rawName}Type", $entity);
        $form->handleRequest($request);
        if ($form->isValid()) {
            $em->persist($entity);
            $em->flush();
            return new JsonResponse(['result' => true]);
        } elseif ($form->isEmpty()) {
            return new JsonResponse(['result' => false, 'errors' => 'form empty']);
        } else {
            return new JsonResponse(['result' => false, 'errors' => iterator_to_array($form->getErrors(true))]);
        }
    }
}

从twig表单:

{{ form_start(form, {'attr': {'id':name, 'role':'form', 'submit.delegate':submitFunction}}) }}
{{ form_widget(form) }}
{{ form_end(form) }}

Aurelia组件JS:

import {InlineViewStrategy} from 'aurelia-framework';
import {customElement, bindable, inject} from 'aurelia-framework';
import $ from 'jquery';
import {HttpClient} from 'aurelia-http-client';
import 'fetch';

@customElement('symfony-form')
@inject(Element)
export class SymfonyForm {

    @bindable entity;

    constructor(element) {
        this.content = '';
        this.http = new HttpClient();
        this.http.configure(config => {
          config
            .withBaseUrl('http://localhost:8000/');
        });


        this.element = element;
    }

    bind(binding, override) {
        return this.http.get('_form/entity/' + this.entity, {'submitFunction': 'submit()'})
        //.then(response => response.html())
        .then(response => {
            this.content = response.response;
        });
    }

    submit() {
        // application/x-www-form-urlencoded
        this.http.createRequest('_form/entity/' + this.entity)
            .withHeader('Content-Type', 'application/x-www-form-urlencoded')
            .asPost()
            .withContent($(this.element).find('form').serialize())
            .send()
            .then(response => {
                alert(response.response);
            });
        //alert('submitted ' + this.entity);
        // return this.http.post('_form/entity/' + this.entity, $(this.element).find('form').serialize())
        // .then(response => {
        //     alert(response.response);
        // });
    }
}
<template>
    <form role="form" submit.delegate="submit()">
        <div innerHTML.bind="content"></div>
    </form>
</template>
<template>
    <require from="form"></require>
  <section class="au-animate">
    <h2>${heading}</h2>
    <form role="form" submit.delegate="submit()">
      <div class="form-group">
        <label for="fn">First Name</label>
        <input type="text" value.bind="firstName" class="form-control" id="fn" placeholder="first name">
      </div>
      <div class="form-group">
        <label for="ln">Last Name</label>
        <input type="text" value.bind="lastName" class="form-control" id="ln" placeholder="last name">
      </div>
      <div class="form-group">
        <label>Full Name</label>
        <p class="help-block">${fullName | upper}</p>
      </div>
      <button type="submit" class="btn btn-default">Submit</button>
    </form>
    <symfony-form entity="Payee"></symfony-form>
  </section>
</template>

4
为什么你不想在Aurelia上使用单页应用作为前端,只将Symfony作为后端API呢? - Alexander Mikhalchenko
我也在想同样的问题。另外,我不确定你是在问Symfony中的表单验证还是JS中的表单验证? - tftd
@AlexanderM。我计划使用SPA作为前端,但是我希望利用现有的Symfony表单来获得一些免费的验证和CRUD操作。 - Jason Miesionczek
@tftd 我在问关于Symfony的验证。$form->isValid() 总是返回false,而 $form->getErrors() 没有返回任何内容。 - Jason Miesionczek
1
我明白了。问题在于你正在使用Aurelia来渲染表单模板。如果你阅读这里的文档,你会发现你需要使用{{ form_start(form) }}{{ form_end(form) }},其中包括一些隐藏的CSFR字段。你可以使用{{ form_widget(form._token) }}显式地呈现CSFR字段。我想这就是导致你的表单验证失败的原因。 - tftd
1个回答

0

我不是专家,也不精通单页应用程序或JS框架,但根据我所见,问题在于缺少具有正确令牌的CSFR字段,同时我认为您的输入未被命名为适合Symphony读取它们的名称(如果我错过了这个处理,则表示歉意)。您需要将输入名称格式化如下:

<input type="text" name="formname[formfield]" />

例如,我认为您需要将姓名字段设置为:

<input type="text" name="payeetype[name]" />

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接