คุณมีตัวอย่างของ hook_menu () access callback หรือไม่?


18

ฉันได้ดาวน์โหลดโครงการตัวอย่างแล้ว แต่ในโมดูล menu_example ทั้งหมดaccess callbackจะถูกตั้งค่าเป็นtrue.. ยากที่จะเข้าใจวิธีการทำงาน

ในตัวอย่างของฉันรายการ meno ของฉันควรปรากฏบนโหนด แต่เฉพาะสำหรับบทบาทที่มีสิทธิ์ในการแก้ไขโหนดของตนเอง

ฉันไม่สามารถหาตัวอย่างได้จากการโทรกลับเข้าใช้งาน

มีใครบ้างไหม

คำตอบ:


12

แก้ไข: ฉันพลาดส่วนเกี่ยวกับสิทธิ์ "แก้ไขโหนดเอง" เนื่องจากคุณจะต้องไม่เพียงตรวจสอบสิทธิ์ แต่ยังถ้าโหนดนั้นเป็นของผู้ใช้ปัจจุบัน ฉันได้อัปเดตตัวอย่างด้านล่าง แต่ฉันได้ทิ้งคำอธิบายไว้ด้านบนเหมือนเดิม

รายการเมนูของคุณอยู่ใต้ node / nid (เช่น node / 1234 / some)? จากนั้นคุณอาจไม่จำเป็นต้องใช้การเรียกกลับที่กำหนดเอง

หากคุณกำหนดพา ธ เมนูของคุณตามตัวอย่างต่อไปนี้จะเป็นการโทรกลับไปที่การเข้าใช้เท่านั้น

'node/%node/something'

นี่หมายความว่ามันจะเรียก node_load (1234) สำหรับตัวอย่างข้างต้นและดำเนินการต่อเฉพาะถ้าวัตถุโหนดที่ถูกต้องจะถูกส่งกลับ ดังนั้นคุณสามารถกำหนดสิทธิ์ของคุณด้วยอาร์กิวเมนต์การเข้าถึงได้ตามปกติ

ที่กล่าวว่าการเขียนการเรียกกลับเข้าถึงง่ายจริงๆ มันเป็นเพียงฟังก์ชั่นที่จะรับอาร์กิวเมนต์ใด ๆ ก็ตามที่คุณกำหนดไว้ในอาร์กิวเมนต์การเข้าถึง ยกตัวอย่างเช่นการเรียกกลับเข้าถึงเริ่มต้นคือuser_access ()และเมื่อคุณกำหนดข้อโต้แย้งการเข้าถึงของคุณเหมือนมันจะมีผลในการเรียกร้องดังต่อไปนี้:'access arguments' => array('a permission string')user_access('a permission string')

หากคุณมีหลายอาร์กิวเมนต์อาร์กิวเมนต์เหล่านี้จะถูกส่งเป็นอาร์กิวเมนต์ที่สองสามและอื่น ๆ ในฟังก์ชันของคุณ ในการเข้าถึงโหนดที่ใช้งานในปัจจุบันคุณสามารถใช้menu_get_object ()

ดังนั้นคุณสามารถเขียนการเรียกกลับของคุณแบบนี้ได้ แต่อีกครั้งคุณอาจไม่จำเป็นต้องสร้างมันอีก

function yourmodule_access_check() {
  global $user;
  $node = menu_get_object();

  return $node && $node->uid == $user->uid && user_access('edit own ' . $node->type . ' content');
}

แทนที่จะเข้ารหัสสตริงการอนุญาตให้ใช้ hardcoding คุณสามารถส่งเป็นอาร์กิวเมนต์ให้กับฟังก์ชันหรือสิ่งที่คุณต้องการจะทำ


ไม่สามารถรับตัวอย่างล่าสุดได้ด้วย$items['node/%node/edit']['access callback'] = 'admin_access_only'; และ$node = menu_get_object();ในการเรียกกลับ fn $nodeไม่เคยส่งคืนสิ่งใด ฉันใช้แทน$node = node_load(arg(1)); ซึ่งใช้งานได้ ... คำอธิบายเพิ่มเติมยินดีต้อนรับจริงๆ
Kojo

19

Drupal เป็นตัวอย่างของการเขียนโค้ด

ตัวอย่างที่ง่ายขึ้นคือaggregator_menu ()ซึ่งมีรหัสต่อไปนี้

  $items['admin/config/services/aggregator'] = array(
    'title' => 'Feed aggregator', 
    'description' => "Configure which content your site aggregates from other sites, how often it polls them, and how they're categorized.", 
    'page callback' => 'aggregator_admin_overview', 
    'access arguments' => array('administer news feeds'), 
    'weight' => 10, 
    'file' => 'aggregator.admin.inc',
  );
  $items['admin/config/services/aggregator/add/feed'] = array(
    'title' => 'Add feed', 
    'page callback' => 'drupal_get_form', 
    'page arguments' => array('aggregator_form_feed'), 
    'access arguments' => array('administer news feeds'), 
    'type' => MENU_LOCAL_ACTION, 
    'file' => 'aggregator.admin.inc',
  );

ในกรณีนี้การเรียกกลับเป็นค่าเริ่มต้น ( user_access () ) และอาร์กิวเมนต์การเข้าถึงเป็นอาร์เรย์ที่มีสตริงสำหรับสิทธิ์ รหัสไม่สามารถตรวจสอบมากกว่าการอนุญาต หากสิทธิ์ในการตรวจสอบเป็นสองเงื่อนไขหรือเงื่อนไขในการตรวจสอบไม่ได้เป็นเพียงการอนุญาตดังนั้นการเรียกกลับที่เข้าถึงควรเป็นอีกวิธีหนึ่งซึ่งรวมถึงสิทธิ์ที่กำหนดเอง

