我在尝试刷新消息并将用户重定向回Symfony 2中的上一页时遇到了一个小问题。
我有一个非常简单的CRUD。新建或编辑时,如果相应的创建/更新方法出现问题,我想闪烁一条消息:
-
User --GET--> new
-
new --POST--> create (fails)
-
--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)
这是我的脚本版本,适用于dev
和prod
环境:
$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;
}
}
似乎您需要有一个有效负载才能指向重定向。 对我来说,这似乎是晦涩难懂的概念代码。我还建议您确保配置文件指向正确的重定向代码片段。检查您的服务器访问文件,确保它也启用了重定向。