PHP Symfony 4 Ajax表单提交

5
我将尝试使用ajax提交表单并将其数据发送到数据库,但我不明白如何处理从ajax调用接收到的数据。
我编写了以下代码:
{% extends 'base.html.twig' %}

{% block title %}Assignments | CRM Fabriek{% endblock %}

{% block body %}

    <div class="container">
        <div class="columns">
            <div class="column is-full">
                <div class="level">
                    <h1 class="level-left title title-no-margin is-vcentered">Assignments</h1>

                    <div class="level-right">
                        {% include 'search.html.twig' %}

                        <a href="{{ path("newAssignment") }}" class="level-item button is-success">Add new</a>
                    </div>
                </div>
                <table class="table is-fullwidth">
                    <tr>
                        <th>Name</th>
                        <th>Description</th>
                        <th>Status</th>
                        <th>Actions</th>
                    </tr>
                    {% if assignments != null %}
                        {% for assignment in assignments %}
                            <tr>
                                <td>{{ assignment.name }}</td>
                                <td>{{ assignment.description }}</td>
                                <td>{{ assignment.status }}</td>
                                <td>
                                    <a class="button is-info is-small" href="{{ path('overviewAssignment', {'id': assignment.id}) }}"><i class="fa fa-eye"></i></a>
                                    <a class="button is-warning is-small" href="{{ path('editAssignment', {'id': assignment.id}) }}"><i class="fa fa-pencil"></i></a>
                                    <button class="button is-success is-small" onclick="openModal({{ assignment.id }})"><i class="fa fa-plus"></i></button>
                                </td>
                            </tr>
                        {% endfor %}
                    {% else %}
                        <tr>
                            <td colspan="4">No entries</td>
                        </tr>
                    {% endif %}
                </table>
                <div class="pagerfanta">
                    {{ pagerfanta(pager)}}
                </div>
                <div>
                    <div class="modal">
                        <div class="modal-background"></div>
                        <div class="modal-card">
                            <header class="modal-card-head">
                                <p class="modal-card-title">Modal title</p>
                            </header>
                            <section class="modal-card-body">
                                {{ form_start(form, {'attr': {'id': 'task_form'}}) }}
                                {{ form_row(form.name, {'attr': {'class': 'input'}}) }}
                                {{ form_row(form.description, {'attr': {'class': 'textarea'}}) }}

                                {{ form_label(form.status) }}
                                <div class="control">
                                    <div class="select">
                                        {{ form_widget(form.status) }}
                                    </div>
                                </div>

                                {{ form_end(form) }}
                            </section>
                            <footer class="modal-card-foot">
                                <button id="submit_task" class="button is-success">Save changes</button>
                                <button class="button" onclick="closeModal()">Cancel</button>
                            </footer>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

{% endblock %}

{% block javascripts %}
    <script>
        function openModal(id){
            $('.modal').addClass('is-active');
            $('#submit_task').attr('onClick', 'submitTask('+ id +');');
        }

        function closeModal(){
            $('.modal').removeClass('is-active');

        }
        function submitTask(id){
            console.log(id);

            form = $('#task_form').serialize();

            console.log(form); 
            $.ajax({
                url:'{{ path('submit_task') }}',
                type: "POST",
                dataType: "json",
                data: {
                    "task": form
                },
                async: true,
                success: function (return_data)
                {
                    console.log(return_data);
                },
                error: function (xhr, ajaxOptions, thrownError)
                {

                }
            });
            closeModal();
        }
    </script>
{% endblock %}

使用控制器中的以下方法:

/**
     * @Route("/", name="submit_task")
     */
    public function add_task(Request $request){
        $form_data = $request->get('task');

        return new JsonResponse($form_data);
    }

表单是在索引操作中创建的:
/**
     * @Security("is_authenticated()")
     * @Route("/assignments", name="assignments")
     */
    public function index(Request $request)
    {

        $assignment_rep = $this->getDoctrine()->getRepository(Assignment::class);

        if($request->get('search') == null) {
            if($this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')){
                $assignments = $assignment_rep->findAll();
            }
            else
            {
                /* @var User $user */
                $user = $this->getUser();
                $assignments = array();
                foreach($user->getAssignments() as $assignment){
                    array_push($assignments, $assignment);
                }
            }
        }
        else{

            if($this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')){
                $assignments = $assignment_rep->search($request->get('search'));
            }
            else
            {
                /* @var User $user */
                $assignments = $assignment_rep->searchUser($request->get('search'), $this->getUser()->getId());
            }
        }

        $page = $request->query->get('page', 1);

        $adapter = new ArrayAdapter($assignments);

        $pagerfanta = new Pagerfanta($adapter);
        $pagerfanta->setMaxPerPage(25);
        $pagerfanta->setCurrentPage($page);


        $task = new Task();
        $form = $this->createForm(TaskFormType::class, $task);
        $form->remove('assignment');

        $assignments = $pagerfanta->getCurrentPageResults();

        return $this->render('assignment/index.html.twig', array(
            'assignments' => $assignments,
            'pager' => $pagerfanta,
            'form' => $form->createView()
        ));
    }

