1. 程式人生 > >雲客Drupal8原始碼分析之響應附屬處理attachments_processor

雲客Drupal8原始碼分析之響應附屬處理attachments_processor

在閱讀本主題前,你需要先閱讀本系列的渲染陣列、渲染器、渲染佔位符等主題

附屬物attachments就是渲染陣列的#attached部分,這裡稱為“附屬物”而不叫做“附件”,以便和圖片、檔案等概念相區別,附屬物有如下8個型別(以在#attached中的鍵名列出,如果添加了其他鍵名將引起錯誤):
library:資源庫,儲存css、js、庫js設定等,詳見本系列資源庫詳解
drupalSettings:在渲染陣列中設定的JavaScript 設定資料
html_head:在 HTML <head>部分的標籤
html_head_link: 在 HTML <head>部分的<link>標籤,是html_head的特殊情況
feed:

RSS 訂閱,是html_head_link的特殊情況
http_header:HTTP 響應頭和狀態碼等
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字串中這樣的內容先以佔位符佔位,佔位符由渲染佔位符產生器(服務id:render_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個型別(styles、scripts、scripts_bottom、head)附屬物的佔位符值,其中html_head、html_head_link、feed都是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_link是html_head的特殊情況
在系統最後$renderArray['#attached']['html_head_link']將被轉化為$renderArray['#attached']['html_head']再處理

聚合源link標籤feed:
聚合源(如果你對rss feed還不熟悉,請先搜尋),來自渲染陣列$renderArray['#attached']['feed'],是由$feed構成的陣列,$feed格式如下:
$feed= [$href , $title];
$href是feed的連線
$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" />
feed是html_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》

資源集css與js渲染器
資源解析器返回的資源是以選項陣列表示的,詳見本系列資源解析器主題,資源集渲染器主要工作是將該選項陣列轉換為渲染陣列,並調整路徑等
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']將儲存已經載入的資源庫

我是雲客,【雲遊天下,做客四方】,微訊號:php-world,歡迎轉載,但須註明出處,討論請加qq群203286137