AJAX 表单 post 上的 Symfony 419 状态错误

Symfony 419 status error on AJAX form post

我正在通过 AJAX post posting 一个 Symfony 表单,在我对“Siparis”实体和“SiparisType”中的相关表单字段进行字段编辑后,我保留了在 post.

上获得 419

Symfony 版本:6.0.2 - PHP version:8.1.2 数据库:10.4.22-MariaDB

我试图禁用 csrf 保护,但仍然得到相同的状态 419,除此之外什么都没有。 处理 AJAX post 的 Symfony 路由(我在编辑字段后恢复了我的最新更改,以下版本之前工作正常):

#[Route('/save/', name: 'save', methods: ['POST'])]
public function save_siparis(Request $request, EntityManagerInterface $entityManager): JsonResponse
{
    $siparis = new Siparis();
    try {
        $form = $this->createForm(SiparisType::class, $siparis);
        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            $entityManager->persist($siparis);
            $entityManager->flush();

            return new JsonResponse(['result' => 'OK', 'siparis_id' => $siparis->getId()]);
        }
    }catch(\Exception $e){
        error_log($e->getMessage());
        return new JsonResponse(array('result' => $e->getMessage()), 419);
    }
}

控制器上的渲染表单路由: 唯一的变化是:'firma' => 本节中表单的 $id 选项

#[Route('/new/{id}', name: 'new', methods: ['GET'])]
public function new($id, Request $request, EntityManagerInterface $entityManager, SiparisRepository $siparisRepository,FirmaRepository $firmaRepository, IlgiliRepository $ilgiliRepository): Response
{
    $siparis = new Siparis();
    $latest_siparis = $siparisRepository->findBy(['Musteri' => $id], ['id' => 'desc', ]);
    $siparis_id = 1;
    if(!is_null($latest_siparis))
        $siparis_id = count($latest_siparis) + 1;


    $musteri = $firmaRepository->find($id);
    $siparisNo = 'TST-'.str_replace(' ', '-',$musteri->getKod()).'-'.str_pad($siparis_id, 3, '0', STR_PAD_LEFT);
    $form = $this->createForm(SiparisType::class, $siparis, ['firma' => $id,'attr' => ['id' => 'siparis_form']]);
    $firmalar = $firmaRepository->findBy(['Type' => 0]);
    $maliyet = new Maliyetler();
    $maliyet_form = $this->createForm(MaliyetlerType::class, $maliyet, ['attr' => ['id' => 'maliyet_form']]);
    
    return $this->renderForm('siparis/new.html.twig', [
        'siparisNo' => $siparisNo,
        'sipari' => $siparis,
        'form' => $form,
        'maliyet_form' => $maliyet_form,
        'satici_firmalar' => $firmalar,
        'musteri' => $musteri,
        'mode' =>'NEW'
    ]);
}

我的表单类型: 字段:'siparis_veren' 是一个 TextType,我已将其更改为 EntityType,并通过查询生成器

获取相关实体
public function buildForm(FormBuilderInterface $builder, array $options): void
{
    $firma = $options['firma'];
    $SIPARIS_CHOICES = ['Devam Ediyor' => '1','Tamamlandı' => '2','İptal' => '3'];
    $builder
        ->add('teslim_tarihi', DateType::class, [
            'widget' => 'single_text',
            'label' => 'Teslim Tarihi', 'attr' =>['class' => 'form-control', 'placeholder' => 'Teslim Tarihi']
        ])
        ->add('siparis_tarihi', DateType::class, [
            'widget' => 'single_text',
            'label' => 'Sipariş Tarihi', 'attr' =>['class' => 'form-control', 'placeholder' => 'Sipariş Tarihi']
        ])
        ->add('siparis_veren', EntityType::class,['class' => Ilgili::class,
            'choice_label' => 'full_name',
            'query_builder' => function (EntityRepository $er) use ($firma) {
                return $er->createQueryBuilder('ilgili')
                    ->andWhere('ilgili.firma = :firma')
                    ->setParameter('firma', $firma);
            },
            'label' => 'Siparişi Veren', 'attr' =>['class' => 'form-control', 'placeholder' => 'Siparişi Veren']])
        ->add('siparis_durum', ChoiceType::class,['choices' => $SIPARIS_CHOICES,'attr' =>['class' => 'form-control', 'placeholder' => 'Siparişi Alan'] ])
        ->add('siparis_turu', HiddenType::class)
        ->add('siparis_genel_aciklama', TextType::class,['label' => 'Sipariş Genel Açıklaması', 'attr' =>['class' => 'form-control', 'placeholder' => 'Sipariş Genel Açıklaması']])
        ->add('siparis_satir_aciklama', HiddenType::class)
        ->add('siparis_miktari', HiddenType::class)
        ->add('siparis_fiyati', HiddenType::class)
        ->add('fatura_durumu', HiddenType::class)
        ->add('siparisNo', HiddenType::class)
        ->add('siparis_kdv_orani', HiddenType::class);
}

public function configureOptions(OptionsResolver $resolver): void
{
    $resolver->setDefaults([
        'data_class' => Siparis::class,
        'csrf_protection' => true,
        'csrf_field_name' => '_token',
    ]);
    $resolver->setRequired(['firma']);
}

我在客户端的AJAX表单post(这里没有变化):

$('form[name="siparis"]').submit(function(e) {
        e.preventDefault();

        var url = "{{ path('siparis_save') }}";
        var formSerialize = $(this).serialize();
        $.post(url, formSerialize, function(response) {
            if(response.result === "OK")
            {
                $( 'form[name="maliyetler"]' ).submit();
            }
            else
            {
                console.log(response.result);
            }

        }, 'JSON');
    });

在我的 Siparis 实体中 siparis_veren 是一个文本字段,我向它添加了一个与 Ilgili class 的 ManyToOne 关系,在我进行更改后 post 一直给我 419 错误。

#[ORM\ManyToOne(targetEntity: Ilgili::class, inversedBy: 'siparisler')]
#[ORM\JoinColumn(nullable: false)]
private $siparis_veren;

我尝试清除缓存,从表单类型和控制器中删除了相关的 siparis_veren 字段,但结果是一样的,除非我像以前一样将 siparis_veren 恢复为 TextType。

抱歉,如果我的解释还不够,我找不到关于这个问题的任何结果,SO 是我唯一的选择,我是 Symfony 的新手。

谢谢。

好的,我发现了问题,我没有注意到我在 Try Catch catch 块上将状态设置为 419,所以以为它是关于 Symfony 或客户端的。在进行了一些调试之后,我得到“解析表单选项时发生错误App\Form\SiparisType”:缺少必需的选项“firma”。

引起的错误

SiparisConroller.php

$form = $this->createForm(SiparisType::class, $siparis);

save_siparis() 函数中的这一行。在 SiparisType 中,我根据需要设置了 'firma' 字段 SiparisType.php

$resolver->setRequired(['firma']);

因此我在 Try Catch 块中遇到错误。

感谢@jean-max 对检查 Try Catch 的建议。