Liferay 7 / DXPで上部の管理ナビゲーションバー(Control menu)の表示を制御したい


対応バージョン

Liferay DXP SP1以降 / Liferay 7 CE

はじめに

プロジェクトの要件で、Liferayの上部に表示される管理ナビゲーションバー(Control Menu)の表示を制御したいという要件は多くある。その場合の対応方法を説明する。

公式ドキュメント:THEME CONTRIBUTORS
公式ドキュメント:CONTEXT CONTRIBUTORS
に対応方法の説明が載っているが、実際のポートレットの作成方法をここに説明する。

前提条件

Liferay workspaceは作成されていて、bladeツール、Theme作成ツール各種はインストールされている前提とする。以下の資料でセットアップ方法は説明している。

テストシナリオとして、Liferayの標準ロール、Administrator権限があるユーザーにのみControl Menuを表示させる、という仕様で実装する。

Template context contributorの作成

$(liferay_workspace)/modulesの下に移動。

そこでControl Menuのバンドルを置換するためのTheme contributerを作成する必要がある。Liferay Developer Studio / IDEの File -> New -> Liferay Module Projectを選択、Project Template Nameでtemplatecontextcontributorを選択。

もしくはコマンドラインで

blade create -t template-context-contributor -p com.liferay.product.navigation.control.menu.theme.contributor -c SampleProductNavigationControlMenu sample-product-navigation-control-menu-theme-contributor

でbladeツールを使ってモジュールプロジェクトを作成する。

SampleProductNavigationControlMenuTemplateContextContributorの作成

Control Menuのベースとなるファイルを開く

ProductNavigationControlMenuTemplateContextContributor.java
vi /liferay-portal/modules/apps/web-experience/product-navigation/product-navigation-control-menu-theme-contributor/src/main/java/com/liferay/product/navigation/control/menu/theme/contributor/internal/ProductNavigationControlMenuTemplateContextContributor.java

以下の部分をSampleProductNavigationControlMenuTemplateContextContributor.javaにコピーする。

    @Override
    public void prepare(
        Map<String, Object> contextObjects, HttpServletRequest request) {

        boolean isShowControlMenu = isShowControlMenu(request);

        contextObjects.put("isShowControlMenu", String.valueOf(isShowControlMenuFlg));
    }

    protected boolean isShowControlMenu(HttpServletRequest request) {
        ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
            WebKeys.THEME_DISPLAY);

        if (themeDisplay.isImpersonated()) {
            return true;
        }

        if (!themeDisplay.isSignedIn()) {
            return false;
        }

        User user = themeDisplay.getUser();

        if (!user.isSetupComplete()) {
            return false;
        }

        return true;
    }

次に、標準ロールのAdministrator権限がある場合にのみ表示を絞る、またその表示条件をTheme側に出力する変数をセットする処理を追加すると、以下のようになる。

    @Override
    public void prepare(
        Map<String, Object> contextObjects, HttpServletRequest request) {

        //Theme側でメニューの表示非表示を判断できるようにするための変数を書き込む。
        boolean isShowControlMenu = isShowControlMenu(request);
        contextObjects.put("isShowControlMenu", String.valueOf(isShowControlMenu));
    }

    protected boolean isShowControlMenu(HttpServletRequest request) {
        ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
            WebKeys.THEME_DISPLAY);

        if(!isAdmin(request)) {
            return false;
        }

        if (themeDisplay.isImpersonated()) {
            return true;
        }

        if (!themeDisplay.isSignedIn()) {
            return false;
        }

        User user = themeDisplay.getUser();

        if (!user.isSetupComplete()) {
            return false;
        }

        return true;
    }

    /**
     * Extra check for test
     * 
     * @param request
     * @return
     */
    protected boolean isAdmin(HttpServletRequest request) {
        ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
                WebKeys.THEME_DISPLAY);
        boolean bRet = false;

        try {

            //管理者権限がある時のみ表示したい。
            //ここでは説明的にわかりやすように、文字列でロールを取得しているが、実プロジェクトではロールIDを使うようにする方がよいかもしれない。
            //(実プロジェクトでは管理者のロール名が変更される可能性もあるので。ロールIDがDB毎に変わる可能性がある場合は、Administratorなどの文字列をキーにする方がいいケースもある。)
            Role adminRole = RoleLocalServiceUtil.getRole(themeDisplay.getCompanyId(), "Administrator");

            List<Role> roles = themeDisplay.getUser().getRoles();

            for(Role role : roles) {
                if(role.getName().equals(adminRole.getName())) {
                    bRet = true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bRet;
    }   

次に、bnd.bndファイルを以下のように変更する。

bnd.bnd
Bundle-SymbolicName: sampleproductnavigationcontrolmenutemplatecontextcontributor
Bundle-Version: 2.0.6
Liferay-Releng-Module-Group-Description:
Liferay-Releng-Module-Group-Title: Product Navigation
Liferay-Theme-Contributor-Type: product-navigation-control-menu
Web-ContextPath: /product-navigation-control-menu-theme-contributor

Bundle-Version、Liferay-Theme-Contributor-Type、Web-ContextPathは現行のDXPに含まれているProductNavigationControlMenuTemplateContextContributor.javaのbnd.bndをコピーする。

これでTheme Contributorの準備ができたので、

blade deploy

でデプロイ、続いてThemeの作成を行う。

Themeの作成

$(liferay_workspace)/themesディレクトリに移動し、Liferay CEのクラシックテーマを持つテーマを作成する。(Liferay 7 / DXPでのテーマの作り方を参照)

以下を変更

init-custom.ftl
<#if isShowControlMenuFlg>
    css_class = css_class?replace("has-control-menu", "")
    css_class = css_class?replace("open", "")
</#if>

のようにCSSのクラスを変更した上で、

portal_normal.ftl
<@liferay.control_menu />

portal_normal.ftl
<#assign isShowControlMenu = htmlUtil.escape(isShowControlMenu!) />
<#if "true" == isShowControlMenu >
    <@liferay.control_menu />
</#if>

に変更、

gulp deploy

でデプロイ。

上記のContributor / Themeをデプロイした場合、Administrator権限をもつユーザーにはControl Menuが表示され、それ以外のユーザーにほ表示されなくなるはず。