雲客Drupal源碼分析之系統管理工具欄toolbar

系統管理工具欄toolbar是指用戶登錄後頁面頂部的黑色條區域,後簡稱工具欄,裏面列出了系統最重要的一些鏈接,默認有:管理、快捷方式、用戶等,點擊這些鏈接後會展開顯示對應的子鏈接。注意這裏並沒有將工具欄裏面的鏈接稱爲菜單,在drupal中菜單有明確的定義(請見本系列後續的菜單系統介紹),默認情況下工具欄用到了菜單,但她本身不是菜單,先明確這一點以便於理解一些概念。

工具欄由兩部分構成:
tab:工具欄裏面的鏈接,可以通過附加類屬性的方式追加顯示圖標
tray:這是可選的,代表點擊tab中的鏈接後展開顯示的對應區域(tab的托盤),裏面可以放置子鏈接或其它內容;如果省略tray,那麼點擊tab後將直接打開其鏈接,否則點擊事件被攔截並展開tray顯示。
模塊可以向工具欄中添加tab和其對應的tray

添加工具欄:
整個管理工具欄是通過鉤子“page_top”添加的,該鉤子在HTML渲染器的以下方法中派發:

\Drupal\Core\Render\MainContent\HtmlRenderer::buildPageTopAndBottom

運行時機在塊系統運行後,她向#type爲html的渲染數組添加子元素page_top,工具欄就位於該子元素中(html渲染數組默認有三個子元素page_top 、page、page_bottom),工具欄由核心模塊toolbar添加,鉤子函數如下:

function toolbar_page_top(array &$page_top) {
  $page_top['toolbar'] = [
    '#type' => 'toolbar',
    '#access' => \Drupal::currentUser()->hasPermission('access toolbar'),
    '#cache' => [
      'keys' => ['toolbar'],
      'contexts' => ['user.permissions'],
    ],
  ];
}

由該鉤子可見,工具欄並不是依據用戶是否登錄來判斷顯示的,只要具備'access toolbar'權限即顯示。

添加工具欄鏈接:
從上面的鉤子可知道管理工具欄由toolbar元素類型的渲染數組產生,所有工作被封裝到該元素類型中,該元素類型類如下:
\Drupal\toolbar\Element\Toolbar
在其中將派發toolbar鉤子及其修改鉤子來構建工具欄,如果模塊需向工具欄添加鏈接可以實現該鉤子,這裏假設模塊名爲yunke,添加菜單的鉤子示例如下:

function yunke_toolbar()
{
    $items['yunke'] = [
        '#type'   => 'toolbar_item',
        'tab'     => [
            '#type'       => 'link',
            '#title'      => "雲客",
            '#url'        => \Drupal\Core\Url::fromRoute('<front>'),
            '#attributes' => [
                'title' => "工具欄頂級鏈接",
                'class' => ['toolbar-icon'], //如需圖標,則在此處補充具體的圖標類
            ],
        ],
        '#weight' => 10000, //菜單排序 越大越靠後
    ];

    // tab如不需要托盤區域,那麼在此處直接返回$items即可,不需要以下內容,
    //此時tab鏈接爲以上'#url'指定的地址,以下構建tray托盤區域
    $items['yunke']['tray'] = [
        '#heading' => '托盤區域', //一個隱藏的內容,用於輔助視障設備
    ];
    //列出以下子鏈接,注意以下將採用links主題鉤子,因此不是以屬性方式傳遞
    $links = [
        'index'     => [
            'title' => "鏈接一",
            'url'   => \Drupal\Core\Url::fromRoute('<front>'),
        ],
        'info'      => [
            'title' => "鏈接二",
            'url'   => \Drupal\Core\Url::fromRoute('<front>'),
        ],
        'resources' => [
            'title' => "鏈接三",
            'url'   => \Drupal\Core\Url::fromRoute('<front>'),
        ],
    ];
    $items['yunke']['tray']['group1']=[
        '#theme' => 'links__toolbar_yunke', //默認將採用links主題鉤子
        '#links' => $links,
        '#attributes' => [
            'class' => ['toolbar-menu'],
        ],
    ];
    $items['yunke']['tray']['group2']=[ //可以根據需要給菜單分組
        '#type' => 'link',
        '#title' => '子菜單組',
        '#url' => \Drupal\Core\Url::fromRoute('<front>'),
    ];
//還可以在$items['yunke']['tray']中追加任意需要顯示的內容
    return $items;

}

以上列子yunke模塊只添加了一個tab,如需多個只需在$items中添加多個子元素即可

調整工具欄:
模塊可以實現toolbar修改鉤子來調整工具欄,如排序、刪除其他模塊的工具欄設置等等,這裏以排序做一個演示,假設模塊名爲yunke:

function yunke_toolbar_alter(&$items)
{
    $items['administration']['#weight']=999;
}

這將使“管理”鏈接排到“用戶”後面,這裏需要注意:如果你想通過該鉤子去調整其他模塊提供的工具欄元素,還需要視情況而定,在使用了延遲構建#lazy_builder或渲染前處理器#pre_render時,有些鏈接可能尚未產生,通常這種情況下需要用到對應模塊自己派發的修改鉤子,比如這裏你並不能調整管理菜單的內容,而需要通過菜單系統來調整。

刪除整個工具欄:
添加整個工具欄是在鉤子“page_top”中,那麼刪除她也可以實現該鉤子,這裏介紹一種方法,假設模塊名爲“yunke_help”,如下:

function yunke_help_page_top(array &$page_top)
{
    $route_name = \Drupal::routeMatch()->getRouteName();
    if ($route_name != "yunke_help.index") {
        return;
    }
    if (isset($page_top["#pre_render"]) && is_array($page_top["#pre_render"])) {
        $page_top["#pre_render"][] = "delete_toolbar";
    } else {
        $page_top["#pre_render"] = ["delete_toolbar"];
    }
}
function delete_toolbar($e)
{
    unset($e['toolbar']);
    return $e;
}

以上方法用到了#pre_render,你可能會想到爲什麼不在page_top鉤子中直接unset變量$page_top['toolbar'],這是因爲我們無法保證各模塊鉤子的執行順序,執行時可能還未產生,且系統也沒有派發對應的page_top修改鉤子。
我們來看一看如下的toolbar修改鉤子是否能實現刪除功能:

function yunke_toolbar_alter(&$items)
{
    $items['#access']=false;
}

這是不行的,因爲該鉤子在工具欄渲染數組的#pre_render中運行,此時權限檢查已經執行過了。但如果改爲以下邏輯將可以實現刪除:

function yunke_toolbar_alter(&$items)
{
    $items = [];
    $items['#cache'] = []; //禁用工具欄渲染數組緩存
}

該方法雖然能夠實現刪除,但不如以上採用#pre_render的方法優雅,且浪費性能。

系統管理菜單:
工具欄中的管理鏈接是真正的菜單,內容由菜單系統提供,工具欄tab由toolbar模塊在toolbar_toolbar()鉤子中添加,關於該內容請閱讀本系列菜單主題。

 

我是雲客,【雲遊天下,做客四方】,聯繫方式見主頁,歡迎轉載,但須註明出處

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章