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


8

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

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

では、フィールドを表示するときに(Drupal 7で)ビューのエンティティアクセスをどのように実装すればよいでしょうか。

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


カスタムview_modeの使用を検討しましたか?
Darvanen

@ダーバネンはい、しかし私はシステムが誰にでもできる証拠が必要です。したがって、レンダリングされたエンティティをすべての人が使用するとは想定できません。
Neograph734

@ Neograph734あなたのその実体はノードか何かですか?
mchar

@mcharエンティティAPIモジュールで構築されたカスタムエンティティです。
Neograph734 2016

あなたの問題の解決策はhook_node_grantshook_node_access_recordsの実装であると思います(私が間違っている場合は正しい)が、これらのフックがカスタムエンティティに適用されるかどうかはわかりませんが(おそらくそうです)、少なくともこれがアクセスを制御する最も効率的な方法ですnodesDrupal に関する限り。
mchar

回答:


7

エンティティ提供モジュールにすでにビューの統合が設定されていて、ページ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クエリベースの場合、ビューページャーオプションを変更するなど)。


1
これは間違いなく出発点ですが、ビューページャーを壊します(ページあたり25項目ではなく、場合によっては0です)。ページネーションが計算される前にこれを処理する方法はありますか?
Neograph734 2016

1
ページ付けは既にクエリ内... LIMIT 25 OFFSET 0にあるようです:しかし、クエリにアクセスコールバックを埋め込むことはできません。それはできないのですか?
Neograph734 2016

1
それが言及されていないので、私はそれについてさえ考えませんでした。とにかく、ビューオブジェクトには$query、変更されたカウントを反映するために操作できるページャープロパティのプロパティが含まれています。
Shawn Conn

1
Shawnもしませんでしたが、ソリューションを実装するときにそれに遭遇しました。これはまだ十分に機能しません(アイテムの合計量をクエリが返す量に設定するため、ページあたりのアイテム数(25)より大きくなることはありません)。別のカウントクエリでこれを試して、アイテムの合計数を取得します。
Neograph734 2016

1
申し訳ありませんが、それは私が時間を食いしばっていたときの急な編集でした。私は以前にこの正確な問題を解決したと思っていましたが、そのコードを再検討したところ、ファジーページネーションを使用して問題を解決できました。私はそれに応じて答えを更新しました。
Shawn Conn 2016

1

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

hook_views_data()(またはhook_views_data_alter())、追加してくださいaccess query tagテーブルキーを。Viewsがノードに対しても同様にこれを行うことがわかり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);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.