In den Feldformatierer eines anderen Moduls einbinden?

9

Ich versuche derzeit, auf meiner Drupal 7-Site ein knotenreferenziertes Bildfeld zu implementieren, das den Ansichtsmodus abhängig von der programmatischen Logik unmittelbar vor dem Rendern ändert. Das Feld wird derzeit für eine Reihe von Inhaltstypen über ihre Einstellungen für den Anzeigemodus gerendert, von denen jeder den Feldformatierer 'Gerenderter Knoten' verwendet.

erster Versuch

Meine erste Idee war, Folgendes zu implementieren, wenn man bedenkt, dass ein Haken ein Haken ist:

function HOOK_field_formatter_view( $entity_type, $entity, $field ... ){
  switch ($display['type']) {
    case 'node_reference_node':
      /* Programatical logic here to modfy field render settings */
    break;
  }
}

Offensichtlich tausche HOOK gegen den Namen meines Moduls.

Es ist auch nicht wichtig , ob das oben vor oder nach der ursprünglichen Funktion feuern würde node_reference_field_formatter_viewin , node_reference.moduleweil ich entweder Ausgang den es außer Kraft setzen würde ganz oder hoffentlich ändert ihre Werte vor dem Rendern. Das einzige Problem ist, dass der obige Hook nur auf Modulbasis zu funktionieren scheint - dh er ist nicht standortweit, sodass er für mein Modul im Grunde nicht ausgelöst wird.

Jetzt kann ich natürlich meinen eigenen Feldformatierer schreiben, um einen gerenderten Knoten auszugeben. Aber es scheint eine Verschwendung zu sein, wenn man bedenkt, dass es bereits eine gibt.

andere Ansätze

Meine anderen Ansätze waren HOOK_preprocess_nodeund, HOOK_preprocess_fieldaber die ersteren enthalten keine view_modeInformationen, und die letzteren enthalten mindestens 5 verschiedene komplizierte Strukturen, die alle Verweise auf eine view_modeEigenschaft auf verschiedenen Ebenen haben - und es fühlt sich ziemlich hackig an, jede von ihnen modifizieren zu müssen Werte. Selbst wenn ich bestimmte view_modeEigenschaften geändert habe, ändert sich das resultierende Bild nicht.

Frage

Kennt jemand eine saubere Möglichkeit, vor dem Rendern eines Feldformatierers (eines Contrib-Moduls) einzugreifen und seine Einstellungen auf Seitenbasis zu ändern - dh indem die Einstellungen für den permanenten Ansichtsmodus des tatsächlichen Inhaltstyps nicht geändert werden müssen?

Pebbl
quelle
2
Ich habe hook_field_formatter_view_alter()wahrscheinlich seit über einem Jahr nach einem oder ähnlichem gesucht , es existiert leider nicht. Zu Ihrer hook_preprocess_node()Information , es view_modesteht definitiv zur Verfügung, es ist in $vars['view_mode'], nicht $vars['node']->view_modedas , was Sie versucht haben könnten, es zu versuchen.
Clive
@Clive Dank für die Info, ach ja , und für den Hinweis auf den view_modeauf hook_preprocess_node, dumm ich! Ich frage mich, ob so etwas hook_field_formatter_view_alter()in D8 existiert ...
Pebbl
Ich habe noch nichts gesehen ... aber dann wird in D8 alles in Plugins konvertiert (ich bin mir bei Feldern nicht sicher). Es kann also sein, dass Sie eine vorhandene Klasse einfach überschreiben können, um die Arbeit zu erledigen. Das wäre ideal . Hier ist die Hoffnung!
Clive
1
@Clive, hast du deinen magischen Alter Hook gefunden, der hier für D7 erwähnt wurde?
tyler.frankenstein

Antworten:

11

In der Frage wird erwähnt, dass hook_field_formatter_view()nur das Ursprungsmodul aufgerufen wird, Sie jedoch den Besitz des Feldformatierers über übernehmen können hook_field_formatter_info_alter().

Sie sollten in der Lage sein, den moduleSchlüssel des Formatierers auf MYMODULE zu setzen, wie:

function MYMODULE_field_formatter_info_alter(&$info) {
  $info['some_field_formatter']['module'] = 'MYMODULE';
}

Anschließend können Sie MYMODULE_field_formatter_view()das vorhandene Modul implementieren , das es verarbeitet hat, um ein zu änderndes Element zu erhalten.

