Wie erhalte ich entity_type und entity_id von einer Entitätsseite?

9

Einige Seiten (Pfade) repräsentieren eine Entität. Zum Beispiel:

  • Die Seiten auf diesen Pfaden stellen eine Knotenentität dar, entity_id (nid) ist XX:
    • / node / xx
    • / node / xx / delete
    • / node / xx / edit
  • Die Seite in diesem Pfad stellt eine Suchserverentität dar (definiert durch das Such-API-Modul). Entity_id (Maschinenname) ist 'apache_solr':
    • / admin / config / search / search_api / server / apache_solr

Wie laden Sie die Basisdaten zu dieser Entität (ID und Typ) ein, wenn der Hook oder die Funktion, in der Sie sich befinden, diese nicht an Sie weitergibt?

Die Standardmethode zum Abrufen der aktuellen Entität ist anscheinend die Verwendung menu_get_object($entity_type,$position_of_id_in_url) . Dies setzt jedoch voraus, dass Sie nur für einen Entitätstyp codieren: Sie müssen den Entitätstyp programmgesteuert angeben, und noch schlimmer, Sie als Mensch müssen die URL-Position der Entitäts-IDs, die diese Entität verwendet, recherchieren und hart codieren .

Das nächste, was ich bisher finden kann, ist, die zugrunde liegende System-URL für die Seite zu erhalten (z. B. substr(request_uri(),strlen($base_path))), dann eine monströse Schalterliste zu schreiben, die auf so etwas wie diesem Vorschlag basiert , zu raten und dann Fälle für jede mögliche Entität, von der Sie glauben, dass eine Site sie jemals haben könnte, hart zu codieren . Aber es muss etwas Besseres geben, oder?

Eine allgemeine Lösung aus dem Kern wäre am besten, aber ich akzeptiere auch eine Antwort, die von gängigen Modulen wie ctools ( Seitenmanager , Kontexte usw.), Entity API , Devel usw. abhängt .

