| 
12.09.2011
 | 
13:39

TYPO3: Datenbankabfragen mit TypoScript

Auf dem TYPO3-Camp München (t3cm11) habe ich einige Tricks zum Thema „Datenbankabfragen mit TypoScript” vorgestellt. Schwerpunkt war die Darstellung einzelner Felder aus der Datenbank. Im Folgenden stelle ich eine kurze Zusammenfassung des Vortrags mit Beispielen vor.

TypoScript ermöglicht den Zugriff auf Datenbankfelder. Man kann sich deshalb in vielen Fällen den Import (oder das Erstellen) von Extensions sparen, wenn man TypoScript nutzt. Als Beispiel wird tt_news verwendet, da diese Extension eine ganze Reihe interessanter Datenbankfelder mit sich bringt.

Es gibt im Wesentlichen drei Elemente, die Datenbankabfragen ermöglichen:

  • RECORDS
  • CONTENT
  • stdWrap-Funktionen: field und data

RECORDS-Objekt

Das RECORDS-Objekt ist relativ einfach, bietet jedoch relativ wenige Möglichkeiten. Eine Beispielabfrage wäre folgende:

Quelltext:  Alles auswählen  |  Zeilennummerierung an/aus
  1. 10 = RECORDS
  2. 10.source = 1
  3. 10.tables = tt_news
  4. 10.conf.tt_news = TEXT
  5. 10.conf.tt_news.field = title

Das Listing zeigt wie mit dem RECORDS-Objekt die Überschrift der News mit der ID 1 ausgegeben wird. Die Angabe von sources ist dabei zwingend notwendig. conf definiert die Art der Ausgabe, d.h. welche Felder ausgegeben werden sollen. Statt eines TEXT-Objekts könnte man hier beispielsweise ein COA-Objekt verwenden, um komplexere Ausgaben zu erzeugen.

Hier ein Beispiel dazu:

Quelltext:  Alles auswählen  |  Zeilennummerierung an/aus
  1. 10 = RECORDS
  2. 10.source = 1,2,3
  3. 10.tables = tt_news
  4. 10.conf.tt_news = COA
  5. 10.conf.tt_news {
  6.   1 = TEXT
  7.   1.field = title
  8.   1.wrap = <h3>|</h3>
  9.   2 = TEXT
  10.   2.field = bodytext
  11.   2.crop = 50|...|1
  12.   2.wrap = <p class="teaser">|</p>
  13. }

In diesem Beispiel werden die drei News mit den IDs 1, 2 und 3 ausgegeben. Die Ausgabe beschränkt sich auf den Titel und den Anfang des eigentlichen News-Textes.

RECORDS eignet sich also zur Ausgabe einzelner Datensätze oder einer Liste. Allerdings bietet es deutlich weniger Möglichkeiten als CONTENT.

Datenbankabfragen mit CONTENT

CONTENT kennt man normalerweise aus dem klassischen Templating. Allerdings erlaubt CONTENT, ähnlich wie RECORDS, die Ausgabe und das Zusammenstellen einzelner Felder. Außerdem erlaubt CONTENT über die select-Funktion wesentlich ausgefeiltere Datenbankabfragen mit JOINs u.ä. Ich empfehle daher die Verwendung von CONTENT, wenn man sich nicht sicher ist, ob man CONTENT oder RECORDS verwenden will.

Das Beispiel der letzten Listing würde mit dem CONTENT-Objekt folgendermaßen aussehen:

Quelltext:  Alles auswählen  |  Zeilennummerierung an/aus
  1. 10 = CONTENT
  2. 10 {
  3.   table = tt_news
  4.   select {
  5.     pidInList = 64
  6.   }
  7.   renderObj = COA
  8.   renderObj {
  9.     wrap = <div class="news_list">|</div>
  10.     1 = TEXT
  11.     1.field = title
  12.     1.wrap = <h3>|</h3>
  13.     2 = TEXT
  14.     2.field = bodytext
  15.     2.crop = 50|...|1
  16.     2.wrap = <p class="teaser">|</p>
  17.   }
  18. }

Knackpunkt bei CONTENT ist die Verwendung der wenig bekannten Funktion renderObj. Diese erwartet ein cObject, z.B. ein COA, das die Ausgabe steuert.

Es gibt bei CONTENT jedoch auch Einschränkungen. So wird lediglich der Zugriff auf Tabellen mit den Präfixen „tt_”, „tx_”, „ttx_”, „fe_” oder „user_”. Auch die pages-Tabelle ist abgedeckt. Damit sind praktisch alle Standardtabellen und Extensions abgedeckt, es gibt jedoch hin und wieder Fälle, in denen diese Einschränkung greift. Außerdem muss in der select-Funktion zwingend das Feld pidInList gesetzt werden. Diese Seiten-Id ist im obigen Beispiel 64 und muss in der Regel per Hand gesetzt werden, was beim Kopieren von TS-Code auf andere Seite lästig sein kann (Man könnte freilich eine Konstante definieren…).

Das CONTENT-Objekt bietet also ebenfalls schöne Möglichkeiten zur Darstellung einzelner Datenfelder an.

stdWrap-Funktionen data und field

data und field bieten bekanntermaßen in TEXT-Objekten die Möglichkeit, Datenfelder darzustellen. In den obigen Listings befinden sich bereits Beispiele für field. data bietet darüber hinaus eine sehr direkte Möglichkeit, einzelne Daten anzuzeigen:

