Symfony2:重定向到最后一个路由并闪烁一条消息


Symfony2: Redirecting to last route and flash a message?

我在尝试刷新消息并将用户重定向回Symfony 2中的上一页时遇到了一个小问题。

我有一个非常简单的CRUD。新建或编辑时,如果相应的创建/更新方法出现问题,我想闪烁一条消息:

  1. User --GET--> new
  2. new --POST--> create (fails)
  3. --REDIRECT--> new (with flash message)

我正在执行以下操作:

  $this->container->get('session')->setFlash('error', 'myerror');
  $referer = $this->getRequest()->headers->get('referer');   
  return new RedirectResponse($referer);

但是,它不会重定向到正确的引荐来源!即使引用的值是正确的(例如:http://localhost/demo/2/edit/),它也会重定向到索引。为什么?

这是Naitsirch和Santi代码的替代版本。我意识到一个特征非常适合此功能。还对代码进行了一些优化。我更喜欢返回包括 slug 在内的所有参数,因为在生成路由时可能需要这些参数。

此代码在 PHP 5.4.0 及更高版本上运行。当然,您可以将该特性用于多个控制器。如果将特征放在单独的文件中,请确保在 PSR-0 之后将其命名为与特征相同的名称。

<?php
trait Referer {
    private function getRefererParams() {
        $request = $this->getRequest();
        $referer = $request->headers->get('referer');
        $baseUrl = $request->getBaseUrl();
        $lastPath = substr($referer, strpos($referer, $baseUrl) + strlen($baseUrl));
        return $this->get('router')->getMatcher()->match($lastPath);
    }
}
class MyController extends Controller {
    use Referer;
    public function MyAction() {
        $params = $this->getRefererParams();
        return $this->redirect($this->generateUrl(
            $params['_route'],
            [
                'slug' => $params['slug']
            ]
        ));
    }
}

对于symfony 3.0,flash消息重定向回上一页,这可以在控制器中完成。

           $request->getSession()
                ->getFlashBag()
                ->add('notice', 'success');
            $referer = $request->headers->get('referer');
            return $this->redirect($referer);

来自 Naitsirch 的消息显示在下一个 url 中:https://github.com/symfony/symfony/issues/2951

对于您需要的似乎是一个很好的解决方案:

public function getRefererRoute()
{
    $request = $this->getRequest();
    //look for the referer route
    $referer = $request->headers->get('referer');
    $lastPath = substr($referer, strpos($referer, $request->getBaseUrl()));
    $lastPath = str_replace($request->getBaseUrl(), '', $lastPath);
    $matcher = $this->get('router')->getMatcher();
    $parameters = $matcher->match($lastPath);
    $route = $parameters['_route'];
    return $route;
}

然后使用重定向:

public function yourFunctionAction()
{
    $ruta = $this->getRefererRoute();
    $locale = $request->get('_locale');
    $url = $this->get('router')->generate($ruta, array('_locale' => $locale));
    $this->getRequest()->getSession()->setFlash('notice', "your_message");   
    return $this->redirect($url);
}
这对

我有用:

$this->redirect($request->server->get('HTTP_REFERER'));

我的网站上也有类似的功能。它是多语言的。文章仅存在于单个区域设置中。当用户尝试切换到其他区域设置时,它应该重定向回上一页,并闪烁消息,指出请求的区域设置中不存在该页面/文章。

/en/article/3 -> /fr/article/3 (404) -> Redirect(/en/article/3)

这是我的脚本版本,适用于devprod环境:

$referer = $request->headers->get('referer')
// 'https://your-domain.com' or 'https://your-domain.com/app_dev.php'
$base = $request->getSchemeAndHttpHost() . $request->getBaseUrl();
// '/en/article/3'
$path = preg_replace('/^'. preg_quote($base, '/') .'/', '', $referer);
if ($path === $referer) {
    // nothing was replaced. referer is an external site
} elseif ($path === $request->getPathInfo()) {
    // current page and referer are the same (prevent redirect loop)
} else {
    try {
        // if this will throw an exception then the route doesn't exist
        $this->container->get('router')->match(
            // '/en/hello?foo=bar' -> '/en/hello'
            preg_replace('/'?.*$/', '', $path)
        );
        // '/app_dev.php' . '/en/article/3'
        $redirectUrl = $request->getBaseUrl() . $path;
        return new RedirectResponse($redirectUrl);
    } catch ('Symfony'Component'Routing'Exception'ResourceNotFoundException $e) {}
}

我刚刚设置了一个简单的应用程序,它似乎工作正常。我的 createAction() 看起来像这样:

public function createAction()
{
    $entity  = new Pokemon();
    $request = $this->getRequest();
    $form    = $this->createForm(new PokemonType(), $entity);
    $form->bindRequest($request);
    if ($entity->getName() == "pikachu")
    {
        $this->container->get("session")->setFlash("error", "Pikachu is not allowed");
        $url = $this->getRequest()->headers->get("referer");
        return new RedirectResponse($url);
    }
    if ($form->isValid()) {
        $em = $this->getDoctrine()->getEntityManager();
        $em->persist($entity);
        $em->flush();
        return $this->redirect($this->generateUrl('pokemon_show', array('id' => $entity->getId())));
    }
    return $this->render('BulbasaurBundle:Pokemon:new.html.twig', array(
        'entity' => $entity,
        'form'   => $form->createView()
    ));
}

流程如下:

  • 用户导航到/new
  • 用户输入无效的"皮卡丘"选项
  • 用户点击提交(将帖子发布到/创建)
  • 应用程序拒绝该条目,添加 flash 消息,并重定向回/new
  • 用户看到/new 与闪存消息

要检查的几件事:

  • 您的/demo/{entityId}/edit路线是否真正有效?(即,如果您在浏览器中输入它,它实际上会转到您期望的位置吗?

  • 您是否将不同的重定向/转发链接在一起?我注意到,当我有一个重定向到 URL 的控制器时,我会出现意外(但正确)的行为,而负责该 URL 的控制器也会重定向到其他地方。我已经通过使用转发来解决此问题。

也就是说,如果所有其他方法都失败了,您可以使用控制器的 redirect() 方法来管理重定向:

public function createAction()
{
    ...
    return $this->redirect($this->generateUrl("pokemon_new"));
    ...
}

在这里,将其声明为服务,它会随时随地将引用返回给您。没有特征,没有奇怪的依赖关系。

class Referer
{
    /** @var RequestStack */
    private $requestStack;
    /** @var RouterInterface */
    private $router;
    public function __construct(RequestStack $requestStack, RouterInterface $router)
    {
        $this->requestStack = $requestStack;
        $this->router       = $router;
    }
    public function getReferer() : string
    {
        $request = $this->requestStack->getMasterRequest();
        if (null === $request)
        {
            return '';
        }
        //if you're happy with URI (and most times you are), just return it
        $uri = (string)$request->headers->get('referer');
        //but if you want to return route, here you go
        try
        {
            $routeMatch = $this->router->match($uri);
        }
        catch (ResourceNotFoundException $e)
        {
            return '';
        }
        $route = $routeMatch['_route'];
        return $route;
    }
}

似乎您需要有一个有效负载才能指向重定向。 对我来说,这似乎是晦涩难懂的概念代码。我还建议您确保配置文件指向正确的重定向代码片段。检查您的服务器访问文件,确保它也启用了重定向。