有没有办法在 Symfony 中使用表单发送 GET 请求并避免在更改 URL 时重新加载页面?

Is there a way to send a GET request using forms in Symfony and avoid reloading the page while changing the URL?

我有以下表格类型:

<?php

namespace Myproject\App\ErpBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormEvent;
use Myproject\OrderBundle\Entity\OrderProductType;
use Myproject\OrderBundle\Entity\OrderOrder;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\HttpFoundation\RequestStack;

class OrderSearchType extends AbstractType
{
    protected $em;
    protected $container;
    protected $requestStack;

    public function __construct(ObjectManager $em, ContainerInterface $container, RequestStack $requestStack)
    {
        $this->em = $em;
        $this->container = $container;
        $this->requestStack = $requestStack;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $data = $builder->getData();
        $currentRequest = $this->requestStack->getCurrentRequest();
        $pt = [
            'class' => OrderProductType::class,
            'choices' => [],
            'required' => false
        ];
        if ($productType = $currentRequest->query->get('ProductType', null)) {
            $pt["data"] = $productType;
        }
        $id = [
            'label' => 'id',
            'required' => false
        ];
        if ($idValue = $currentRequest->query->get('id', null)) {
            $id["data"] = $idValue;
        }
        $name = [
            'label' => 'név',
            'required' => false
        ];
        if ($nm = $currentRequest->query->get('name', null)) {
            $name["data"] = $nm;
        }
        $builder
            ->add('productType', EntityType::class, $pt)
            ->add('id', IntegerType::class, $id)
            ->add('name', TextType::class, $name)
            ->add('status', ChoiceType::class, [
                'choices' => [  'Bármilyen',
                                OrderOrder::$ORDER_STATUS_TEXT[OrderOrder::$ORDER_STATUS_ORDERED],
                                OrderOrder::$ORDER_STATUS_TEXT[OrderOrder::$ORDER_STATUS_ACCEPTED],
                                OrderOrder::$ORDER_STATUS_TEXT[OrderOrder::$ORDER_STATUS_REFUSED]
                            ],
                'data' => $currentRequest->query->get('status', "1")
            ])
            ->add('search', SubmitType::class, [
                'label' => 'Keresés',
                'attr' => ['class' => 'btn btn-primary btn-sm']
            ]);

        $builder->addEventListener(FormEvents::PRE_SUBMIT, array($this, 'onPresubmit'));
        $builder->addEventListener(FormEvents::POST_SET_DATA, array($this, 'onPostSetData'));
    }

    public function onPostSetData(FormEvent $event)
    {
        $form = $event->getForm();
        $data = $form->getData();
        $event->getForm()
            ->add('productType', EntityType::class, [
                'class' => OrderProductType::class,
                'choices' => $this->em->getRepository(OrderProductType::class)->findAll(),
                'choice_label' => function($orderProductType = null) {
                    return sprintf($orderProductType ? $orderProductType->getTitle() : "Kérem válasszon");
                },
                'label' => 'Termékfajta',
                'required' => false,
                'attr' => [
                    'class' => 'selectpicker',
                    'data-live-search' => 'true'
                ]
            ]);
    }

    public function onPresubmit(FormEvent $event)
    {
        $form = $event->getForm();
        $data = $event->getData();
        $event->getForm()
            ->add('productType', EntityType::class, [
                'class' => OrderProductType::class,
                'choices' => $this->em->getRepository(OrderProductType::class)->findAll(),
                'choice_label' => function($orderProductType = null) {
                    return sprintf($orderProductType ? $orderProductType->getTitle() : "Kérem válasszon");
                },
                'label' => 'Termékfajta',
                'required' => false,
                'attr' => [
                    'class' => 'selectpicker',
                    'data-live-search' => 'true'
                ]
            ]);
    }
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => null,
            'em' => $this->em,
        ]);

        parent::configureOptions($resolver);
    }

    public function getBlockPrefix()
    {
        return 'route';
    }
}

在ui上显示是这样的:

            {{ form_start(form, { 'attr': {'class': 'myprojectAdminForm pull-right', 'id': form.vars.name } }) }}
                Szűrés: 
                {{ form_widget(form.productType) }}
                {{ form_widget(form.id, {'attr': {'placeholder': form.id.vars.label, 'class':'form-control'}}) }}
                {{ form_widget(form.name, {'attr': {'placeholder': form.name.vars.label, 'class':'form-control' }}) }}
                {{ form_widget(form.status, {'attr': {'class':'form-control'}}) }}
                {{ form_widget(form.search) }}
                {{ form_widget(form._token) }}
                {{ form_errors(form) }}
            {{ form_end(form, {'render_rest': false}) }}

每当用户点击搜索时,就会执行以下 Javascript:

    $("#erpordersearch_search").click(function(e) {
        e.preventDefault();
        var productTypeID = document.querySelector("#erpordersearch_productType").value;
        var ID = document.getElementById("erpordersearch_id").value;
        var name = document.getElementById("erpordersearch_name").value;
        var status = document.getElementById("erpordersearch_status").value;
        var url = window.location.href.substring(0, window.location.href.lastIndexOf("/page"));
        url = url + "/page1";
        window.location.href = url + "[ProductTypeID=" + productTypeID + "&id=" + ID + "&name=" + name + "&status=" + status + "]";
    });

这行得通,但问题是我在 ui 上跟踪用户操作历史,如果系统加载了整个页面,那么我将丢失所有用户操作历史,因为历史保存在Javascript中。我知道我可以将历史记录保存在数据库或 localStorage 中,但在我的情况下,这两者都不是可行的选择,因为它们会违反项目的政策。我被要求进行修改,其中包含以下功能:

关于如何通过 Symfony 和我正在从事的特定项目的组合来实现这一点,我得到了一些模糊的描述,但它不清楚并且包含我无法在此处分享的特定于项目的信息。

所以我的问题是:有没有办法使用 PHP 和 Symfony,在发送请求时更改 URL 并仍然保留在 Javascript 中定义的所有变量?

我认为这是可能的唯一方法(准备更模糊的解释)是将您的 JavaScript 变量存储在按下搜索按钮时提交的不可见表单元素中。

然后这些应该通过 post 数据发送到 Symfony 控制器,然后您可以使用此处概述的方法将变量从 PHP 发送到 JavaScript(但已修改对于树枝语法)- How can I store JavaScript variable output into a PHP variable?

如果在脚本文件中,您可以尝试以这种方式传递参数 - https://www.gun.io/blog/pass-arguments-to-embedded-javascript-tutorial-example


编辑

再次阅读所有内容(并在下面的评论中讨论)后,我想我更好地理解了这个问题。

我个人同意你的看法,这看起来不可能在纯 Symfony 中通过 GET 请求来完成。

即使有 "hacky" 方法,它也不是可扩展的或动态的,因此不值得做。