【问题标题】:Redirect two steps back in Symfony在 Symfony 中重定向两步
【发布时间】:2018-07-24 12:28:18
【问题描述】:

使用 Symfony 4,我有一个路由来编辑一个实体,该实体在提交后将用户重定向到另一个路由,如下所示:

if ($form->isSubmitted() && $form->isValid()) {

        //....

        $em->persist($thisEntity);
        $em->flush();

        return $this->redirectToRoute('this_entity_index');
    }

在通过路由this_entity_index 呈现的实体的index page 上,我显示了用于编辑实体的按钮,因此这种重定向是有意义的。但是,我对此实体有一个不同的show page(通过show_route 呈现),它还包含一个路由到编辑路由的编辑按钮。编辑后,用户将再次被重定向到实体的index page。在这种情况下,我希望发生的事情是在这种情况下必须将用户重定向到show page,所以基本上,我需要让用户退后两步。 如果我使用:

return $this->redirect($request->headers->get('referer'));

用户只需将其发送回编辑表单(后退一步)。也许有一个简单的解决方案可以让用户返回两个步骤?这样,我可以将用户发送回index pageshow page 或用户来自的任何其他页面。我必须使用用户的会话吗?任何建议表示赞赏。

【问题讨论】:

  • 它是否始终是您想要将 abck 重定向到的实体的索引页?
  • 不,恰恰相反。它目前正在重定向到索引路由(我将重命名这是我的问题)。
  • lemme 改写 - 当用户点击后退按钮时,是否总是会转到 show page 页面?
  • 不,这取决于用户从哪里开始。用户可以返回show pageindex page(以及将来更多页面)。
  • 类似 $request->getSession()->set('entity_edit_redirect_route_name',$request->attributes->get('_route'));将为当前路由设置一个会话变量。您可以使用 has 和 get 来检索它。全部在文档中。有几种方法可以实现这一点,具体取决于您的要求。

标签: php symfony symfony4


【解决方案1】:

表单中添加的隐藏输入:

<input type="hidden" name="referer" value="{{app.request.headers.get('referer')}}"/>

if ($form->isSubmitted() && $form->isValid()) {

    //....

    $em->persist($thisEntity);
    $em->flush();

    return $this->redirect($request->request->get('referer'));
}

【讨论】:

  • 哈,原来的解决方案,我喜欢。我编辑的代码中有一些小错误,因为您的代码重定向不是到路由,而是到 URL,并且有错字。谢谢您的意见。
【解决方案2】:

我遇到了同样的问题,我想出了更复杂的解决方案,可以在表单中作为类方法使用。我刚刚创建了一个重定向字段类型,它可以为我处理一些逻辑,并且很容易放入每个表单中。背后的逻辑与 Deniz Aktürk 解决方案中的相同。

<?php

namespace App\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\OptionsResolver\OptionsResolver;

class FieldRedirectType extends AbstractType
{

    /**
     * @var RequestStack
     */
    private $requestStack;

    public function __construct(RequestStack $requestStack)
    {
        $this->requestStack = $requestStack;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'mapped' => false,
        ]);
    }

    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {

        $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) {
            $form = $event->getForm();
            $parentName = $form->getParent()->getName();

            $currentRequest = $this->requestStack->getCurrentRequest();
            $post = $currentRequest->request->get($parentName);

            $redirectUrl = isset($post[$form->getName()]) ? $post[$form->getName()] : '';
            $referer = $currentRequest->headers->get('referer');
            if (empty($redirectUrl) && ! empty($referer)) {
                $redirectUrl = $referer;
            } else if ($redirectUrl == $referer) {
                $redirectUrl = '';
            }

            $config = $form->getParent()->get($form->getName())->getConfig();
            $options = $config->getOptions();

            $form->getParent()->add($form->getName(), HiddenType::class, array_replace($options, [
                'data' => $redirectUrl,
            ]))
            ;
        });
    }

    public function getParent()
    {
        return HiddenType::class;
    }
}

首先,我“扩展”了HiddenType 字段,使其成为基本字段类型。 然后我使用PRE_SET_DATA 事件根据之前的请求或标头为我的隐藏字段设置适当的数据。如果出现验证错误,我需要从之前的请求中获取数据。因为在提交此类表单后,我的推荐人将更改并指向我的编辑/添加表单页面。这就是为什么我第一次需要将我的推荐人保存到隐藏字段中,然后依赖发布的数据,而不是直接推荐人标题。 在该事件中,您无法从 redirect 字段中检索数据,因为尚未设置表单数据。这就是为什么我需要直接从发布请求中获取数据。 SF 通过向响应添加主表单类型键来创建帖子数组。所以对于 user 表单类型,最终的数组是这样的:

array:1 [
  "user" => array:9 [
    "email" => "email"
    "first_name" => "name"
    "last_name" => "lastname"
    "_redirectUrl" => "where_to_redirect_back"
  ]
]

您可以通过$parentName = $form-&gt;getParent()-&gt;getName(); 检索的 user 密钥 现在根据发布的$redirectUrl 和引用者,您可以确定哪个值是正确的。

然后您必须为该字段设置正确的值,但是由于事件的循环,您不能再次使用setData() 方法。 这就是为什么我们必须在父表单中获取字段集的所有初始选项。然后使用data 选项向该字段注入新值。最后将字段添加到父表单中,如果名称已存在,SF 会将其视为替换字段。

最后,您可以按如下方式使用该字段:

$form->add('_redirectUrl', FieldRedirectType::class); // inside controller or in other form type class

$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
    $redirectUrl = $form->get('_redirectUrl')->getData();
    if (empty($redirectUrl)) { // in case of empty value, redirect to some default place
        return $this->redirectToRoute('default_basic_route');
    }
    return $this->redirect($redirectUrl);
}

如果您要填写一个以上的表单,并且最后您希望该用户被重定向到他来自的第一页,它也可以作为 2 (n) 步后退重定向。您必须将前一个 redirectField 中的值传递给 redirectField。首先添加的redirectField应该没有初始值,所以可以从referer header中设置。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-01
    • 2017-07-04
    • 2020-05-09
    • 1970-01-01
    • 2013-09-10
    • 2014-01-19
    • 2015-06-24
    相关资源
    最近更新 更多