node_menu ()กำหนดเมนูบางอย่างที่ใช้การเรียกกลับเข้าถึงที่แตกต่างจากค่าเริ่มต้น ฟังก์ชั่นมีรหัสต่อไปนี้

  foreach (node_type_get_types() as $type) {
    $type_url_str = str_replace('_', '-', $type->type);
    $items['node/add/' . $type_url_str] = array(
      'title' => $type->name, 
      'title callback' => 'check_plain', 
      'page callback' => 'node_add', 
      'page arguments' => array($type->type), 
      'access callback' => 'node_access', 
      'access arguments' => array('create', $type->type), 
      'description' => $type->description, 
      'file' => 'node.pages.inc',
    );
  }

ฟังก์ชันที่ถูกกำหนดเป็น access callback ( node_access () ) เป็นฟังก์ชันต่อไปนี้:

function node_access($op, $node, $account = NULL) {
  $rights = &drupal_static(__FUNCTION__, array());

  if (!$node || !in_array($op, array('view', 'update', 'delete', 'create'), TRUE)) {
    // If there was no node to check against, or the $op was not one of the
    // supported ones, we return access denied.
    return FALSE;
  }
  // If no user object is supplied, the access check is for the current user.
  if (empty($account)) {
    $account = $GLOBALS['user'];
  }

  // $node may be either an object or a node type. Since node types cannot be
  // an integer, use either nid or type as the static cache id.

  $cid = is_object($node) ? $node->nid : $node;

  // If we've already checked access for this node, user and op, return from
  // cache.
  if (isset($rights[$account->uid][$cid][$op])) {
    return $rights[$account->uid][$cid][$op];
  }

  if (user_access('bypass node access', $account)) {
    $rights[$account->uid][$cid][$op] = TRUE;
    return TRUE;
  }
  if (!user_access('access content', $account)) {
    $rights[$account->uid][$cid][$op] = FALSE;
    return FALSE;
  }

  // We grant access to the node if both of the following conditions are met:
  // - No modules say to deny access.
  // - At least one module says to grant access.
  // If no module specified either allow or deny, we fall back to the
  // node_access table.
  $access = module_invoke_all('node_access', $node, $op, $account);
  if (in_array(NODE_ACCESS_DENY, $access, TRUE)) {
    $rights[$account->uid][$cid][$op] = FALSE;
    return FALSE;
  }
  elseif (in_array(NODE_ACCESS_ALLOW, $access, TRUE)) {
    $rights[$account->uid][$cid][$op] = TRUE;
    return TRUE;
  }

  // Check if authors can view their own unpublished nodes.
  if ($op == 'view' && !$node->status && user_access('view own unpublished content', $account) && $account->uid == $node->uid && $account->uid != 0) {
    $rights[$account->uid][$cid][$op] = TRUE;
    return TRUE;
  }

  // If the module did not override the access rights, use those set in the
  // node_access table.
  if ($op != 'create' && $node->nid) {
    if (module_implements('node_grants')) {
      $query = db_select('node_access');
      $query->addExpression('1');
      $query->condition('grant_' . $op, 1, '>=');
      $nids = db_or()->condition('nid', $node->nid);
      if ($node->status) {
        $nids->condition('nid', 0);
      }
      $query->condition($nids);
      $query->range(0, 1);

      $grants = db_or();
      foreach (node_access_grants($op, $account) as $realm => $gids) {
        foreach ($gids as $gid) {
          $grants->condition(db_and()
            ->condition('gid', $gid)
            ->condition('realm', $realm)
          );
        }
      }
      if (count($grants) > 0) {
        $query->condition($grants);
      }
      $result =  (bool) $query
        ->execute()
        ->fetchField();
      $rights[$account->uid][$cid][$op] = $result;
      return $result;
    }
    elseif (is_object($node) && $op == 'view' && $node->status) {
      // If no modules implement hook_node_grants(), the default behavior is to
      // allow all users to view published nodes, so reflect that here.
      $rights[$account->uid][$cid][$op] = TRUE;
      return TRUE;
    }
  }

  return FALSE;
}

มีสามจุดสังเกต:

  • อาร์กิวเมนต์ที่ประกาศด้วย "access arguments" จะถูกส่งผ่านไปยังฟังก์ชันในลำดับเดียวกัน ฟังก์ชั่นใช้พารามิเตอร์ที่สามเพราะมันไม่ได้ใช้เพียงโทรกลับเข้าถึง
  • ฟังก์ชันจะส่งคืนTRUEหากผู้ใช้มีการเข้าถึงเมนูและFALSEหากผู้ใช้ไม่สามารถเข้าถึงเมนู
  • การเรียกกลับเข้าถึงสามารถใช้เมื่อเมนูควรแสดงเฉพาะในสถานการณ์ที่เฉพาะเจาะจง

เมื่อประกาศaccess callbackฟังก์ชั่นที่กำหนดเองมันจะต้องปรากฏอยู่ใน.moduleไฟล์ของคุณเพราะ Drupal ไม่สามารถหาได้ในการfileประกาศ (อย่างน้อยสำหรับฉัน)
tyler.frankenstein
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.