PHP symfony 4 ajax form submission

San*_*ker 5 javascript php ajax jquery symfony

I'm trying to submit a form using ajax and send it's data to the database, but I don't understand how to proces the data received from the ajax call.

I wrote the following code:

{% 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 %}
Run Code Online (Sandbox Code Playgroud)

With the following method in the controller:

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

        return new JsonResponse($form_data);
    }
Run Code Online (Sandbox Code Playgroud)

The form is created in the index action:

/**
     * @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()
        ));
    }
Run Code Online (Sandbox Code Playgroud)

I would like to know how to process the form data without the "form" object in the function. Could anyone help me out with this problem!

kem*_*ica 7

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

获取 AJAX 数据

这部分很简单,在控制器中简单调用 $data = $request->getContent();

创建服务

创建一个服务来帮助处理此类数据。它使用 Symfony 的验证器(参见构造函数:)ValidatorInterface,并调用validateAndCreate了一个方法,该方法接受作为参数$data(这是 AJAX 请求正文内容)和$entityClassName(这是要创建和填充数据的实体,例如:User::class将生成类名细绳)

规范器、编码器和序列化器

这三个对于处理 AJAX 内容很重要。$data可以反序列化并直接注入实体实例(从 ClassName 参数创建)

如果发送数据,JSON则使用JsonEncoder,一旦创建了序列化程序对象,它将能够将 JSON 数据直接反序列化为新实例化的对象(参数中的 className 用于生成对象)。

生成对象后,使用验证器检查它是否为有效对象。我建议@Assert在所有 Entity 对象中使用 ,以便验证器相应地工作。

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;

    }
}
Run Code Online (Sandbox Code Playgroud)

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

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);

    }
Run Code Online (Sandbox Code Playgroud)

AJAX 表单处理的客户端示例

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;

    }
}
Run Code Online (Sandbox Code Playgroud)
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);

    }
Run Code Online (Sandbox Code Playgroud)