更改请求,从会话中检索数据

Changing the Request, retrieving data from the Session

场景:

我想让他看到页面/myapp/myentity//list?entity_filter[search]=something&page=2

我正在尝试使过滤器粘附到用户的会话中,这样当用户重新打开 /myapp/myentity/list 时没有任何参数,他会得到最后一次看到的结果,具有相同的过滤器和页码。

我采用了这种方法,但我认为它已被高度弃用,因为我正在修改 $request 对象和 $_GET 超全局(由于直接使用 $_GET 的分页库),尽管它有效.

/**
 * @Route("/myapp/myentity/list",  name="entity_list")
 * @Method({"GET"})
 */
public function myEntityListAction(Request $request) {
    if (0===$request->query->count()) { //querystring is empty
        $prev_query=$request->getSession()->get('my_entity_list', null);
        if ($prev_query) { //is there something in session?
            $_GET=$prev_query;
            $original_request=$request;
            $request=$request->createFromGlobals();
            $request->setSession($original_request->getSession());
        }
    } else { //i have something in my querystring
        $request->getSession()->set('my_entity_list', $request->query->all()); //i store it in session
    }
    //...do the other stuff (form, filters, pagination, etc)
}

我想我会采用另一种方法,将用户重定向到 /myapp/myentity/list?entity_filter[search]=something&page=2(从会话中读取),这样我就不必修改 $_GET$request .

问题来了:我如何安全地编辑 $request 以注入或更改我需要的东西而不进行重定向?我可以通过子请求安全地完成它吗?

您可以使用 Before filter。在侦听器中,检查您的会话,提取保存的路径(或过滤器)并使用类似

的方式重定向(如果需要)
$event->setController(function() use ($redirectUrl) {
    return new RedirectResponse($redirectUrl);
});

您也可以使用 $event->getRequest() 获取请求并根据需要进行更改。

Re-explaining 设置

您无法安全地编辑请求。不应在控制器内部修改请求,因为它是 "last place" 您将使用它的地方(即使您也可以在视图中使用它)。真的不安全。

重定向基于响应,而不是请求。

(Bonus: Something good to let the user reset (or "clear") this information in the session. 我建议你创建一个按钮为此。)

让我们re-explain你的(已经很好的)场景:

  • 第 1 步:
    用户转到 /myapp/myentity/list
    查询中和 session.
    中均无任何内容 列表显示应有的样子
  • 第 2 步:
    用户通过单击 Page 2 提交搜索表单,例如
    表单提交使用户转到
    /myapp/myentity/list?entity_filter[search]=something&page=2
    发出此请求后,控制器将 session 中的查询字符串保存为 "last seen query string",即您已经在使用的 my_entity_list session 参数。
    使用过滤器显示列表
  • 第 3 步:
    用户通过单击徽标返回到 /myapp/myentity/list,例如
    没有任何疑问。但是在 session 中有一些东西。 用户被重定向到 /myapp/myentity/list?{last_query_string}
    然后回到第2步
  • 第 4 步:
    用户点击 "Clear filters" 按钮。
    AJAX 或普通请求,无关紧要:my_entity_list 已被任何控制器从 session 中取消设置。
    将用户重定向到 /myapp/myentity/list.
    返回步骤 1。

现在,代码

您的代码也必须用类似这样的东西重新组织:

/**
 * @Route("/myapp/myentity/list",  name="entity_list")
 * @Method({"GET"})
 */
public function myEntityListAction(Request $request) {

    // First, get query string
    $queryStringArguments = $request->query->all();

    if (0 === count($queryStringArguments)) {
        $lastQueryStringArguments = $request->getSession()->get('my_entity_list', null);

        if ($lastQueryStringArguments) {
            // Just replace the var, don't manipulate the request
            $queryStringArguments = $lastQueryStringArguments;
        }
    }

    // Whatever the var is retrieved from request or session,
    // this will always be saved in session.
    if (count($queryStringArguments)) {
        $request->getSession()->set('my_entity_list', $queryStringArguments); //i store it in session
    }

    //...do the other stuff (form, filters, pagination, etc)
}

最后,最佳实践

在你的情况下,你正在做的事情绝对不安全注射。

您应该验证查询字符串并检索仅您需要的数据

这可以通过 FormType 或简单的手动验证来完成,您应该取消设置所有 undesirable/unused 查询字符串参数 以避免潜在的注入。

使用 $allowedParams = ['page', 'search_query', 'filter_by_id']; 之类的变量或类似的变量非常容易实现,并且会帮助您重置此数组中 not 的所有键(因此不添加他们 session 也不会使用 html/javascript 注入来操纵您的表单)