Groupモジュールをちょっと理解する
DrupalのGroupモジュール を解説します。Site Builder、Developer向けです。 今回の解説はver3.0です。1.5系、2.0系は解説しません。
なにができるのか
ユーザごとにNode (コンテンツ) のCRUD制御が可能。
制御の対象は Node のみ!!
補足: 仕組み的にはContent Entity・Config Entity すべてが対象ですが、Node以外を対象としたい場合Contrib モジュールやカスタムモジュールの作成が必要です。
ユーザが所属するグループによってNodeの表示・作成・編集・削除の制御ができる。
制御対象はNodeのみ。他のサードパーティモジュールがあるが今回は触れない。
通常はNodeの作成・編集・削除の制御はContent Type(Node Type)単位でRoleごとのPermissionの付与によって実現されるが、Node単位で制御可能になる。
Nodeの表示制御は基本的にNodeを閲覧できるか、できないかしか選択できない。
どういう時につかうのか
ざっくりいうと会員サイトでユーザの所属によってコンテンツの表示を出しわけしたい時。
ちゃんというとユーザごとにNode表示・操作を厳密に制限したい時。
グループと紐づいたNodeはグループに関係ない操作はAccess Deniedとなる。
Viewsなどの一覧表示もユーザに関係ないNodeは表示されない。
操作性向上のためにコンテンツ制御を加えたいだけならGroupモジュールは重い。
一覧絞り込みのためだけならタクソノミーでカテゴライズする設計で実現したほうがいい。
どういう挙動になるのか
グループに紐づいたNodeは、グループによるアクセス制御が入る。
グループに1つも紐づいていないコンテンツは、通常のロール×パーミッションのアクセス制御になる。
グループと紐づいたNodeはグループに関係ないユーザの操作はすべてAccess Deniedとなる。
ユーザにとってAccess DeniedなコンテンツはViewsの一覧には出てこない。
Node詳細のURLを直にアクセスしても403になる。
何を設定するか
グループタイプを作成
コンテンツタイプを作成するようにグループタイプを作成する。
グループタイプの各種設定
フィールドの設定
コンテンツタイプで設定できるフィールドを同じ。グループに好きなデータ(フィールド)を持てる。
ロール・パーミッションの設定
詳細は後述
対象の許可するEntityを指定
各コンテンツタイプごとのリレーションプラグインを有効にする
https://scrapbox.io/files/64575a39f20241e6cb072b10.png
グループ作成
コンテンツタイプを定義したらコンテンツが作成できるのと同じで、グループタイプを定義したら個々のグループが作成できる。
グループにユーザを紐付け
作成したグループにユーザを紐付けする
グループにコンテンツを紐付け
作成したグループにコンテンツを紐付けする
グループのページからAdd new entity でコンテンツ新規作成と同時にグループ紐付けすることも可能
グループ内のロール・パーミッションを理解する
アクセス制御はグループ内で定義するロールとパーミッションがすべてといっても過言ではない。
Outsider / Insider / Individual を理解する
管理画面より意訳 (カッコ内の英語が実際の説明文)
Outsider: グループ外の特定のロールを持つユーザ (Assigned to all non-members who have the corresponding global role.)
Insider: グループ内の特定のロールを持つユーザ (Assigned to all members who have the corresponding global role.)
Individual: ユーザ個々に適用可能 (Can be assigned to individual members.)
※ global role とは、通常のロールを指す
グループ内外と個別権限設定を用意することが可能。
たとえばAuthenticated user(ログイン中のユーザ)にたいして、以下の定義でアクセス制御を適用できる。
Outsider × Authenticated user ロール で、グループ外の時にどういうアクセス制御とするか
Insider × Authenticated user ロール で、グループ所属時にどういうアクセス制御とするか
Group Admin (Individualで個別定義) で、ロール関係なく個別にアクセス制御をつけるか
https://scrapbox.io/files/64575a3fa00ea8b564df64cf.png
パーミッション
あまりにも量が多いので実物を見た方がいい。ざっくり以下のパーミッションが設定可能。
グループの作成・編集・削除・閲覧
グループに紐づいたコンテンツの作成・編集・削除・閲覧
既存コンテンツをグループに紐づける権限
グループのパーミッション一覧サンプル
https://scrapbox.io/files/64575a5e1e1ba4a3e60f76c3.png
developer向け : Group Relationshipの関連性を理解する
ユーザやNodeとグループの関連は Group Relationship がすべてを握っている。
Group RelationshipがユーザやNode、Groupをそれぞれ参照している。
以下のように Group Relationship が双方(Node・User と Group) の参照を持っている。
Node <--- Group Relationship ---> Group
User <--- Group Relationship ---> Group
table:group_relationship
type entity_id group_id group_type
user 1 1 section
node 1 1 section
node 2 1 section
node 3 2 secsion
※ この表は簡略化している。実態はgroup_relationship_field_data テーブルを見るべし。
上記の場合、ユーザ1はNodeの1と2は同じグループで、Node3が違うグループ。
権限次第だがユーザ1は違うグループに関連づけられたNode3は何もできない。
SQLでグループ制御のデータ取得したい場合はGroup Relationship(group_relationship_field_dataテーブル)を参照することになる。
運用ケース
社内ポータルサイト
概要
ユーザ・コンテンツ・グループを管理する専用ユーザがいる
一般ユーザは自分の所属するグループのコンテンツだけ閲覧できる
カスタマイズ方針
管理ユーザはOutsider, Insiderどちらも強い権限を与えて、一般ユーザはInsiderのときにコンテンツ閲覧の権限のみ与える
グループ関連のページは公開サイトテーマで表示されるため、管理テーマにしたい場合はThemeNegotiatorで調整する
Nodeとグループ、ユーザとグループの一括紐付け機能は無いのでカスタマイズで作成する(ことが多い)
カスタムモジュールでごりごり作る
Feedsを使ってGroup Relationshipを作成する
オンラインサロン的な何か
自分の所属するグループのコンテンツだけ閲覧できる
グループ内に管理者と一般ユーザがいる
加入には管理者の承認がいる
グループの所属には承認が必要
グループ離脱には退会処理が必要
カスタマイズ方針
UI/UXは全部独自作る
Groupモジュール提供のページのカスタマイズは辛いと判断。
グループのデータ構造やアクセス制御はそのまま使い、加入/脱退ページは独自に作成して処理を挟む。
グループの加入だけでは何も権限無しとして(Outsiderと同じ扱いとし)、承認行為はメンバー編集で Individual role を付与するのがいいのでは。
グループのコンテンツ一覧、ユーザ一覧はViewsでできているのでカスタマイズ可能。
Developer向け : Search APIとの連携 注意点
検索や一覧のベースにSearch APIのindexを使用する場合、必ずカスタマイズが必要。
カスタムモジュールでNodeとGroup Relationshipを紐づける必要あり。
Reverse referenced entity でコンテンツとグループの関連性をindexとして持つ
Group Relationship の中でNodeのリレーションだけindexするようにprocessorを用意する
Group Relationshipにはユーザのとリレーションも含まれる、これを除外する
viewsのhookでqueryを書き換える
ユーザが所属するグループのコンテンツだけ取得するand条件を付け加える。
補足:なぜカスタマイズが必要?
Search API + Views の実処理はほとんどSearch APIが担っているから。
管理UIや見た目の機能は普通のViewsと変わらないのはインターフェースが一緒だから。
Search API + Viewsの実態を追いかけるとSearch APIモジュールにあるviews pluginsがガンガン動いている。
Groupモジュールがこれをサポートしていない。多分これからもサポートしないのでは。
Developer向け : Render Cache
あらゆるブロックのRender Cacheがグループに対応していない。
公式ドキュメントにあるようにキャッシュなしになるように調整が必要
routingでno cache にするとか
form rennder array でキャッシュ無効にするとか
preprocess hook でキャッシュを無効にするとか
viewsの設定でキャッシュ無効にするとか
おしまいに
ここまで概要を説明したつもりでこの説明量になる。
Groupモジュールを使いこなすにはSite BuilderとDeveloperがタッグを組んで立ち向かった方がいい。