¿Cómo agrego una condición de acceso a un elemento del menú?

17

¿Cómo puedo agregar nuevas condiciones además de las existentes que determinan si un elemento del menú está visible? Estas condiciones no deben limitarse a la configuración de permisos.

Como ejemplo de caso de uso (no necesariamente el motivo de esta pregunta): supongamos que tengo un tipo de contenido cuyos usuarios solo pueden crear un nodo. Tengo un elemento de menú para agregar ese tipo de contenido. Pero si el usuario ya ha creado un nodo de ese tipo de contenido, quiero ocultar el elemento del menú. Mi primer pensamiento es ejecutar una consulta para verificar la existencia de un nodo creado por el usuario actual que sea del tipo de contenido específico. Si existe, oculte el elemento del menú.

Creo que este tipo de funcionalidad debería entrar hook_menu_alter()y agregar la lógica requerida allí. Pero no estoy seguro de cómo hacerlo sin pasar por alto las verificaciones existentes, como verificar si el usuario tiene permisos para crear ese tipo de contenido. ¿Tendría que incluir esa lógica dentro de mi propia condición? ¿O puedo agregar a la lógica de acceso existente sin sobrescribirla?


Editar: Algunas personas parecen centradas en responder "¿cómo limito a un usuario a crear un nodo de un tipo de contenido". Esa no es la pregunta aquí. La pregunta es cómo agregar condiciones de acceso personalizadas a un elemento del menú.

Chaulky
fuente

Respuestas:

11

Lo que debe hacer es agregar su devolución de llamada a través de hook_menu_alter (), y luego dentro de su devolución de llamada simplemente haga su lógica y luego devuelva los datos a través de la devolución de llamada original.

Para asegurarse de que no sobrescribe ningún otro cambio de hook_menu_alter (), debe pasar la devolución de llamada anterior a su devolución de llamada mediante el argumento de acceso.

Todo esto es teórico, pero el código debería ser algo como esto:

MYMODULE_menu_alter(&$items) {
  $items['menu']['access arguments'] = array_merge(array($items['menu']['access callback']), $item['menu']['access arguments']);
  $items['menu']['access callback'] = 'MYMODULE_access_callback';
}

MYMODULE_access_callback() {
  $args = func_get_args();

  // Do Stuff.
  if ($something == FALSE) {
    return FALSE;
  }

  $function = array_shift($args);
  return call_user_func_array($function, $args);
}
Descifrar
fuente
Entonces, si asigno una nueva función de devolución de llamada de acceso, ¿eso definitivamente sobrescribe la devolución de llamada original?
Chaulky
Sí, solo puede tener una devolución de llamada de acceso por elemento de menú, por lo tanto, asegúrese de pasar de nuevo a la devolución de llamada original. He visto un módulo que hace algo como esto, uno de los módulos pesados ​​de permisos, aunque no recuerdo cuál.
Descifrar el
¿Qué está haciendo el array_shift en $ args?
Chaulky
Extrae el primer argumento de los 'argumentos de acceso', que hicimos con la antigua 'devolución de llamada de acceso'. Entonces, si la antigua devolución de llamada era 'MYMODULE2_access_callback', eso es lo que está devolviendo array_shift. También lo elimina de la matriz para que solo pasemos los argumentos que espera la devolución de llamada.
Descifrar
1

En respuesta a los comentarios anteriores, la solución en D7 sería usar:

/**
 * Implements hook_node_access().
 */
function mymodule_node_access($node, $op, $account) {
  $type = is_string($node) ? $node : $node->type;

  if ($op == 'create' && $type == 'mynodetype' && db_query("SELECT 1 FROM {node} WHERE type = :type AND uid = :uid", array(':type' => $type, ':uid' => $account->uid))->fetchField()) {
    // If the user has already created a node of a specific type, they cannot
    // create any more.
    return NODE_ACCESS_DENY;
  }

  // Otherwise do not affect any node access.
  return NODE_ACCESS_IGNORE;
}
Dave Reid
fuente
1
Esto no parece tener nada que ver con los elementos del menú. Todavía no estoy muy familiarizado con D7, pero parece que esto es específico para la creación de nodos. La pregunta se centra en los elementos del menú en general.
Chaulky
Oh, ya veo ... esto es en respuesta a mi comentario pidiendo más detalles sobre su solución D7 sugerida en su respuesta que apunta al módulo Node Limit. Todavía un poco fuera de tema, pero apreciado.
Chaulky
Debido a que la visibilidad de los enlaces create mynodetype está controlada por la función node_access (), que invocaría este enlace en Drupal 7.
Dave Reid
1

Estás buscando el módulo API de acceso al menú en cadena .

La API de acceso al menú en cadena permite que su módulo encadene sus propias funciones de devolución de llamada de acceso al menú en las entradas del enrutador de menú de otros módulos.

Hay al menos un ejemplo en Drupal Stack Exchange sobre cómo usarlo.

Crantok
fuente
-1

Una opción sería crear un nuevo rol que tenga permiso para crear contenido para su tipo de contenido. Después de que un usuario cree un nodo de ese tipo, elimine ese rol y ya no podrá crear más.

cjworden
fuente
-1

Quizás deberías probar el módulo Node Limit .

Desde la página del proyecto:

El módulo Node Limit permite a los administradores restringir el número de nodos de un tipo específico que pueden crear roles o usuarios. Por ejemplo, si un sitio tiene un rol de "Anunciante" que puede crear nodos de "publicidad", entonces el administrador de límite de nodos puede restringir a todos los usuarios en ese rol a un número específico de nodos. También puede restringir usuarios por usuario.

Dave Reid
fuente
Limitarse a un nodo es solo un ejemplo de caso de uso para agregar un método de devolución de llamada de acceso personalizado. Además, Node Limit no elimina el elemento del menú, solo evita que el usuario agregue otro nodo de ese tipo de contenido.
Chaulky
Eso es cierto ahora que miro nuevamente la descripción del módulo. Si esto fuera en Drupal 7, en realidad sería fácil, ya que puede usar hook_node_access ($ nodo, 'crear', $ cuenta) lo que afectaría la visibilidad del enlace de tipo de nodo de creación en sí.
Dave Reid
Eso es interesante. Planeo mudarme a D7 pronto. ¿te importaría escribirlo con más detalle y publicar una respuesta?
Chaulky
Versión D7 de la respuesta publicada.
Dave Reid