我想知道如何在函数中处理表单数据而不使用“form”对象。有人能帮我解决这个问题吗!

你说的“the method”是指哪个方法? - Finesse
1个回答

7
您的问题是我在Symfony3中遇到的问题,从那时起,我一直在尝试处理通过AJAX发送的内容的各种方法。
获取AJAX数据
这部分很简单,在控制器中只需调用$data = $request->getContent(); 创建服务
创建一个服务来帮助处理这种类型的数据。它使用Symfony的验证器(请参见构造函数:ValidatorInterface),并且有一个名为validateAndCreate的方法,该方法以参数$data(即AJAX请求正文内容)和$entityClassName(即要创建和填充数据的实体,例如:User::class将生成类名字符串)。
规范化器、编码器和序列化器
这三个在处理您的AJAX内容时非常重要。$data可以被反序列化并直接注入到实体实例中(从ClassName参数创建)。
如果数据以JSON格式发送,则使用JsonEncoder,一旦创建了序列化器对象,它就能够直接将JSON数据反序列化到新实例化的对象中(className参数用于生成对象)。
生成对象后,使用验证器检查是否为有效对象。我建议在所有Entity对象中使用@Assert,以使验证器按照预期工作。
class ApiService
{

    private $validator;
    public function __construct(ValidatorInterface $validator)
    {
        $this->validator = $validator;
    }

    public function validateAndCreate($data, $entityClassName){

        $objectNormalizer = new ObjectNormalizer();
        $normalizers = [$objectNormalizer];
        $encoders = [new JsonEncoder()];
        $serializer = new Serializer($normalizers, $encoders);

        $result = $serializer->deserialize($data, $entityClassName, 'json');
        $errors = $this->validator->validate($result);

        if(count($errors) > 0){
            throw new CustomApiException(Response::HTTP_BAD_REQUEST, (string) $errors);
        }

        return $result;

    }
}

在控制器中创建新会议的使用示例

public function newMeeting(Request $request, ApiService $apiService, FractalService $fractalService){
        /** @var Admin $admin */
        $admin = $this->getUser();

        /** @var UserRepository $rep */
        $em = $this->getDoctrine()->getManager();

        $data = $request->getContent();

        if(empty($data)) throw new CustomApiException(Response::HTTP_BAD_REQUEST, "Data sent null.");

        /** @var Meeting $test */
        $meeting = $apiService->validateAndCreate($data, Meeting::class);

        $meeting->setAdmin($admin);
        $admin->addMeeting($meeting);

        $em->persist($test);
        $em->flush();

        //Return data however you wish, I use a FractalService

        $data = $fractalService->generateData($meeting, MeetingTransformer::class, 'meeting');
        return $fractalService->generateResponse($data);

    }

用于AJAX表单处理的客户端示例

$("#form").on("submit", function(e){
   e.preventDefault();
   let data = {};
   $(this).serializeArray().forEach((object)=>{
      data[object.name] = object.value;
   });
   console.log(data);
   
   //TODO: ajax call here with data
   //If ajax call fails because server can't decode
   //Think of doing : data = JSON.stringify(data);
   console.log(JSON.stringify(data));
   
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="form">
  <input type="text" value="john" name="firstname"/>
  <input type="text" value="smith" name="lastname"/>
  <input type="text" value="florida" name="address"/>
  <input type="text" value="1234512345" name="phonenumber"/>
  <input type="text" value="john.smith@gmail.com" name="email"/>

  <input type="submit" value="submit this"/>
</form>


我将尝试这个,有一个问题; 分形服务与所有这些有什么关系? - Sander Bakker
@SanderBakker,由于我有一个API系统,我需要按照JSONApi规范将数据转换为特定的常规格式。在此处了解有关Fractal的更多信息:https://github.com/samjarrett/FractalBundle(我不建议在您的情况下使用它)。 - kemicofa ghost
@SanderBakker 请注意,CustomApiException 只是我创建的自定义异常。我有一个监听器来监听该特定异常并返回 HTTP 400 错误请求响应。您需要相应地进行更改。 - kemicofa ghost
不知道为什么它似乎无法使用JSON编码器进行解码;JsonDecode->decode('task=task_form%255Bname%255D%3DTest%26task_form%255Bdescription%255D%3DTest%26task_form%255Bstatus%255D%3DTo-do%26task_form%255B_token%255D%3DEvrXAl-zRja0oZM60ajFoG9KcdIu7zj7i8WOF1RH2eE&assignment_id=1', 'json', array('json_decode_associative' => true, 'json_decode_recursion_depth' => 512, 'json_decode_options' => 0))。这是怎么回事? - Sander Bakker
@SanderBakker 是的,因为你发送的不是 JSON 数据,而是表单数据,不是真正的 JSON 数据。我会看看能否提供一个客户端示例。 - kemicofa ghost
@SanderBakker,请检查JavaScript代码,console.log是您想要发送的格式。在实际发送之前,您可能需要进行JSON.stringify处理。 - kemicofa ghost

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