81. 响应附属处理attachments_processor

在阅读本主题前,你需要先阅读本系列的渲染数组、渲染器、渲染占位符等主题

 

附属物attachments就是渲染数组的#attached部分,这里称为“附属物”而不叫做“附件”,以便和图片、文件等概念相区别,附属物有如下8个类型(以在#attached中的键名列出,如果添加了其他键名将引起错误):

library资源库,保存cssjs、库js设置等,详见本系列资源库详解

drupalSettings在渲染数组中设置的JavaScript 设置数据

html_head HTML <head>部分的标签

html_head_link HTML <head>部分的<link>标签,是html_head的特殊情况

feedRSS 订阅,是html_head_link的特殊情况

http_headerHTTP 响应头和状态码等

placeholders占位内容,严格说来这不算附属物,只是系统将其和附属物在同一个服务中处理

html_response_attachment_placeholders保存四大类别附属物的占位符,见后

 

在系统中对附属物的处理是在派发kernel.response事件阶段:

订阅器服务:html_response.subscriber

类:\Drupal\Core\EventSubscriber\HtmlResponseSubscriber

执行方法:onRespond

优先级:0-0

该订阅器只针对html响应进行处理:

\Drupal\Core\Render\HtmlResponse

只是起到简单的订阅事件作用,全部附属物处理工作在附属物处理器中进行,见下。

 

附属物处理器:

负责在上述订阅器中对HTML响应进行附属物占位符替换处理

服务名:html_response.attachments_processor

类:Drupal\Core\Render\HtmlResponseAttachmentsProcessor

获取方法:\Drupal::service('html_response.attachments_processor');

 

该处理器只针对\Drupal\Core\Render\HtmlResponse响应,这也是系统HTML页面的主要响应,下文针对各类附属物单独讲解。

 

内容占位符placeholders

placeholders严格说来不属于附属物,而是页面内容,往往是不合适缓存的需要动态产生的页面局部内容,需要内容占位的元素(元素即渲染数组)键名只能包含:'#lazy_builder', '#cache', '#create_placeholder','#weight', '#printed',其中'#lazy_builder'指定了一个回调用于产生真实内容的渲染数组,在html字符串中这样的内容先以占位符占位,占位符由渲染占位符产生器(服务idrender_placeholder_generator)产生,格式如下:

<drupal-render-placeholder callback="' . Html::escape($callback) . '" arguments="' . Html::escape($arguments) . '" token="' . Html::escape($token) . '"></drupal-render-placeholder>

 

渲染占位符产生器同时在渲染数组中$elements['#attached']['placeholders']中添加值,其是一个数组,键名为占位符,键值是一个数组,该数组只有两个键名:'#lazy_builder'用于指定返回新渲染数组的回调、'#cache'用于保存缓存源数据

 

对内容占位符的处理就是将响应(html字符串)中的内容占位符替换成真实内容,这一过程在渲染器中执行,真实内容由$elements['#attached']['placeholders']中占位符键名保存的回调产生(来自于渲染数组的'#lazy_builder'),回调会产生新的渲染数组,渲染器对其合并原缓存元数据,并渲染,用渲染结果去替换占位符。

 

该过程往往会产生新的缓存元数据和附属物,因此在附属物处理器中她需要首先处理,首先调用渲染器的$renderer->renderRoot($html)方法进行渲染,在返回后更新响应对象的缓存元数据和附属物,这样就可开始其他的附属物处理了。(读到这里是否感觉对drupal渲染管道有拨云见日的感觉呢,也明白什么叫根渲染了是吧)

 

附属物占位符html_response_attachment_placeholders

保存4个类型(stylesscriptsscripts_bottomhead)附属物的占位符值,其中html_headhtml_head_linkfeed都是head类型,附属物替换就是替换她保存的占位符字符串,该内容是在以下预处理函数中添加的:

