You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP Slim 4 + Twig:如何在所有页面加载相同动态数据?

在Slim 4中全局注入动态菜单数据到Twig模板的方案

以下几种方案都能避免在每个控制器重复代码,让header.twig能直接加载菜单数据:

方案1:通过Twig全局变量注入(推荐)

直接把菜单数据注册为Twig全局变量,所有模板无需额外处理就能访问,最适合静态或低动态性的菜单。

  1. 抽离菜单逻辑到服务类
    把HomeController里的菜单查询、分类逻辑单独封装成服务,方便复用:
// src/Service/MenuService.php
namespace App\Service;

use PDO;

class MenuService
{
    private $db;

    public function __construct(PDO $db)
    {
        $this->db = $db;
    }

    public function getMegaMenuData(): array
    {
        // 你的菜单查询逻辑
        $stmt = $this->db->query('SELECT * FROM menu_items ORDER BY parent_id, sort_order');
        $items = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        // 处理成mega menu需要的结构(比如树形、分组)
        return $this->buildMenuStructure($items);
    }

    private function buildMenuStructure(array $items): array
    {
        $structuredMenu = [];
        // 这里写你的菜单分类逻辑
        return $structuredMenu;
    }
}
  1. 在容器中注册服务
    用PHP-DI的话,在容器配置文件里添加:
// config/container.php
return [
    App\Service\MenuService::class => function (\Psr\Container\ContainerInterface $c) {
        return new App\Service\MenuService($c->get(PDO::class));
    },
];
  1. 注册Twig全局变量
    在Twig初始化的地方,把菜单数据注入为全局变量:
// src/Factory/TwigFactory.php
$twig = \Twig\Twig::create($settings['paths'], $settings['options']);

$menuService = $container->get(App\Service\MenuService::class);
$twig->addGlobal('mega_menu', $menuService->getMegaMenuData());

return $twig;
  1. 在header.twig中直接使用
{# templates/partials/header.twig #}
<div class="mega-menu">
    {% for column in mega_menu %}
        <div class="menu-column">
            <h3>{{ column.title }}</h3>
            <ul>
                {% for item in column.items %}
                    <li><a href="{{ item.url }}">{{ item.name }}</a></li>
                {% endfor %}
            </ul>
        </div>
    {% endfor %}
</div>

方案2:用路由中间件全局注入

如果菜单需要根据请求动态调整(比如用户权限、当前路由),用中间件在每个请求前注入数据。

  1. 创建菜单中间件
// src/Middleware/MenuMiddleware.php
namespace App\Middleware;

use App\Service\MenuService;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Views\Twig;

class MenuMiddleware
{
    private $twig;
    private $menuService;

    public function __construct(Twig $twig, MenuService $menuService)
    {
        $this->twig = $twig;
        $this->menuService = $menuService;
    }

    public function process(Request $request, RequestHandler $handler): Response
    {
        // 可以根据request参数调整菜单数据
        $menuData = $this->menuService->getMegaMenuData();
        $this->twig->getEnvironment()->addGlobal('mega_menu', $menuData);
        
        return $handler->handle($request);
    }
}
  1. 绑定中间件到全局或路由组
// src/routes.php
// 全局所有路由都生效
$app->add(App\Middleware\MenuMiddleware::class);

// 或者只给特定路由组绑定
$app->group('/', function ($group) {
    $group->get('', \App\Controller\HomeController::class . ':index');
    $group->get('/about', \App\Controller\AboutController::class . ':index');
})->add(App\Middleware\MenuMiddleware::class);
  1. header.twig中直接使用mega_menu变量即可

方案3:Twig函数延迟加载

如果菜单不是所有页面都需要,用Twig函数实现延迟加载,只有调用时才查询数据。

  1. 注册Twig函数
// 在Twig初始化文件中
$twig->addFunction(new \Twig\TwigFunction('get_mega_menu', function () use ($container) {
    $menuService = $container->get(App\Service\MenuService::class);
    return $menuService->getMegaMenuData();
}));
  1. 在header.twig中调用
{% set mega_menu = get_mega_menu() %}
<div class="mega-menu">
    {% for item in mega_menu %}
        <!-- 渲染逻辑 -->
    {% endfor %}
</div>

额外优化

如果菜单数据很少变动,可以在MenuService的getMegaMenuData方法中加入缓存逻辑(比如文件缓存、Redis),减少数据库查询次数。

内容的提问来源于stack exchange,提问作者cesarcarlos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 09:07:14