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

Twig扩展needs_context为空,如何获取current_page实现导航激活类?

嘿,我来帮你搞定这个needs_context拿不到current_page的问题!其实核心问题大概率是两个点:要么你的Twig扩展没正确配置上下文传递,要么current_page压根没进到Twig的上下文里。下面给你一步步拆解解决方案:

首先,修正Twig扩展的上下文配置

敲黑板!Twig扩展里有两个地方要注意:一个是类的needsContext属性(驼峰命名),另一个是函数定义里的'needs_context' => true选项(下划线命名),这俩都得设置对,不然上下文根本传不进你的activeClass函数里。

修改你的Helper类:

class HelperExtension extends \Twig_Extension
{
    // 开启类级别的上下文需求
    protected $needsContext = true;

    public function getFunctions()
    {
        return [
            new \Twig_SimpleFunction('activeClass', [$this, 'activeClass'], [
                // 函数级别也要明确声明需要上下文
                'needs_context' => true,
            ]),
        ];
    }

    // 第一个参数就是Twig的上下文数组
    public function activeClass($context, $targetPage)
    {
        // 现在就能从上下文里取current_page了
        if (isset($context['current_page']) && $context['current_page'] === $targetPage) {
            return 'active';
        }
        return '';
    }

    public function getName()
    {
        return 'helper_extension';
    }
}

第二步,把current_page注入Twig上下文

现在你得确保current_page确实存在于Twig的上下文里,有两种常用方式:

方式1:全局注入(一劳永逸)

在Slim初始化Twig视图的地方,把当前路由名称作为全局变量注入,这样所有模板都能拿到:

$container['view'] = function ($c) {
    $view = new \Slim\Views\Twig('path/to/your/templates', [
        'cache' => 'path/to/cache/folder', // 可选,生产环境开启
    ]);

    // 加载Slim自带的Twig扩展(处理路由URL用)
    $basePath = rtrim(str_ireplace('index.php', '', $c['request']->getUri()->getBasePath()), '/');
    $view->addExtension(new \Slim\Views\TwigExtension($c['router'], $basePath));

    // 添加你的自定义Helper扩展
    $view->addExtension(new HelperExtension());

    // 把当前路由名称注入为全局变量current_page
    $currentRoute = $c['router']->getCurrentRoute();
    $view->getEnvironment()->addGlobal('current_page', $currentRoute ? $currentRoute->getName() : '');

    return $view;
};

记得给你的路由都设置名称,比如:

$app->get('/foo', function ($request, $response) {
    return $this->view->render($response, 'foo.twig');
})->setName('foo'); // 这里的名称就是你要传给activeClass的参数

方式2:路由渲染时单独传递

如果只需要在特定路由里传递,就在渲染模板时手动传:

$app->get('/foo', function ($request, $response) {
    return $this->view->render($response, 'foo.twig', [
        'current_page' => 'foo',
    ]);
});

进阶方案:不用上下文,直接从Slim容器拿路由

其实你还可以绕开Twig上下文,直接在Helper扩展里注入Slim的Router,这样不用依赖current_page变量,更靠谱:

修改Helper类:

class HelperExtension extends \Twig_Extension
{
    private $router;

    // 构造函数注入Slim的Router实例
    public function __construct(\Slim\Router $router)
    {
        $this->router = $router;
    }

    public function getFunctions()
    {
        return [
            new \Twig_SimpleFunction('activeClass', [$this, 'activeClass']),
        ];
    }

    public function activeClass($targetRouteName)
    {
        $currentRoute = $this->router->getCurrentRoute();
        // 判断当前路由名称是否匹配目标
        if ($currentRoute && $currentRoute->getName() === $targetRouteName) {
            return 'active';
        }
        return '';
    }

    public function getName()
    {
        return 'helper_extension';
    }
}

然后注册扩展时注入Router:

$container['view'] = function ($c) {
    // ... 其他代码
    // 传入容器里的router实例
    $view->addExtension(new HelperExtension($c['router']));
    // ...
};

这种方式下,模板调用还是和之前一样:<a href="{{ path('foo') }}" class="{{ activeClass('foo') }}">Foo</a>,不用管current_page的事了。

最后检查点

  • 确认你的路由都设置了setName(),不然getCurrentRoute()->getName()会返回null
  • 检查Twig扩展的配置,needsContext和'needs_context'两个地方都要正确设置
  • 如果用全局注入,确保在初始化视图时getCurrentRoute()能拿到当前路由(比如不要在中间件之前调用)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 03:37:25