大規模な多言語Drupalイントラネットを構築していますが、言語設定の構成に問題があります。
約6つの異なる言語があり、各言語には多くの機密コンテンツがあります。 (国ごとに)約20の異なる役割があり、各役割は1つ以上の言語にアクセスできます。例えば。ドイツのすべての通常のユーザーはドイツ語のコンテンツにのみアクセスできますが、ドイツのマネージャーはドイツ語と英語のコンテンツを切り替えることができます。
現在、私は通常のドイツのユーザーにドイツ語のコンテンツのみを表示させ、通常の英語のユーザーに英語のコンテンツのみを表示させることだけに苦労しています。それはどのように行われますか?
「言語交渉:なし」を選択すると、すべてのユーザーに英語のコンテンツが表示され、言語に依存するものは機能しません。 「言語ネゴシエーション:接頭辞のみ」を選択すると、すべてのユーザーがURLに接頭辞を入力するだけで、すべての異なる言語を切り替えることができます。
独自のアクセスモジュールを作成せずに、探していることを達成することはできますか?
私は週末にこれをなんとか解決しました、誰かが同じ問題を抱えているなら私の解決策を共有したいと思いました。
TL; DR。
私のセットアップでは、contribモジュール Content Access を使用します。基本構成;システムユーザー設定で、匿名ユーザーに対してaccess content
を拒否し、各コンテンツタイプ(admin/content/node-type/[type]/access
)のアクセス制御設定で、認証済みユーザーの表示アクセスを無効にします。このようにして、コンテンツアクセスモジュールは、個々のノードレベルでさえ、どのロールまたはどのユーザーがコンテンツを表示/更新/削除できるかを正確に制御します。
次に [〜#〜] acl [〜#〜] apiを実装した独自のモジュールを作成しました。ノードアクセスシステムを学ぶのは少し難しいですが、ACLモジュールのドキュメントやチュートリアルが完全に不足しているため、なおさらですが、私がそれを理解すると、モジュールは本当にうまく機能します。
モジュールは、ユーザー言語のアクセス許可を決定するために翻訳アクセス(i18n_accessモジュール)を利用します。翻訳アクセスは、編集/削除にアクセス制御を提供しますが、コンテンツの表示には提供しません。もしそうなら、このモジュールは必要なかったでしょう...
それで、最初にデフォルトのパーミッション再構築フォームにカスタム送信ハンドラを追加しました
/**
* Rebuild all permission when using the standard form
*/
function mymodule_form_node_configure_rebuild_confirm_alter(&$form, &$form_state) {
array_unshift($form['#submit'], 'mymodule_rebuild_permissions_submit_handler');
}
/**
* Route submit function through custom handler to get rid of unwanted $form arguments
*/
function mymodule_rebuild_permissions_submit_handler() {
mymodule_rebuild_permissions();
drupal_set_message(t('Language permissions have been rebuilt.'));
}
ここからがおもしろいところです。私は、言語によって制限されたすべてのノード(私の場合はすべてのノード)を反復する「再構築許可」関数を作成しました。 uidが指定されている場合、権限はそのユーザーのみに対して再構築されます。
/**
* Rebuilds permissions for all nodes and users, or only for a specified user
*/
function mymodule_rebuild_permissions($uid = null) {
//Select the nodes to apply language restriction on
$nodes = db_query("SELECT nid, language FROM {node}");
while($node = db_fetch_object($nodes)) {
$acl_id = mymodule_get_node_acl($node);
if(!$uid) {
mymodule_update_user_access_all($acl_id, $node);
} else {
mymodule_update_user_access($acl_id, $node, $uid);
}
}
}
上記のように、ノードのACL IDを取得/作成する関数が必要です
/**
* Gets the node ACL id
*/
function mymodule_get_node_acl($node) {
$module = 'mymodule';
$acl_name = $module.'_'.$node->nid;
//Get the ACL for this node
$acl_id = acl_get_id_by_name($module, $acl_name);
//If it doesn't exist, create new ACL
if(!$acl_id){
$acl_id = acl_create_new_acl($module, $acl_name);
// View = 1, Update = 0, Delete = 0, Priority = 0
acl_node_add_acl($node->nid, $acl_id, 1, 0, 0, 0);
}
return $acl_id;
}
ユーザー権限を更新するためだけでなく
/**
* Update language permissions for all users
*/
function mymodule_update_user_access_all($acl_id, $node) {
$users = db_query("SELECT uid FROM {users} WHERE uid > 1");
while($user = db_fetch_object($users)) {
mymodule_update_user_access($acl_id, $node, $user->uid);
}
}
/**
* Updates language permissions for a specific user
*/
function mymodule_update_user_access($acl_id, $node, $uid) {
//Remove from list
acl_remove_user($acl_id, $uid);
//Add again if user has permissions
if(mymodule_node_access($node, $uid)) {
acl_add_user($acl_id, $uid);
}
}
ユーザーに役割と言語のアクセス権があるかどうかを確認する
function mymodule_node_access($node, $uid) {
//Get the user roles
$user_roles = user_load($uid)->roles;
//Get the content access roles
$node_roles = content_access_get_per_node_settings($node);
//Check if user has permission to view node
$node_access = false;
if(isset($node_roles['view'])) {
foreach($node_roles['view'] as $role) {
if(isset($user_roles[$role])) {
$node_access = true;
}
}
}
//Check i18n selected languages
$perm = db_result(db_query("SELECT perm FROM {i18n_access} WHERE uid = %d", $uid));
$user_languages = $perm ? explode(', ', $perm) : array();
$lang_access = in_array($node->language, $user_languages) || $node->language == '';
//Return true if we have both node and language access
return $node_access && $lang_access;
}
ノードとユーザーを挿入/更新するときは、明らかにアクセス制御を更新する必要があります
/**
* Implementation of hook_nodeapi()
*/
function mymodule_nodeapi(&$node, $op) {
if($op == 'insert' || $op == 'update') {
$acl_id = mymodule_get_node_acl($node);
mymodule_update_user_access_all($acl_id, $node);
if($op == 'insert') {
node_access_rebuild();
}
}
}
/**
* Implementation of hook_user()
*/
function mymodule_user($op, &$edit, &$account) {
if($op == 'after_update') {
mymodule_rebuild_permissions($account->uid);
}
}
最後に、ACL APIを機能させるためにこれらの関数を含める必要がありました
/**
* Implementation of ACL hook hook_enabled()
*/
function mymodule_enabled() {
return !mymodule_disabling();
}
/**
* Implementation of hook_disable().
*/
function mymodule_disable() {
mymodule_disabling(TRUE);
}
/**
* Remembers if we have disabled access.
*/
function mymodule_disabling($set = NULL) {
static $disabling = FALSE;
if (isset($set)) {
$disabling = $set;
}
return $disabling;
}
...以上です!
何よりも前に権限を再構築することを忘れないでください(/admin/content/node-settings
)
まず、Rulesを試してみましょう。多分、i18nとの統合を見つけることができます。
そうでない場合は、カスタムモジュールを記述することが唯一のオプションです。チェック hook_boot 、これを使用してユーザーの言語を確認し、必要な言語でコンテンツを表示できます。
「言語ネゴシエーション:接頭辞のみによる」を選択した場合、hook_init()
を使用して、次の行に沿って何かを実行できる可能性があります。
if "arg(#) equals user's language" {
return // all is good
} else {
if "user's role allows access to that language" {
return // all is good
} else {
drupal_not_found();
}
}
「arg(#)...」と「ユーザーの役割が許可する」ロジックをサイトの詳細に具体化する必要があることは明らかです。