Wie füge ich einer Menüoption eine Zugriffsbedingung hinzu?

17

Wie kann ich neue Bedingungen zu vorhandenen Bedingungen hinzufügen, die bestimmen, ob ein Menüelement sichtbar ist? Diese Bedingungen sollten nicht auf Berechtigungseinstellungen beschränkt sein.

Beispiel für einen Anwendungsfall (nicht unbedingt der Grund für diese Frage): Angenommen, ich habe einen Inhaltstyp, für den Benutzer nur einen Knoten erstellen dürfen. Ich habe einen Menüpunkt zum Hinzufügen dieser Art von Inhalten. Wenn der Benutzer jedoch bereits einen Knoten dieses Inhaltstyps erstellt hat, möchte ich den Menüeintrag ausblenden. Mein erster Gedanke ist, eine Abfrage auszuführen, um die Existenz eines Knotens zu überprüfen, der vom aktuellen Benutzer erstellt wurde und der einen bestimmten Inhaltstyp aufweist. Falls vorhanden, verbergen Sie den Menüpunkt.

Ich würde denken, diese Art von Funktionalität sollte dort eingehen hook_menu_alter()und die erforderliche Logik hinzufügen. Ich bin mir jedoch nicht sicher, wie ich das tun soll, ohne die vorhandenen Prüfungen zu umgehen, z. B. zu prüfen, ob der Benutzer Berechtigungen zum Erstellen dieser Art von Inhalten hat. Müsste ich diese Logik in meinen eigenen Zustand einbeziehen? Oder kann ich die vorhandene Zugriffslogik erweitern, ohne sie zu überschreiben?


Bearbeiten: Einige Leute scheinen sich darauf zu konzentrieren, zu antworten, "Wie beschränke ich einen Benutzer auf das Erstellen eines Knotens eines Inhaltstyps". Das ist hier nicht die Frage. Die Frage ist, wie ich einem Menüelement benutzerdefinierte Zugriffsbedingungen hinzufüge.

Chaulky
quelle

Antworten:

11

Sie müssen lediglich Ihren Rückruf über hook_menu_alter () hinzufügen und dann in Ihrem Rückruf einfach Ihre Logik ausführen und dann die Daten über den ursprünglichen Rückruf zurückgeben.

Um sicherzugehen, dass Sie keine anderen hook_menu_alter () -Änderungen überschreiben, sollten Sie den vorherigen Rückruf über das Zugriffsargument an Ihren Rückruf übergeben.

Das ist alles theoretisch, aber der Code sollte ungefähr so ​​lauten:

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);
}
Entziffern
quelle
Wenn ich also eine neue Access-Callback-Funktion vergebe, überschreibt dies definitiv den ursprünglichen Callback?
Chaulky
Ja, Sie können nur einen Zugriffsrückruf pro Menüelement durchführen. Stellen Sie daher sicher, dass Sie zum ursprünglichen Rückruf zurückkehren. Ich habe ein Modul gesehen, das so etwas macht, eines der berechtigungsintensiven Module, kann sich aber nicht erinnern, welches.
entziffern
Was macht array_shift auf $ args?
Chaulky
Es zieht das erste Argument aus den 'Zugriffsargumenten' heraus, die wir als alten 'Zugriffsrückruf' bezeichnet haben. Wenn der alte Rückruf also "MYMODULE2_access_callback" war, gibt array_shift dies zurück. Es wird auch aus dem Array entfernt, sodass nur die vom Rückruf erwarteten Argumente übergeben werden.
entziffern
1

In Reaktion auf die obigen Kommentare würde die Lösung in D7 lauten:

/**
 * 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
quelle
1
Dies scheint nichts mit Menüpunkten zu tun zu haben. Ich bin noch nicht so vertraut mit D7, aber es sieht so aus, als ob dies spezifisch für die Erstellung von Knoten ist. Die Frage konzentriert sich auf Menüpunkte im Allgemeinen.
Chaulky
Oh, ich verstehe ... dies ist eine Antwort auf meinen Kommentar, in dem ich Sie nach weiteren Details zu Ihrer in Ihrer Antwort vorgeschlagenen D7-Lösung frage, die auf das Node-Limit-Modul verweist. Noch ein bisschen abseits des Themas, aber sehr geschätzt.
Chaulky
Da die Sichtbarkeit der Links zum Erstellen von Mynodetypen durch die node_access () -Funktion gesteuert wird, wird dieser Hook in Drupal 7 aufgerufen.
Dave Reid
1

Sie suchen nach dem Chain Menu Access API- Modul.

Mit der Chain Menu Access API kann Ihr Modul seine eigenen Menüzugriffs-Rückruffunktionen in die Menürouter-Einträge anderer Module einbinden.

Es gibt mindestens ein Beispiel für die Verwendung von Drupal Stack Exchange.

Crantok
quelle
-1

Eine Möglichkeit wäre, eine neue Rolle zu erstellen, die über die Berechtigung zum Erstellen von Inhalten für Ihren Inhaltstyp verfügt. Nachdem ein Benutzer einen Knoten dieses Typs erstellt hat, entfernen Sie diese Rolle und er kann keine weiteren erstellen.

cjworden
quelle
-1

Vielleicht sollten Sie das Node Limit- Modul ausprobieren .

Von der Projektseite:

Mit dem Modul "Knotenbegrenzung" können Administratoren die Anzahl der Knoten eines bestimmten Typs einschränken, die Rollen oder Benutzer erstellen können. Wenn eine Site beispielsweise die Rolle "Werbetreibender" hat, mit der "Werbeknoten" erstellt werden können, kann der Administrator für Knotenbegrenzungen alle Benutzer in dieser Rolle auf eine bestimmte Anzahl von Knoten beschränken. Er kann Benutzer auch auf Benutzerbasis einschränken.

Dave Reid
quelle
Die Beschränkung auf einen Knoten ist nur ein Beispiel für das Hinzufügen einer benutzerdefinierten Zugriffsrückrufmethode. Außerdem entfernt die Knotenbegrenzung das Menüelement nicht, sondern verhindert lediglich, dass der Benutzer einen weiteren Knoten dieses Inhaltstyps hinzufügt.
Chaulky
Das stimmt jetzt, wo ich die Modulbeschreibung nochmal durchschaue. Wenn dies auf Drupal 7 der Fall wäre, wäre es tatsächlich einfach, da Sie hook_node_access ($ node, 'create', $ account) verwenden können, was sich auf die Sichtbarkeit der Verknüpfung vom Typ create node auswirkt.
Dave Reid
Das ist interessant. Ich habe vor, bald zu D7 zu wechseln. Würde es Ihnen etwas ausmachen, es genauer zu schreiben und eine Antwort zu schreiben?
Chaulky
D7-Version der Antwort gepostet.
Dave Reid