Wer kennt es nicht, man hat einen Node oder, allgemeiner, eine Entity mit einem bestimmten Feld. Dieses möchte man nun im eigenen Modul oder Theme irgendwie ausgeben.
Den bisher gewohnten Weg aus Drupal 6, welcher auch in Drupal 7 funktioniert, beschritt man, indem man sich durch das Node-Objekt hangelte, sich das Feld griff. Codeseitig sah dies meist so aus:
<?php
$node->field_name['und'][0]['value'];
// oder
$node->field_name['de'][0]['value'];
// oder
$node->field_name[$node->language][0]['safe_value'];
?>Dieser Weg hat jedoch so seine Tücken.
So stehen ['und'], ['de'] etc. hier für die Lokalisierung der Website. Bei einsprachigen sowie mehrsprachigen Seiten kann es zu Problemen kommen, wenn sich der Keyname ändert. Man könnte jetzt sagen: "Ja, aber dafür habe ich doch $node->language zur Verfügung!", soweit richtig, aber warum sich überhaupt damit abkämpfen, wenn es Möglichkeiten gibt, die unabhängig der Sprache funktionieren? Dazu später mehr.
Das auf diesem Weg gewonne Value oder Safe-Value (nicht immer vorhanden), birgt insofern Sicherheitsrisiken, als dass es sich hier um reine Benutzereingaben handelt, welche zusätzlich nochmal zu behandeln wären, da sie so nicht durch die Sicherheitsschicht von Drupal laufen.
Will man so multiple Felder ausgeben, so muss man dies durch Schleifen realisieren.
Und zu guter Letzt, sei gesagt, das eben nur ein Value ausgegeben und so die Theming-Schicht ausgehebelt wird.
Und wie macht man es nun besser? Natürlich mit der
Drupal 7 Field-API
Die Field-API stellt für das Verarbeiten und Rendern von Feldern ein paar sehr nützliche Funktionen bereit.
Im Folgenden möchte ich euch 3 Vertreter näher bringen.
Dies wären:
field_view_field()
- Dokumentation: field_view_field()
Diese Funktion erwartet den Entity-Typen, z.B. 'node', das entsprechende Entity-Objekt und natürlich das Feld, was man ausgeben möchte. Optional kann ein Konfigurations-Array übergeben werden, mit z.B. Formatter-Einstellungen getroffen werden können; sowie der Language-Code kann übergeben werden, sofern man explizit eine bestimmte Sprache wünscht.
Aber was macht field_view_field() genau?
Kurz gesagt: Sie liefert den entsprechenden Render-Array des Feldes mit allen Elementen des Feldes zurück, d.h. es werden auch multiple Felder berücksichtigt.
Über print render($varname); erfolgt dann das aus D7 gewohnte Rendern.
Ein Beispiel für field_view_field()
Wir wollen ein Feld vom Typ "Bild" aus einem Node.
<?php
// Wir holen uns das Node-Objekt über node_load().
$node = node_load($nid);
// Unser Konfigurationsarray.
$display = array(
'type' => 'image', // Der Feld-Typ z.B. image, file, text.
'settings' => array( // Formatter-settings.
'image_style' => 'your_image_style', // Bild mit einem angelegtem Bildstil ausgeben.
'image_link' => 'content', // Und das Bild noch auf den Inhalt verlinken.
),
);
$variables['output'] = field_view_field('node', $node, 'field_NAME', $display);
?>In der Template-Datei müssen wir nun nur noch folgendes einbinden:
<?php print render($output);?>
Als Ergebnis sollten wir nun das fertig gerenderte Bild oder Bilder bei multiplen Feldern sehen können. Nebenbei gefragt: Jemand auf die Lokalisierung geachtet? ;) …
Der Markup ergibt sich in etwa so:
<div class="field field-name-field-image field-type-image field-label-hidden">
<div class="field-items">
<div class="field-item even" rel="og:image rdfs:seeAlso" resource="http://url-zum-bild/imagexy.jpg">
<a href="/node/3">
<img typeof="foaf:Image" src="http://url-zum-bild/imagexy.jpg" width="300" height="180" alt="">
</a>
</div>
</div>
</div>| Pro | Contra |
|---|---|
| • Lokalisierung muss nicht beachtet werden, dies leistet die Funktion | • Dokumentation bezgl. des Konfig-Arrays ist aus meiner Sicht etwas dürftig, damit verbunden ist viel Ausprobieren und Testen (wer eine gute Übersicht hat, immer her damit) |
| • Theming-Schicht wird komplett berücksichtigt |
field_get_items()
- Dokumentation: field_get_items()
Diese Funktion liefert uns einen Array mit allen Elemente eines Feldes zurück und erwartet ähnliche Parameter wie field_view_field(). So muss der Entity-Typ, das Entity-Objekt und der Feldname übergeben werden.
Um die Ergebnisse aus field_get_items() weiter zu verarbeiten, können wir uns jetzt der dritten Funktion bedienen:
field_view_value()
- Dokumentation: field_view_value()
field_view_value() erwartet ebenfalls den Entity-Typen, das Entity-Objekt, den Feldnamen und ein bestimmtes Element aus dem Feld. Wie auch field_view_field(), kann field_view_value ein Konfigurations-Array übergeben werden.
Als Ausgabe erhalten wir wieder einen Render-Array.
Ein Beispiel für field_get_items() und field_view_value():
<?php
// Wir holen uns das Node-Objekt über node_load().
$node = node_load($nid);
// Unser Konfigurationsarray.
$display = array(
'type' => 'image', // Der Feld-Typ z.B. image, file, text.
'settings' => array( // Formatter-settings.
'image_style' => 'your_image_style', // Bild mit einem angelegtem Bildstil ausgeben.
'image_link' => 'content', // Und das Bild noch auf den Inhalt verlinken.
),
);
// Wir holen uns alle Elemente des Feldes
$items = field_get_items('node', $node, 'field_name');
// Value für das erste Element des Feldes
$variables['output'] = field_view_value('node', $node, $item[$delta], $display);
?>In der Template-Datei wieder ganz einfach:
<?php print render($output);?>
Wir erhalten wieder das gerenderte Bild, jedoch unterscheidet sich der Markup im Vergleich zum Herangehen mit field_view_field():
<a href="/node/3">
<img typeof="foaf:Image" src="http://url-zum-bild/imagexy.jpg" width="300" height="180" alt="">
</a>Hier wird auch der wesentliche Unterschied zwischen field_view_field() und field_view_value() ersichtlich. Letzteres gibt wirklich nur das gerenderte Value zurück und nicht das gesamte Feld ansich. Weiterhin kann eben nur ein bestimmtes Element angesprochen werden. Will man also ein multiples Feld ausgeben, muss dies über eine Schleife geschehen.
| Pro | Contra |
|---|---|
| • Lokalisierung muss nicht beachtet werden, dies leistet die Funktion | • Dokumentation bezgl. des Konfig-Arrays ist aus meiner Sicht etwas dürftig, damit verbunden ist viel Ausprobieren und Testen (wer eine gute Übersicht hat, immer her damit) |
| • ein bestimmtes Element des Feldes ausgeben | • Multiple Felder müssen mit einer Schleife generiert werden |
| • Schlanker Markup, da nur das Value gerendert wird | • 2 Funktionsaufrufe: field_get_items() & field_view_value() |
Noch ein kleines Beispiel
Während der Session auf der #dughh, kam die Frage auf, wie man mit dieser Methode ein Bild verlinkt und dazu das Title-Attribut beim Link setzt.
Hier eine Möglichkeit:
<?php
// Wir holen uns das Node-Objekt über node_load().
$node = node_load($nid);
// Jetzt holen wir alle Elemente des Feldes 'field_name'
$items = field_get_items('node', $node, 'field_name');
// Unser Konfigurationsarray.
$display = array(
'type' => 'image',
'settings' => array(
'image_style' => 'your_image_style',
),
);
// Wir holen uns das erste Bild.
$image = field_view_value('node', $node, 'field_image', $items[0], $display);
// Jetzt das Ganze mit einem Link wrappen mit Hilfe der l()-Funktion.
// Dafür definieren wir uns ein paar Optionen.
$options = array(
'html' => TRUE, // Da unser 'Text' HTML enthält, müssen wir HTML auf TRUE setzen
'attributes' => array(
'title' => 'TITLE HERE', // Unser Title-Attribut.
),
);
// Nun mit Hilfe der l()-Funktion unser Ergebnis übergeben.
// Dabei ist zu beachten, dass unser Bild vorher
// mit drupal_render() in das entsprechende HTML zu übersetzen ist.
$variables['image'] = l(drupal_render($image), 'path/to/somewhere', $options);
?>Und wir erhalten:
<code><a href="/node/3" titl="TITLE HERE">
<img typeof="foaf:Image" src="http://url-zum-bild/imagexy.jpg" width="300" height="180" alt="">
</a>Fazit
Mit den angesprochenen Funktionen lassen sich also sehr viele Stolperfallen vermeiden und man kann bis zum Aufruf von render() Einfluss nehmen. Wenn gleich der ein oder andere Sonderfall mittels einer Helper-Funktion abzudecken ist, so sind die Funktionen aus der Drupal 7 Field-API in jedem Fall dem "gewohnten" Weg vorzuziehen.
Soweit meine Übersicht bezüglich der Field-Funktionen. Ich hoffe konnte an die ein oder andere Stelle Licht ins Dunkel bringen, freue mich über eure Anmerkungen und wünsche euch viel Spass mit den Funktionen :) .















