如何让varnish将动态菜单缓存到不同的状态?
我当前的项目(基于Symfony 2.8)使用KnpMenuBundle
和varnish来缓存页面。它还使用ESI
来禁用某些页面上的一个特定元素的缓存。其中包括菜单。但由于这不是一个变化很大的元素,我想知道是否可以缓存菜单的不同状态并将相关状态传递给当前调用菜单的页面。
涉及的主要文件如下:
main.html.twig
{{ render_esi(controller('AppBundle:Menu:mainESI')) }}
的appbundle \控制器\ MenuController.php
public function mainESIAction($path = null)
{
return $this->render('menu/main_menu_esi.html.twig', [
'path' => $path
]);
}
菜单/ main_menu_esi.html.twig
{{ knp_menu_render('main-menu', {'template':'menu/main_menu.html.twig'}) }}
答案 0 :(得分:2)
我对Symfony知之甚少,但总的来说,如果你能从cookies中获得所需的状态,你可以试试这个场景:
在recv()中:
in hash():
在miss / pass(3.x)或backend_fetch(4.x)中:
我使用这个场景非常成功。 ESI包含的片段现在可完全缓存,并为每个唯一的cookie值提供不同的版本。
答案 1 :(得分:1)
你不能。
对于Varnish,url将是相同的,因此它将呈现相同的。
在外面应用您的逻辑并在路线中添加参数:
{% if is_granted('ROLE_ADMIN') %}
{% set menu_mode = 'admin' %}
{% else %}
{% set menu_mode = 'normal' %}
{% endif %}
{{ render_ssi(controller('AppBundle:Menu:mainESI',{'menu_mode':menu_mode})) }}
答案 2 :(得分:1)
毕竟这是可能的。我需要的解决方案如下:
的appbundle /资源/视图/ base.html.twig
{{ render_esi(controller('AppBundle:Menu:mainESI', { 'currentPath': currentPath })) }}
的appbundle /控制器/ MenuAdminController.php
public function mainESIAction($currentPath = null)
{
return $this->render('menu/main_menu_esi.html.twig', [
'currentPath' => $currentPath,
]);
}
的appbundle /匹配器/选民/ PathVoter.php
<?php
namespace AppBundle\Matcher\Voter;
use Knp\Menu\ItemInterface;
use Knp\Menu\Matcher\Voter\VoterInterface;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* Class PathVoter
*/
class PathVoter implements VoterInterface
{
protected $uri;
/**
* @param RequestStack $requestStack
*/
public function setRequest(RequestStack $requestStack)
{
if (($request = $requestStack->getCurrentRequest())) {
$pathInfo = $request->getPathInfo();
$requestUri = $request->getRequestUri();
if (!empty($pathInfo) && '/_fragment' === $pathInfo && !empty($request->attributes->get('currentPath'))) {
$this->uri = $request->attributes->get('currentPath');
} else {
$this->uri = $pathInfo;
}
}
}
/**
* @param ItemInterface $item
* @return bool|void
*/
public function matchItem(ItemInterface $item)
{
$uri = $item->getUri();
if ((null === $this->uri) || (null === $uri)) {
return;
}
if ($item->getUri() === $this->uri) {
return true;
}
return;
}
}
的appbundle /资源/配置/ services.yml
parameters:
app.menu.voter.class: AppBundle\MenuBundle\Matcher\Voter\PathVoter
services:
app.menu.voter:
class: %app.menu.voter.class%
calls:
- [setRequest, [@request_stack]]
tags:
- { name: knp_menu.voter }