template_preprocess_html(&$variables)(位于core\includes\theme.inc

(预处理函数有能力添加缓存元数据和附属物,逻辑位于主题管理器中,详见主题管理器和主题注册中预处理函数一节)。

此外在\Drupal\Core\Render\HtmlResponse中也有补充默认设置,该项值类似如下:

[html_response_attachment_placeholders] => Array
(
[styles]=>
<css-placeholder token="adoAt0nf3KI5PsdTh274WS4ttC5No7Ko6rIYzlf4jt-dg5Qm9EfISwA93gWuIlIZpGGhBkYodQ">
[scripts]=>
<js-placeholder token="adoAt0nf3KI5PsdTh274WS4ttC5No7Ko6rIYzlf4jt-dg5Qm9EfISwA93gWuIlIZpGGhBkYodQ">
[scripts_bottom]=>
<js-bottom-placeholder token="adoAt0nf3KI5PsdTh274WS4ttC5No7Ko6rIYzlf4jt-dg5Qm9EfISwA93gWuIlIZpGGhBkYodQ">
[head]=>
<head-placeholder token="adoAt0nf3KI5PsdTh274WS4ttC5No7Ko6rIYzlf4jt-dg5Qm9EfISwA93gWuIlIZpGGhBkYodQ">
)

 

头部通用标签html_head

html头部标签(位于head区域的标签),来自渲染数组$renderArray['#attached']['html_head'],是由$head元素构成的一个数组,$head的格式如下:

$head = [$element , $name];

$element是单个头部标签的渲染数组,可以省略$element ['#type'] = 'html_tag';,系统会自动补全

$name用于批量渲染头部标签时在$element组成的更大的渲染数组中充当本元素的子元素名,开发者随意指定

我们可以在渲染数组中通过她设置任意头部标签,示例如下:

$renderArray['#attached']['html_head'][] = [
    [
        '#type'       => 'html_tag', //如上所述,可省略该行,系统会自动补充
        '#tag'        => 'meta', //头部标签名
        '#attributes' => [
            'charset' => 'utf-8',
        ],
        '#weight'     => -1000,
    ],
    'system_meta_content_type'
];
$renderArray['#attached']['html_head'][] = [
    [
        '#tag'        => 'meta',
        '#attributes' => [
            'name'    => 'viewport',
            'content' => 'width=device-width, initial-scale=1.0',
        ],
    ],
    'viewport'
];

这将产生以下标签:

<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

 

头部link标签html_head_link

html头部(head区域)的link标签,来自渲染数组$renderArray['#attached']['html_head_link'],是由$link构成的数组,$link格式如下:

$link = [$attributes, $should_add_header];

$attributes是一个属性集数组,构成link标签的属性,键名为属性名,键值为属性值

$should_add_header是一个布尔值,指示该link是否还需要添加到http响应头中,默认值为false

我们可以在渲染数组中通过她设置任意头部link标签,示例如下:

$renderArray['#attached']['html_head_link'][] = [
    [
        'rel'  => 'shortcut icon',
        'href' => '/core/misc/favicon.ico',
        'type' => 'image/vnd.microsoft.icon',
    ],
    false
];

将生成如下一个link标签:

<link rel="shortcut icon" href="/core/misc/favicon.ico" type="image/vnd.microsoft.icon" />

如果上面的$should_add_header指定为true时还会添加如下一条http响应头:

Link: < /core/misc/favicon.ico>; rel="shortcut icon"; type="image/vnd.microsoft.icon"

 

html_head_linkhtml_head的特殊情况

在系统最后$renderArray['#attached']['html_head_link']将被转化为$renderArray['#attached']['html_head']再处理

 

聚合源link标签feed

聚合源(如果你对rss feed还不熟悉,请先搜索),来自渲染数组$renderArray['#attached']['feed'],是由$feed构成的数组,$feed格式如下:

$feed= [$href , $title];

$hreffeed的连接

$title是标题,可选,默认为空字符串,该值应该是翻译后的值

示例如下:

$renderArray['#attached']['feed'][] = [
    'http://www.yunke.com/rss.xml',
    'yunke'
];

html头部区域将产生如下一个link标签:

<link rel="alternate" type="application/rss+xml" title="yunke" href="http://www.yunke.com/rss.xml" />

feedhtml_head_link的一种特殊情况

在系统最后$renderArray['#attached']['feed']将被转化为$renderArray['#attached']['html_head_link']再处理,feed不会产生http响应头

 

响应头http_header

来自渲染数组$renderArray['#attached']['http_header'],是由$ header构成的数组,$ header格式如下:

$ header = [$name , $value , $replace];

$name是响应头的名字

$value是响应头的值

$replace是一个布尔值,true表示替换当前已设置的值,false表示将值追加到当前的值中,不设置默认为false

示例如下:

    $renderArray ['#attached']['http_header'][] = ['X-Test-Teapot-Replace', 'This value gets replaced'];
    $renderArray ['#attached']['http_header'][] = ['X-Test-Teapot-Replace', 'Teapot replaced', TRUE];
    $renderArray ['#attached']['http_header'][] = ['X-Test-Teapot-No-Replace', 'This value is not replaced'];
    $renderArray ['#attached']['http_header'][] = ['X-Test-Teapot-No-Replace', 'This one is added', FALSE];
    $renderArray ['#attached']['http_header'][] = [' status', 404];

 

该选项也可以用于设置状态码或cookie,由于执行时期在系统派发响应事件时,因此优先级较高,如果你想要进行测试,请在控制器中执行以下代码:

        $renderArray=['#markup' => "this is http_header test"];
        $renderArray['#attached']['http_header'][] = ['X-Yunke', 'This is http_header value', FALSE];
        return $renderArray;

可在火狐开发者工具中查看响应头,如下:

X-Yunke: This is http_header value

 

资源解析器:

该块内容较多,用独立主题阐述,请见本系列《资源解析器AssetResolver

 

资源集cssjs渲染器

资源解析器返回的资源是以选项数组表示的,详见本系列资源解析器主题,资源集渲染器主要工作是将该选项数组转换为渲染数组,并调整路径等

css资源集渲染器:

服务名:asset.css.collection_renderer

类:Drupal\Core\Asset\CssCollectionRenderer

js资源集渲染器:

服务名:asset.js.collection_renderer

类:Drupal\Core\Asset\JsCollectionRenderer

 

补充说明:

如果页面是ajax加载,那么以下位置将保存已加载数据:

$ajax_page_state = \Drupal::requestStack()->getCurrentRequest()->get('ajax_page_state');

比如$ajax_page_state['libraries']将保存已经加载的资源库

 

 

 

本书共97小节:

评论 (写第一个评论)