You are here

function tac_fields_field_access in Taxonomy Access Control 6

Implements hook_field_access().

See also

content_access().

File

tac_fields/tac_fields.module, line 113
Allows administrators to control access to individual CCK fields based on the node's taxonomy categories.

Code

function tac_fields_field_access($op, $field, $account, $node = NULL) {
  switch ($op) {
    case 'view':
      $column = 'grant_view';
      break;
    case 'edit':
      $column = 'grant_update';
      break;
    default:
      return TRUE;
      break;
  }
  $fieldname = $field['field_name'];

  // If TAC Fields does not control the field, allow access.
  if (!in_array($fieldname, _tac_fields_controlled_fields())) {
    return TRUE;
  }

  // We can't do anything without a node, because we need the node's terms.
  if (!isset($node)) {
    return TRUE;
  }
  $nid = $node->nid;
  if (!is_numeric($nid)) {
    return TRUE;
  }
  if (is_array($account->roles)) {
    $rids = array_keys($account->roles);
  }
  else {
    $rids[] = 1;
  }

  // Get a list of all terms this node is in, regardless of user's access.
  // Don't use API calls here.
  // Cache.
  static $tids = array();

  // @todo: What's with the mixing of nid and revision id here (and in TAC)?
  if (!isset($tids[$nid])) {
    $tids[$nid] = array();
    $r = db_query('SELECT tid FROM {term_node} WHERE vid = %d', $node->vid);
    while ($row = db_fetch_object($r)) {
      $tids[$nid][] = $row->tid;
    }
  }
  $args = array_merge(array(
    $node->vid,
    $fieldname,
  ), $rids);
  if (!empty($tids[$nid])) {
    $result = db_query("SELECT \n         tadg.rid, \n         BIT_OR(COALESCE(\n           ta." . db_escape_table($column) . ", \n           tad." . db_escape_table($column) . ", \n           tadg." . db_escape_table($column) . "\n           )) AS " . db_escape_table($column) . "\n       FROM {term_node} tn\n       INNER JOIN {term_data} t ON t.tid = tn.tid\n       INNER JOIN {term_field_access_defaults} tadg \n         ON tadg.vid = 0\n       LEFT JOIN {term_field_access_defaults} tad \n         ON tad.vid = t.vid AND tad.rid = tadg.rid AND tad.field = tadg.field\n       LEFT JOIN {term_field_access} ta \n         ON ta.tid = t.tid AND ta.rid = tadg.rid AND ta.field = tadg.field\n       WHERE tn.vid = %d \n         AND tadg.field = '%s'\n         AND tadg.rid IN (" . db_placeholders($rids, 'int') . ")\n       GROUP BY tadg.rid\n       ", $args);
  }
  else {

    // Use the default for nodes with no taxonomy term.
    $result = db_query("SELECT \n         n.nid, \n         tadg.rid AS rid, \n         tadg." . db_escape_table($column) . " \n           AS " . db_escape_table($column) . " \n       FROM {node} n \n       INNER JOIN {term_field_access_defaults} tadg ON tadg.vid = 0 \n       WHERE n.nid = %d \n         AND tadg.field = '%s'\n         AND tadg.rid  IN (" . db_placeholders($rids, 'int') . ")\n       ", $args);
  }

  // Deny access by default for fields we do control.
  $access = 0;

  // Ignore => 0, Allow => 1, Deny => 2 ('10' in binary).
  // With an Allow and no Deny, the value from the BIT_OR will be 1.
  // If a Deny is present, the value will then be 3 ('11' in binary).
  while ($row = db_fetch_array($result)) {

    // If this role allows access to the field, then grant it to the user.
    $access += $row[$column] == 1 ? 1 : 0;
  }
  return (bool) $access;
}