Отправка формы ajax в PHP symfony 4

Я пытаюсь отправить форму с помощью 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.info(id);

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

            console.info(form); 
            $.ajax({
                url:'{{ path('submit_task') }}',
                type: "POST",
                dataType: "json",
                data: {
                    "task": form
                },
                async: true,
                success: function (return_data)
                {
                    console.info(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);
    }

Форма создается в действии index:

/**
     * @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()
        ));
    }

Я хотел бы знать, как обрабатывать данные формы без объекта «форма» в функции. Может ли кто-нибудь помочь мне с этой проблемой!

Какой метод вы имеете в виду, говоря «метод»?

Finesse 20.05.2018 10:39
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
5
1
13 151
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваша проблема - это то, на что я наткнулся еще в Symfony3, и с тех пор я пробовал различные методы обработки контента, отправленного через AJAX.

Получить данные AJAX

Эта часть проста, в контроллере просто вызовите $data = $request->getContent();

Создать услугу

Создайте сервис, который поможет обрабатывать такие данные. Он использует валидатор Symfony (см. Конструктор: ValidatorInterface) и имеет метод под названием validateAndCreate, который принимает в качестве параметра $data (который является содержимым тела запроса AJAX) и $entityClassName (который является объектом для создания и заполнения данными, например: User::class сгенерирует строку имени класса)

Нормализатор, кодировщик и сериализатор

Эти три будут важны при обработке вашего AJAX-контента. $data можно десериализовать и внедрить непосредственно в экземпляр объекта (созданный из параметра ClassName).

Если данные отправляются как JSON, используйте JsonEncoder, после создания объекта сериализатора он сможет десериализовать данные JSON непосредственно во вновь созданный объект (параметр className in используется для создания объекта).

После создания объекта используйте валидатор, чтобы проверить, является ли он действительным объектом. Я рекомендую использовать @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;

    }
}

Пример использования в контроллере для создания новой встречи

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.info(data);
   
   //TODO: ajax call here with data
   //If ajax call fails because server can't decode
   //Think of doing : data = JSON.stringify(data);
   console.info(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 = "[email protected]" name = "email"/>

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

Я собираюсь попробовать это, один вопрос; При чем здесь фрактальный сервис?

Sander Bakker 20.05.2018 10:56

@SanderBakker, поскольку у меня есть система API, мне нужно преобразовать данные в определенный обычный формат в соответствии со спецификациями JSONApi. Подробнее о фрактале смотрите здесь github.com/samjarrett/FractalBundle (не рекомендую использовать его в вашем случае)

kemicofa ghost 20.05.2018 10:58

@SanderBakker имейте в виду, что CustomApiException - это просто созданное мной настраиваемое исключение. У меня есть слушатель, который прослушивает это конкретное исключение, чтобы вернуть неверный ответ на запрос HTTP 400. Вам придется соответственно изменить это.

kemicofa ghost 20.05.2018 11:00

Почему-то кажется, что он не может декодировать с помощью кодировщика de json; JsonDecode-> decode ('task = task_form% 255Bname% 255D% 3DTest% 26ta‌ sk_form% 255Bdescript‌ ion% 255D% 3DTest% 26ta‌ sk_form% 255Bstatus% 2‌ 55D% 3DTo-do% 26task_f‌ orm% 255B_token% 255D% ‌ 3DEvrXAl-zRja0oZM60a‌ jFoG9KcdIu7zj7i8WOF1‌ RH2eE & assignment_id = ‌ 1 ',' json ', array (' json_decode_associative '=> true,' json_decode_recursion_depth '), как это могло произойти> 512 ?

Sander Bakker 20.05.2018 11:20

@SanderBakker да, потому что вы не отправляете JSON, вы отправляете данные формы, а не данные JSON. Я посмотрю, не смогу ли я предоставить пример клиентской части.

kemicofa ghost 20.05.2018 11:24

@SanderBakker там проверьте код javascript, console.info - это формат, в котором вы хотите его отправить. Возможно, вам придется выполнить JSON.stringify, прежде чем отправлять его.

kemicofa ghost 20.05.2018 11:32

Другие вопросы по теме