function MYMODULE_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  // Your custom logic
  $element = OTHER_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display);
  // Any alterations
}
Graham C.
quelle
Können Sie Ihre Antwort näher erläutern? Code bereitstellen?
Scott Joudry
Eine gute Lösung, ich denke fast nie daran, das Geschäft eines anderen Moduls vollständig in Besitz zu nehmen (und nach Änderungen weiterzuleiten) ... habe es nur ausprobiert und am Ende habe ich viel einfacheren Code. Prost!
Pebbl
1
@ScottJoudry ~ ist möglicherweise erwähnenswert, dass Sie, wenn Sie auf diese Weise übernehmen, sicherstellen müssen, dass Sie über Methoden für alle field_formatterFunktionen von node_reference verfügen, dh MYMODULE_field_formatter_settings_summaryund MYMODULE_field_formatter_settings_form(auch wenn es sich nur um Proxy-Funktionen handelt, die zum ursprünglichen Modul zurückkehren), andernfalls über das Back- Die Benutzeroberfläche wird in allen Anzeigemodus-Panels unterbrochen, als versucht wurde, diese Methoden im falschen Modul zu finden.
Pebbl
Der Ansatz von Graham C ist interessant, erfordert jedoch zu viele Überschreibungen.
Milkovsky
2

Ok, also wurde mir klar, warum meine Änderungen an #view_modebeiden vorgenommen wurden hook_preprocess_nodeund hook_preprocess_fieldsnicht funktionierten. (Danke an Clive für den Hinweis, dass ich die Anwesenheit von #view_modein total vermisst habe hook_preprocess_node) .

Mein Problem ergab sich aus der Tatsache, dass #view_modees bereits verarbeitet und in die richtige #image_styleEigenschaft umgewandelt worden war - etwas, nach dem ich nicht gesucht hatte.

Trotzdem scheint das Ändern dieses Werts zu stark davon abhängig zu sein, in welchem ​​Hook Sie ihn geändert haben. Endlich funktioniert jedoch Code, der das gerenderte Bild tatsächlich ändert:

function HOOK_preprocess_field( &$vars ){
  $element     = &$vars['element'];
  $entity_type = !empty($element['#entity_type']) ? $element['#entity_type'] : 'unknown';
  $bundle      = !empty($element['#bundle'])      ? $element['#bundle']      : 'unknown';
  $view_mode   = !empty($element['#view_mode'])   ? $element['#view_mode']   : 'unknown';
  $field_name  = !empty($element['#field_name'])  ? $element['#field_name']  : 'unknown';
  switch ( "$entity_type:$view_mode:$bundle/$field_name" ) {
    case 'node:full:mlandingpage/field_lead_image':
      if ( !empty($vars['items']) && 
           ($subelement = &$vars['items'][0]) ) {
        if ( !empty($subelement['field_image']) && 
             ($subfield = &$subelement['field_image'][0]) ) {
          /// this needs to be set to the image_style value, not the view_mode value.
          $subfield['#image_style'] = 'grid-normal-4-cols';
        }
      }
    break;
  }
}

Das obige fühlt sich immer noch nicht sehr eloquent an, aber es funktioniert zumindest. Ich nehme Clives Wort auf die Tatsache, dass es eine solche _alter-Methode für Feldformatierer nicht gibt - es ist eine Schande, dass Formatierer ein äußerst leistungsfähiges Merkmal von D7 sind. Es wäre schön, mehr Erweiterungsmöglichkeiten zu haben.

Wie auch immer, wenn zukünftige Leute bessere Ideen haben, antworte :)

Pebbl
quelle
0

Am einfachsten ist es, den Panelizer zu verwenden .

Wenn Sie nicht Panelizer, sondern die Standard-Drupal-Ansichtsmodi oder die Display Suite verwenden, versuchen Sie es mit hook_field_display_alter () oder hook_field_display_ENTITY_TYPE_alter () .

Sie haben Entität, Anzeigekontext sowie alle Formatierungseinstellungen dort. Und Sie können die Einstellungen für das Feldrendern einfach ändern. Sie können den Feldformatierer sogar in einen anderen ändern.

Der Ansatz funktioniert perfekt für mich. Der einzige Nachteil ist, dass Sie möglicherweise mit unterschiedlichen Einstellungen in der Benutzeroberfläche "Anzeige verwalten" verwechselt werden.

melkowski
quelle
0

https://www.drupal.org/node/2130757 Es gibt ein gutes Beispiel. hook_field_formatter_third_party_settings_form () ist nützlich, um die Form des vorhandenen Feldformatierers zu ändern.

Dies funktioniert jedoch nicht mit Feldgruppen.

Pierre Noel
quelle