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
相关产品推荐
相关产品推荐

