本篇主题讲解drupal8系统是如何计算页面标题的,标题很重要,尤其对于搜索引擎优化来说,标题权重很高
页面有标题当然是针对请求格式为html而言,在整个执行流程中如果控制器直接返回响应对象,那么标题计算就在控制器中随意进行 流程仅仅停留在Symfony的渲染管道中,如果控制器返回的是渲染数组,那么将派发视图事件,主内容视图订阅器MainContentViewSubscriber将判断请求格式,并启动对应的格式渲染器渲染输出 今天的话题就发生在请求格式为html的HtmlRenderer渲染器中,这个渲染器用到了标题解析器 这就是本主题的内容,下面看看标题是怎么计算出来的:
首先如果控制器返回的渲染数组包含#title子元素,如:$main_content['#title'],那么将原封不动的使用其值,标题计算完成 如果没有包含,则调用标题解析器进行计算,标题解析器服务id为“title_resolver” 类:Drupal\Core\Controller\TitleResolver 构造函数接收控制器解析器:controller_resolver及字符串翻译服务:string_translation
下面看一下标题解析源代码:
public function getTitle(Request $request, Route $route) { $route_title = NULL; // A dynamic title takes priority. Route::getDefault() returns NULL if the // named default is not set. By testing the value directly, we also avoid // trying to use empty values. if ($callback = $route->getDefault('_title_callback')) { $callable = $this->controllerResolver->getControllerFromDefinition($callback); $arguments = $this->controllerResolver->getArguments($request, $callable); $route_title = call_user_func_array($callable, $arguments); } elseif ($title = $route->getDefault('_title')) { $options = array(); if ($context = $route->getDefault('_title_context')) { $options['context'] = $context; } $args = array(); if (($raw_parameters = $request->attributes->get('_raw_variables'))) { foreach ($raw_parameters->all() as $key => $value) { $args['@' . $key] = $value; //@和%表示要进行转义的状态,见下文解释 $args['%' . $key] = $value; } } if ($title_arguments = $route->getDefault('_title_arguments')) { $args = array_merge($args, (array) $title_arguments); } // Fall back to a static string from the route. $route_title = $this->t($title, $args, $options); } return $route_title; }
首先查找路由定义中是否设置有标题回调,设置格式和控制器完全一样,键名为_title_callback,对回调的执行和控制器完全一样 通过标题回调得到的结果不会被翻译,需要翻译需要在回调中进行 如果没有设置回调则查找_title子元素,如果设置了则进行翻译工作(翻译系统介绍请看后续主题 检查是否设置翻译上下文_title_context 此上下文用于翻译过程的消除歧义,比如may 到底翻译成“可以”还是“五月”呢?一般为空 准备翻译参数,将请求中的_raw_variables值放入参数数组,_raw_variables仅包含占位符变量的原始值,不包括路由额外提供的变量 然后检查路由是否提供额外标题参数,如果有则合并入参数数组
然后将标题、参数、上下文传递给翻译系统进行翻译,标题计算工作完成
优先级总结:控制器指定 》标题回调 》路由标题指定
下面给出一个完整冗余的标题路由定义:
yunke.content: path: '/yunkehello' defaults: _controller: '\Drupal\yunke\Controller\HelloController::content' _title_callback: '\Drupal\yunke\Controller\HelloController::getTitle' _title: 'Hello @user ! time:@May' _title_context:'Long month name' _title_arguments: @May: "May" @user: "yunke" requirements: _permission: 'access content'
我是云客,【云游天下,做客四方】欢迎转载,但须注明出处,讨论请加qq群203286137