web-dev-qa-db-ja.com

ビューフィールドを表示するときにエンティティアクセスを確認するにはどうすればよいですか?

カスタムエンティティがあります。 hook_entity_info()で定義されたアクセスコールバックがあり、エンティティにアクセスすると呼び出されます。また、レンダリングされたエンティティを表示することを選択したビューでは、ユーザーがエンティティを表示できる場合にのみエンティティが表示されます。

ただし、「レンダリングされたエンティティ」ではなく「フィールド」を表示するようにビューを変更すると、アクセスコールバックが呼び出されなくなり、ユーザーは権限に関係なく、エンティティのすべてのフィールド(およびプロパティ)を表示できます。実行されたクエリを見ると、これは理にかなっており、フィールド値が結合され、エンティティが実際に読み込まれることはありません。

それで、フィールドを表示するとき(Drupal 7)に)ビューのエンティティアクセスをどのように実装する必要がありますか?

hook_field_accessを使用するときにビューでエンティティタイプを確認する方法 が見つかりましたが、結合されたフィールドでのみ機能し、ベースエンティティプロパティでは機能しないと想定しているため、これはソリューションの一部にすぎません。

8
Neograph734

最終的に、ビューがノードで行うのと同じように機能する動作メソッドを見つけることができました。

hook_views_data() (またはhook_views_data_alter())で、必ず_access query tag_テーブルキーを追加します。 node_views_data() でも、ビューがノードに対してこれを行うことがわかります。

_$data['example_table']['table']['base'] = array(
  'field' => 'nid', // This is the identifier field for the view.
  'title' => t('Example table'),
  'help' => t('Example table contains example content and can be related to nodes.'),
  'weight' => -10,

  'access query tag' => 'my_entity_access' // <- Add this.
);
_

次に、独自の _hook_query_TAG_alter_ の実装を追加します。これにより、このタグが追加されているすべてのクエリが変更されます。上記の変更により、これはすべてのビューデータリストに自動的に適用されますが、タグを 手動で追加 にすることもできます。

_node_query_node_access_alter() には、node_query_node_access_alter()(hook_query_TAG_alterのノードモジュール実装)から呼び出されるいくつかの優れたトリックがあります。

_function mymodule_query_my_entity_access_alter(QueryAlterableInterface $query) {
  global $user;

  // Read meta-data from query, if provided.
  if (!$account = $query->getMetaData('account')) {
    $account = $user;
  }
  if (!$op = $query->getMetaData('op')) {
    $op = 'view';
  }

  // From here every query will be different depending on your own needs.
  // Since my entity has a privacy parameter that is either public or private,
  // I chose to implement this as follows:

  // Prepare a database OR.
  $or = db_or();

  // If the user has public view permissions, add it to the OR.
  if (user_access('view public my_entities', $account)) {
    $or->condition('example_table.privacy', 'public');
  }

  // If the user has non-public view permissions, add it to the OR.
  if (user_access('view private my_entities', $account)) {
    $or->condition('example_table.privacy', 'public', '<>');
  }

  // Add the compiled set of rules to the query. 
  $query->condition($or);
}
_
1
Neograph734

エンティティ提供モジュールにビューの統合がすでにセットアップされていると想定し、ページネーションについて心配していません、呼び出すことができます hook_views_pre_render() 結果を反復処理し、ベーステーブルの各エンティティに対してアクセスコールバックを呼び出し、ユーザーがアクセスできないエントリを除外します。

_/**
 * Implements hook_views_pre_render().
 */
function MYMODULE_views_pre_render(&$view) {
  global $user;

  // Iterate over View results for our custom entity
  if ($view->base_table == 'my_entity_base_table') {
    foreach ($view->result as $index => $row) {

      // Presuming eid is the entity PK
      $results = entity_load('my_entity_machine_name', array($row->eid));
      if (!empty($results)) {
        $entity = $results[$row->eid];

        // If the custom access callback returns FALSE, remove from results.
        if (!MYMODULE_my_entity_access_callback('view', $entity, $user)) {
          unset($view->result[$index]);
        }
      }
    }
  }
}
_

ページネーションが気になる場合、それはより難しい問題です。ビューの結果を調整すると、一貫したオフセットが壊れます(たとえば、ページ1は4つの結果を返し、ページ2は10の結果を返す可能性があります)。さらに、SQLクエリの結果は、PHPを実行することによってのみ認識される情報を調整できません。

これらのインスタンスでは、メソッドに合わせて調整する必要があります(例: hook_views_query_alter() アクセスコールバックがDBクエリベースの場合、ビューページャーオプションを変更するなど)。ビューを操作するコールバックにアクセスします。

7
Shawn Conn