Quelltext:  Alles auswählen  |  Zeilennummerierung an/aus
  1. 10 = TEXT
  2. 10.data = DB:tt_news:1:title
  3. 10.wrap = <h3>|</h3>

In diesem Fall wird der Titel der News mit der ID 1 direkt ausgegeben. Die Handhabung ist also einfach und kurz und ermöglicht einen einfachen Zugriff auf einzelne Datenfelder.

Wenn man die ID dynamisch übermittelt bekommt, z.B. über Get/Post-Variablen, kann man die Überschrift ebenfalls mit dieser Methode erzeugen. Die Get-Variable in der URL sei beispielsweise tt_news[uid]=2. Folgendes Listing verwendet diese Variable und zeigt die Überschrift je nach übergebener ID an:

Quelltext:  Alles auswählen  |  Zeilennummerierung an/aus
  1. 10 = TEXT
  2. 10.data = GP:tt_news|uid
  3. 10.wrap = {DB:tt_news:|:title}
  4. 10.insertData = 1

Hier wird ein wenig data und wrap-Magie angewendet.

Zunächst wird der Wert per GP (=Get/Post) aus der übergebenen Variable geholt. In unserem Fall wäre der Wert des Feldes dann 2. Dieser Wert wird gewrapped, und zwar mit einer Datenbank-Feld-Abfrage in geschweiften Klammern. Als Ergebnis enthielte das Feld nun {DB:tt_news:2:title}. Dieser Inhalt wird nun per insertData nochmals geparst und alle Werte zwischen geschweiften Klammern mit Dateninhalten ersetzt. Mit anderen Worten: Die Datenbankabfrage wird gestartet und der Titel der News mit der Id 2 geholt und dargestellt.

Fazit

Man könnte noch viele weitere Beispiele vorstellen. Ziel war es an dieser Stelle, eine kurze Einführung in die verschiedenen Möglichkeiten von TypoScript zu geben. Tatsächlich kann man mit wenigen weiteren Zeilen Inhalte dynamisch gestalten, indem man z.B. per typolink Parameter in die URL schreibt und diese auf einer anderen Seite ausliest, um Datenfelder dynamisch anzeigen zu lassen. Dies sind aber fortgeschrittene Themen, die ich vielleicht beim nächsten Camp zeigen werde.

Links

  •  
  • 5 Kommentare
  •  
Gravatar: MoritzMoritz
12.09.2011
14:29

Gelungen!

Ein gelungener Vortrag der auch für Typoscript Anfänger anschaulich war!

Komplexere SQL Abfragen habe ich bislang in eine userFunc ausgelagert - unnötig wenn man mit CONTENT und stdWrap ordentlich umgehen kann.

Gravatar: Stefan BinderStefan Binder
24.08.2012
10:27

Beispiel

Hier noch ein Anwendungbsp. von mir, hab da relativ lange herum gespielt.

Aus der DB anhand einer Get-Variable eine SysFolder-ID auslesen und dann die Content-Elemente darin ausgeben:



table = tt_content

select{

pidInList {

data = GP:tx_t3blog_pi1|blogList|category

wrap = {DB:tx_t3blog_cat:|:tx_t3entry_catcontentfolder}

insertData = 1

}

orderBy = sorting

languageField = sys_language_uid

}

Gravatar: Stefan BinderStefan Binder
24.08.2012
11:13

mm-tables

Hallo,

hab da noch eine Frage was ich jetzt nicht zusammen bringe...



wrap = {DB:tx_t3blog_post_cat_mm:|:uid_foreign}



wie funkt das mit _mm tables? man müsste das field: uid_local ansprechen... mit cat_mm.uid_local funktionierts nicht :S



thx for help =)



lg Stefan

Gravatar: MaxMax
25.08.2012
16:21

Re: mm-tables

Bei einer mm-table funktioniert das so nicht, weil die uid ja eine andere ist und entsprechenden Referenzen als Fremschlüssel in uid_local bzw. uid_foreign stehen.



Bei den meisten Contents könnstest du das über ein CONTENT-Objekt gehen und im select-Feld einen JOIN definieren, um das mm-Feld einzubinden (join, leftjoin, rightjoin). Über renderObj könntest du dann einzelne Felder des Objekts auf einer Seite ausgeben.



Schau mal auf http://www.typo3.net/tsref/functions/select/ für die vollständige Liste der selects.

Gravatar: Jan-Henrik HempelJan-Henrik Hempel
25.10.2012
21:48

Gute Erläuterung

Im Gegensatz zu diversen anderen Tipps auf verschiedenen Website führt die Lösung hier zum Ziel. Danke!



Ich habe damit ein Language Fallback auf Feldebene realisiert.



22 = TEXT

22 {

data = page : tx_myext_fieldname

stdWrap {

required = 1

wrap = {LLL:EXT:myext/static/template/locallang.xml:pages.field.tx_myext_fieldname}|

stripHtml = 1

htmlSpecialChars.preserveEntities = 1

}

override = TEXT

override {

data = page : uid

wrap = {DB:pages:|:tx_myext_fieldname}

if.isFalse.field = tx_myext_fieldname

insertData = 1

}

insertData = 1

}

Mein Kommentar
Ich möchte über jeden weiteren Kommentar benachrichtigt werden.

Zurück