web-dev-qa-db-fra.com

Comment vérifier l'accès aux entités lors de l'affichage des champs de vues?

J'ai une entité personnalisée. Il existe un rappel d'accès défini dans hook_entity_info() et il est appelé lorsque j'accède à l'entité. Également dans les vues lorsque je sélectionne pour afficher les entités rendues, l'entité n'est affichée que lorsque l'utilisateur est autorisé à voir l'entité.

Cependant, lorsque je modifie la vue pour afficher les "champs" au lieu des "entités rendues", le rappel d'accès n'est plus appelé et les utilisateurs peuvent voir tous les champs (et propriétés) de l'entité, quelles que soient les autorisations. En regardant la requête exécutée, cela a du sens, les valeurs de champ sont jointes et l'entité n'est jamais vraiment chargée.

Alors, comment doit-on implémenter l'accès aux entités pour les vues lors de l'affichage des champs (dans Drupal 7)?

J'ai trouvé Comment vérifier le type d'entité dans Views lors de l'utilisation de hook_field_access? , mais je suppose que cela ne fonctionne que pour les champs joints et non pour les propriétés de l'entité de base, ce ne serait donc qu'une partie d'une solution .

8
Neograph734

En fin de compte, j'ai réussi à trouver une méthode de travail qui fonctionne de la même manière que les vues avec les nœuds.

Dans hook_views_data() (ou hook_views_data_alter()), assurez-vous d'ajouter la clé de table access query tag. Vous pouvez voir que Views le fait également pour les nœuds dans 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.
);

Ajoutez ensuite votre propre implémentation de hook_query_TAG_alter . Cela modifiera chaque requête dans laquelle cette balise est ajoutée. En raison de notre modification ci-dessus, cela sera automatiquement appliqué à toutes les listes de données de vues, mais la balise peut également être ajoutée manuellement .

_node_query_node_access_alter() contient de très bonnes astuces appelées à partir de node_query_node_access_alter () (implémentation des modules de nœuds de 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

En supposant que votre module fournissant l'entité a une intégration de vues déjà configurée, et vous ne vous inquiétez pas de la pagination , vous pouvez invoquer hook_views_pre_render() pour parcourir les résultats et appeler votre rappel d'accès pour chaque entité de votre table de base et filtrer les entrées auxquelles l'utilisateur n'a pas accès:

/**
 * 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]);
        }
      }
    }
  }
}

Si la pagination est un problème , c'est un problème plus difficile; l'ajustement des résultats de la vue rompt la compensation (par exemple, la page 1 peut renvoyer 4 résultats, la page 2 peut renvoyer 10 résultats). De plus, les résultats de la requête SQL ne peuvent pas s'adapter aux informations qui ne sont connues qu'en exécutant PHP.

Dans ces cas, vous devrez ajuster votre méthode (par exemple hook_views_query_alter() si le rappel d'accès est basé sur une requête DB, en modifiant vos options de pager View, etc.) pour s'adapter à la accès rappel manipulant la vue.

7
Shawn Conn