PHP symfony 4 ajax 表单提交

Posted

技术标签:

【中文标题】PHP symfony 4 ajax 表单提交【英文标题】:PHP symfony 4 ajax form submission 【发布时间】:2018-10-30 04:12:13 【问题描述】:

我正在尝试使用 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()
        ));
    

我想知道如何在函数中没有“表单”对象的情况下处理表单数据。谁能帮我解决这个问题!

【问题讨论】:

你说的“方法”是什么方法? 【参考方案1】:

你的问题是我在 Symfony3 中偶然发现的,从那以后我一直在尝试各种方法来处理通过 AJAX 发送的内容。

获取 AJAX 数据

这部分很简单,在控制器中直接调用$data = $request-&gt;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>

【讨论】:

我要试试这个,一个问题;分形服务与所有这些有什么关系? @SanderBakker 因为我有一个 API 系统,所以我需要按照 JSONApi 规范将数据转换为特定的常规格式。在此处查看有关分形的更多信息github.com/samjarrett/FractalBundle(我不建议在您的情况下使用它) @SanderBakker 请记住,CustomApiException 只是我创建的自定义异常。我有一个侦听器来侦听该特定异常以返回 HTTP 400 错误请求响应。你必须相应地改变它。 不知何故,它似​​乎无法使用 de 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-zRja0oZM60ajFoG9KcdIu7zj7i8'1KcdIu7zj7i8KcdIu7zj7i8 , array('json_decode_associative' => true, 'json_decode_recursion_depth' => 512, 'json_decode_options' => 0)) 关于这怎么可能发生的任何线索? @SanderBakker 是的,因为您不是在发送 JSON,而是在发送表单数据而不是真正的 JSON 数据。我会看看我是否不能提供一个示例客户端。

以上是关于PHP symfony 4 ajax 表单提交的主要内容,如果未能解决你的问题,请参考以下文章

使用 ajax 提交 symfony 3 表单

在 Symfony 5 中验证 AJAX 提交的表单

symfony2 中的 Ajax 表单提交,为没有 javascript 的用户提供优雅的降级

CSRF 令牌无效。请尝试重新提交表单。 Symfony 4

Symfony 表单和 Ajax

在 ajax 提交时禁用 symfony 2 csrf 令牌保护