云客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()钩子中添加,关于该内容请阅读本系列菜单主题。

 

我是云客,【云游天下,做客四方】,联系方式见主页,欢迎转载,但须注明出处

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值