I'm trying to cache a mega-menu on my website, since it doesn't change often and is resource heavy to compute.
The menu is already an embedded controller, I just want to change it to an ESI. I've put a timestamp on the embedded menu controller, but the timestamp always ticks up on refresh and the profiler doesn't show any changes.
# config/packages/framework.yaml
framework:
esi: true
fragments: { path: /_fragment }
Controller for the menu:
// src/Controller/HeaderController.php
...
#[Cache(smaxage: 60)]
public function menu(ProductRepository $productRepository): Response
{
/**
* @todo: possibly this should be one query and return an array instead of one query for each section?
*/
/** @var Section[] $sections */
$sections = $this->em->getRepository(Section::class)->findBy(['showInMenu' => true], ['rank' => 'ASC']);
foreach ($sections as $section) {
$section->setProductsInMenu($productRepository->getTopRankedProductsInSection($section));
}
$timestamp = time();
$searchForm = $this->createForm(SearchFormType::class, null, ['action' => $this->generateUrl('app_search')]);
return $this->render('header/_menu.html.twig', [
'searchForm' => $searchForm->createView(),
'sections' => $sections,
'timestamp' => $timestamp,
])
->setPublic();
}
Controller for the homepage. This includes the embedded menu controller in the base.html.twig file.
// src/Controller/HomeController.php
class HomeController extends AbstractController
{
#[Route('/', name: 'app_home')]
public function index(EntityManagerInterface $em, BannerRepository $bannerRepository): Response
{
$banners = $bannerRepository->getActiveBanners();
$featuredProducts = $em->getRepository(Product::class)->findBy(['featured' => 1], ['rank' => 'ASC'], 12);
return $this->render('home/index.html.twig', [
'banners' => $banners,
'featuredProducts' => $featuredProducts,
])
->setPublic()
->setMaxAge(120);
}
}
base.html.twig that is included in all pages and includes the menu embedded controller.
<!-- src/templates/base.html.twig -->
...
<body>
{{ render(controller(
'App\\Controller\\HeaderController::account'
)) }}
{{ render_esi(controller(
'App\\Controller\\HeaderController::menu'
)) }}
<div class="body"> {% block body %}{% endblock %}
</div>
{{ render(controller(
'App\\Controller\\FooterController::links'
)) }}
{{ render(controller(
'App\\Controller\\FooterController::information'
)) }}
{{ render(controller(
'App\\Controller\\FooterController::compliance'
)) }}
</body>
...