Meine unmittelbare Notwendigkeit besteht darin, Formulare innerhalb hook_field_widget_form()eines Widgets zu bearbeiten , das (mit der entsprechenden Konfiguration und den entsprechenden Modulen) an jeden feldfähigen Entitätstyp angehängt werden kann. Während eine allgemeine Lösung am besten wäre, würde ich auch eine enge Antwort akzeptieren, die nur innerhalb dieser Funktion oder in Formularen funktioniert (Die ID und die Daten, die für den Entitätstyp spezifisch sind, scheinen in $ -Form vergraben zu sein, sind jedoch in einer Entität eingegeben tippspezifisch, so dass es wie ein Henne-Ei-Problem erscheint, wenn man es aus der Form bringt.

------------ BEARBEITEN ------------------

Es scheint, dass einige Leute Schwierigkeiten haben, das einfache allgemeine Problem zu verstehen. Hier ist ein alternativer Anwendungsfall (ein weiteres separates, aber verwandtes Problem, mit dem ich konfrontiert bin). Angenommen, Sie haben eine Ansicht, in der einige Entitäten aufgelistet sind. Diese Ansicht befindet sich als Block / Bereich auf Seiten, die eine Entität darstellen können, z. B. eine Knotenseite oder ein Benutzerprofil (oder beide). Sie haben einen Hook eingerichtet, der die Ansichtsdaten liest und die Ergebnisse durchschaut ( foreach $view->result as...). Angenommen , es ist hook_views_pre_renderDas heißt, Sie haben nur das Objekt $ view. Sie möchten etwas tun (z. B. die Zeile entfernen oder einige Felddaten ändern), wenn die Ansichtsergebniszeile dieselbe Entitäts-ID und denselben Entitätstyp wie die Seite hat. Sie haben die Logik, diese Daten aus den Ansichtsergebnissen zu extrahieren. Sie müssen also nur den Entitätstyp und die Entitäts-ID der generierten Seite nachschlagen, um einen Vergleich durchzuführen. Diese Daten befinden sich irgendwo in Drupal. Wenn dies nicht der Fall wäre, hätte Drupal nicht herausfinden können, dass diese Ansicht geladen werden muss. Wie bekommen Sie es also, wenn es nicht an den Hook oder die Funktion übergeben wird, in der Sie sich befinden?

user56reinstatemonica8
quelle
Was ist eine "Entitätsseite", wie von Paul-M hervorgehoben?
Letharion
Ich meine ein http-bereitgestelltes HTML-Dokument, das in einem Browser (oder "Webseite", vielleicht "Pfad" ist der Drupal-Begriff?) Auf einer Drupal-Site gerendert wird, die [hier die richtige Drupal-Terminologie einfügen] darstellt und sich auf dem Pfad einer Entität befindet . Beispiel: / node / xx 'repräsentiert' eine Knotenentität mit der ID xx, ebenso wie / node / xx / delete / node / xx / edit, / admin / config / search / search_api / server / apache_solr repräsentiert eine durch search_api definierte Suchserverentität Modul mit dem Computernamen 'apache_solr'
user56reinstatemonica8

Antworten:

4

In Drupal Core können Sie dies nicht tun. Das relevante Problem zum Hinzufügen solcher Funktionen ist hier .

Der Kern selbst gibt immer zwei Argumente weiter:

function($entity, $entity_type)
Letharion
quelle
Oh Gott ... eine dieser Drupal-Kerndebatten, die seit mehr als einem Jahr andauert ... Eine kurze Frage, damit dieses Thema relevant ist, muss ich bereits das $ entity-Objekt haben. Wie schlagen Sie vor, dass ich das $ entity-Objekt erhalte? Gibt es einen generischen Weg?
user56reinstatemonica8
1
Wenn es eine Möglichkeit gibt, das $ entity-Objekt zu erhalten, kann ich diesen hässlichen, aber praktikablen Hack aus dieser Debatte verwenden, die Sie mit drupal.org/node/1042822#comment-5134730 verlinkt haben, und das Problem lösen. Aber zuerst brauche ich das $ entity Objekt ...
user56reinstatemonica8
4

Der einfachste Weg, dieses Problem zu lösen, ist die Implementierung hook_entity_load().

function MODULE_entity_load($entities, $entity_type) {
  foreach ($entities as $entity) {
    $entity->entity_type = $entity_type;
  }
}

Dann wird an das von zurückgegebene Objekt menu_get_object()ein entity_type gebunden.

Kai
quelle
4

Ich habe im Modul Token Filter (D7-Version) etwas entdeckt, das so funktioniert :

  // Attempt to fetch the entity that is being viewed via a backtrace to the
  // field_attach_view($entity_type, $entity) function and parameters §if found.
    $backtrace = debug_backtrace();
    foreach ($backtrace as $caller) {
      if ($caller['function'] == 'field_attach_view') {
        $entity_type = $caller['args'][0];
        $entity = $caller['args'][2];
        // do stuff with entity
        break;
      }  
    } 

Ziemlich klug - es findet eine Funktion heraus, die vor dem Aufruf seiner Funktion aufgetreten sein muss und $ entity_type und $ entity enthält ($ entity_id würde auch anstelle von $ entity funktionieren), und schaut durch das Backtrace-Objekt zurück, bis es gefunden wird.

Token Filter ist ein Feldverarbeitungsmodul , daher weiß es, dass seine Funktion nach einem Aufruf von field_attach_view () immer aufgerufen wurde . Ich bin nicht der Meinung, dass es eine gute generische Alternative zu field_attach_view gibt - aber der allgemeine Ansatz scheint zu funktionieren und ein fallspezifischer Kandidat kann immer für einen bestimmten Fall gefunden werden, indem ein Backtrace-Debug-Code (ehemals defekter Link behoben) in den Punkt eingefügt wird in dem Code, in dem Sie die Entität abrufen und sehen müssen, was verfügbar ist (überprüfen Sie dann die Logik und testen Sie, um sicherzustellen, dass sie immer vorhanden ist).

user56reinstatemonica8
quelle
1
Netter Hack, wirklich nützlich
Clive
1
Upvote, nur weil das unglaublich ist. Hacky wie die Hölle, aber erstaunlich.
Tobynew
Downvote aus dem gleichen Grund: Hacky wie die Hölle.
Eric MORAND
1

Folgendes funktioniert für mich, um Entität und Entitätstyp nach Pfad abzurufen:

/**
 * Get the entity and entity-type by path.
 *
 * @param string $path
 *   The path to the entity page.
 * @return array|boolean
 *   Contains the entity and the entity-type or false if entity or type could
 *   not be determinded.
 */
function custom_module_get_entity_and_entity_type_by_path($path) {
  $item = menu_get_item($_GET['internal_path']);
  if (empty($item['access']) || empty($item['page_arguments'][0]) || empty($item['load_functions'])) {
    return FALSE;
  }

  $entity = $item['page_arguments'][0];

  // Get entity-type.
  $load_function = reset($item['load_functions']);
  $entity_types = entity_get_info();
  dpm($entity_types);
  $entity_type = '';
  foreach ($entity_types as $type => $type_definition) {
    if ($load_function == $type_definition['load hook']) {
      // When the load_function from menu_get_item matches "load hook" of the
      // entity type definition, then the entity_type was found.
      $entity_type = $type;
      break;
    }
  }
  if (!$entity_type) {
    return FALSE;
  }

  return array('entity' => $entity, 'entity_type' => $entity_type);
}
LarS
quelle
0

kann das helfen?

function entity_by_path($path) {
    $router_item = menu_get_item($path);

    $ent_sug_array = array();
    foreach ($router_item['map'] as $key => $value) {
        if(is_object($value) && isset($value->type)) {
           $ent_sug_array[$key] =  $value;
        }
    }

    $ent_sug = false;
    if(count($ent_sug_array) > 1) {
        $lf_sug = false;
        if(isset($router_item['load_functions'])) {
            if(count($router_item['load_functions']) == 1) {
                reset($router_item['load_functions']);
                $lf_sug = key($router_item['load_functions']);
            }
        }
        if($lf_sug !== false) {
            $ent_sug = is_object($router_item['map'][$lg_sug] && isset($router_item['map'][$lg_sug]->type)) ? $router_item['map'][$lg_sug] : $ent_sug;
        }
    } elseif(count($ent_sug_array) == 1) {
        $ent_sug = reset($ent_sug_array);
    }

    if(!empty($ent_sug)) {
        $bundle = $ent_sug->type;
        $ent_type = method_exists($ent_sug, 'entityType') ? $ent_sug->entityType() : false; //eck case
        if(empty($ent_type)) {
            $aclass = get_class($ent_sug);
            if($aclass == 'stdClass') {
                //node, user, core entity case
                if(isset($router_item['load_functions'])) {
                    $lf = reset($router_item['load_functions']);
                    $ei = entity_get_info();
                    foreach ($ei as $key => $value) {
                        if(empty('load hook'))
                            continue;
                        if($lf == $value['load hook']) {
                            $ent_type = $key;
                            break;
                        }
                    }
                }
            }else{
                //custom entity case
                $ent_type = $aclass;
            }
        }

        return array('entity'=>$ent_sug, 'type'=>$ent_type, 'bundle'=>$bundle);
    }

    return false;
}
Mykola Mykolayovich Dolynskyi
quelle
1
Ihre Funktion schien kompliziert zu sein und fehlende Dokumentation und nicht selbsterklärende Variablen helfen nicht viel, sie besser zu verstehen. Nachdem ich auch mit menu_get_item () eine Lösung gefunden hatte, sah ich, dass sie irgendwie auch in Ihrem Code enthalten ist - siehe Antwort mit function custom_module_get_entity_and_entity_type_by_path(). Ich frage mich, in welchen Fällen meine Lösung nicht funktioniert, da Sie viel mehr tun, um den entity_type zu finden.
LarS
Eigentlich erinnere ich mich noch nicht daran, was mit deiner Funktion nicht stimmte, aber auf jeden Fall habe ich es ausprobiert, bevor ich meine geschrieben habe. In meinem Fall brauchte ich ein Bündel von Entitäten, einen Entitätstyp und einen Entitätsschlüsselwert, um das Thema des Druckmoduls zu verarbeiten, wobei benutzerdefinierte Vorlagen für benutzerdefinierte Entitäten wie diese verwendet wurden. $ Variabl ['theme_hook_suggestions'] [] = "print __ {$ Format} __ {$ ent ['type']} __ {$ ent ['bundle']} __ {$ nid} ";
Mykola Mykolayovich Dolynskyi
1
An meiner Funktion war nichts falsch, da sie nicht vorhanden war. Ich habe sie vor einer Woche veröffentlicht. Jetzt verstehe ich, dass Sie auch den Bundle-Namen benötigen, vielleicht ist das der Grund, warum es komplizierter ist.
LarS
:-D In der Tat vor einer Woche. Wie auch immer, ich habe andere Lösungen ausprobiert, bevor ich meine eigenen geschrieben habe. Ja, Bundle, Entitäts-ID, Entitätstyp sind in meinem Fall erforderlich, um die richtige benutzerdefinierte Vorlage für die Enity-Seite über $
suggest
-1

Die eigentliche Antwort auf diese Frage hängt davon ab, warum Sie die Daten benötigen und auf welcher Ebene des API-Schichtkuchens Sie arbeiten.

Wenn Sie die Entität für eine Seite möchten , können Sie dies nicht tun. Eine bestimmte Seite kann viele Entitäten enthalten. (Jeder Knoten, Kommentar, Taxonomie ... sind alle Entitäten.)

Wenn Sie verwenden hook_field_widget_form(), implementieren Sie ein Feld in der Feld-API. Ihre Antwort finden Sie in der Dokumentation : Der Entitätstyp lautet $element['#entity_type'], und Sie können die Entitäts-ID nicht abrufen, da Felder, die die API implementieren, sich nicht selbst betreffen sollten damit.

Also: Warum brauchen Sie die Entitäts-ID?

paul-m
quelle
Vielen Dank für den Tipp zu $ ​​element, und es ist eine schöne Überraschung, eine Dokumentenseite zu sehen, auf der die Schlüssel eines der Parameter aufgelistet sind. Ich hatte angenommen, wenn der Entitätstyp, für den das Formular bestimmt ist, nicht in $ form oder $ instance vorliegt, würde er sich nicht in einem Element einer Instanz in einem Formular befinden. Natürlich meine ich eine Seite im allgemeinen Sinne eines http-gelieferten HTML-Dokuments in einem Browser, nicht ein Drupal-Knotenpaket, das offensichtlich ein Knoten wäre. Ich benötige die Entitäts-ID für ein Widget, das sich mit Beziehungen aus dem Beziehungsmodul befasst und herausfinden muss, welcher Endpunkt in einer Beziehung "diese" Entität ist. Oder allgemeiner ...
user56reinstatemonica8
... eine Funktion, die beim Rendern einer 'Seite' aufgerufen werden kann, die nur eine Entität darstellt, Daten ausgibt, die auf Entitäten verweisen, und die die verarbeiteten Daten mit Daten in der Entität der 'Seite' vergleichen muss ist aufzudrucken.
user56reinstatemonica8
Ah, wenn mit " Seite " die Seite " Seitenmanager " gemeint ist, die viele Entitäten in verschiedenen Bedienfeldern enthalten kann, habe ich nur die Seiten auf dem Pfad einer bestimmten Entität im Auge behalten . Diese könnten eine beliebige Anzahl von Entitäten laden, würden aber immer noch die eine Entität darstellen, auf der sie sich befinden.
user56reinstatemonica8
Ich würde wetten, dass das Beziehungsmodul bereits das schwere Heben für Sie erledigt
paul-m
Ich verwende das Beziehungsmodul, wie in meinem ersten Kommentar angegeben, und es gibt mir alle Daten, die ich über die Beziehung benötige. Dieser Teil ist in Ordnung, es ist nicht mein Problem. Ich möchte nur die Entität nachschlagen, die dieser Pfad darstellt und für die dieses Formularobjekt, Feld und Widget bestimmt sind, damit ich Daten über die Entität mit den Daten vergleichen kann, die ich über die Beziehung habe. Drupal hat den uri-Abfragepfad bereits analysiert und daraus einen Entitätstyp und eine Entitäts-ID identifiziert. Daher würde ich erwarten, dass es eine triviale Aufgabe ist, dies nur nachzuschlagen. Es scheint jedoch, dass es keinen generischen Weg gibt, dies zu tun.
user56reinstatemonica8