alexander EBNER patrick LOBACHER bernhard ULBRICH
TYPO3 EXTENSIONS PROFESSIONELLE FRONTEND- UND BACKENDPROGRAMMIERUNG
Mit
Extubndase Fluid
Ebner, Lobacher, Ulbrich TYPO3-Extensions
v
Bleiben Sie einfach auf dem Laufenden: www.hanser.de/newsletter Sofort anmelden und Monat für Monat die neuesten Infos und Updates erhalten.
Alexander Ebner Patrick Lobacher Bernhard Ulbrich
TYPO3-Extensions Professionelle Frontend- und Backend-Programmierung
Die Autoren: Alexander Ebner, München Patrick Lobacher, München Bernhard Ulbrich, München
Alle in diesem Buch enthaltenen Informationen, Verfahren und Darstellungen wurden nach bestem Wissen zusammengestellt und mit Sorgfalt getestet. Dennoch sind Fehler nicht ganz auszuschließen. Aus diesem Grund sind die im vorliegenden Buch enthaltenen Informationen mit keiner Verpflichtung oder Garantie irgendeiner Art verbunden. Autoren und Verlag übernehmen infolgedessen keine juristische Verantwortung und werden keine daraus folgende oder sonstige Haftung übernehmen, die auf irgendeine Art aus der Benutzung dieser Informationen – oder Teilen davon – entsteht. Ebenso übernehmen Autoren und Verlag keine Gewähr dafür, dass beschriebene Verfahren usw. frei von Schutzrechten Dritter sind. Die Wiedergabe von Gebrauchsnamen, Handelsnamen, Warenbezeichnungen usw. in diesem Buch berechtigt deshalb auch ohne besondere Kennzeichnung nicht zu der Annahme, dass solche Namen im Sinne der Warenzeichen- und Markenschutz-Gesetzgebung als frei zu betrachten wären und daher von jedermann benutzt werden dürften.
Bibliografische Information Der Deutschen Nationalbibliothek Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.d-nb.de abrufbar.
Dieses Werk ist urheberrechtlich geschützt. Alle Rechte, auch die der Übersetzung, des Nachdruckes und der Vervielfältigung des Buches, oder Teilen daraus, vorbehalten. Kein Teil des Werkes darf ohne schriftliche Genehmigung des Verlages in irgendeiner Form (Fotokopie, Mikrofilm oder ein anderes Verfahren) – auch nicht für Zwecke der Unterrichtsgestaltung – reproduziert oder unter Verwendung elektronischer Systeme verarbeitet, vervielfältigt oder verbreitet werden.
© 2010 Carl Hanser Verlag München Gesamtlektorat: Fernando Schneider Sprachlektorat: Sandra Gottmann, Münster-Nienberge Herstellung: Stefanie König Coverconcept: Marc Müller-Bremer, www rebranding.de, München Coverrealisierung: Stephan Rönigk Datenbelichtung, Druck und Bindung: Kösel, Krugzell Ausstattung patentrechtlich geschützt. Kösel FD 351, Patent-Nr. 0748702 Printed in Germany ISBN 978-3-446-41557-7 www hanser.de/computer
Inhalt
Teil I – Klassische Extensionprogrammierung 1 1.1 1.2 1.3 1.4 1.5
Grundlagen............................................................................................................... 3 Aufbau und Struktur von TYPO3 ............................................................................................3 Aufbau einer Extension............................................................................................................6 Arten und Einteilung von Extensions.......................................................................................7 Der Extension-Key...................................................................................................................8 TYPO3 Coding Guidelines ......................................................................................................9 1.5.1 Namespace ...............................................................................................................10 1.5.2 PHP-Regeln..............................................................................................................11 1.5.3 Dateistruktur.............................................................................................................12 1.5.4 PHP-Syntax ..............................................................................................................15 1.5.5 phpDoc .....................................................................................................................21 1.5.6 Changelog.................................................................................................................22
2 2.1
Eine Extension planen und entwickeln................................................................ 23 Extensions planen ..................................................................................................................23 2.1.1 Wir planen eine Blog-Extension...............................................................................24 Der Kickstarter.......................................................................................................................26 2.2.1 Die Datenbank..........................................................................................................28 2.2.2 Datenbanktabellen und Formulare – eine Erklärung ................................................34 2.2.3 Extend existing Tables .............................................................................................36 2.2.4 Frontend-Plug-ins.....................................................................................................37 2.2.5 Backend-Module ......................................................................................................40 2.2.6 Integrate in existing Modules ...................................................................................41 2.2.7 Clickmenu items.......................................................................................................41 2.2.8 Services ....................................................................................................................42 2.2.9 Static TypoScript code .............................................................................................43
2.2
V
Inhalt
2.3 2.4
3 3.1 3.2 3.3
3.4 3.5 4 4.1 4.2
4.3 4.4
VI
2.2.10 TSconfig................................................................................................................... 43 2.2.11 Die Extension erstellen............................................................................................. 44 Extension-Konfiguration mit ext_emconf.php....................................................................... 45 Die weiteren Dateien der Extension....................................................................................... 50 2.4.1 Verzeichnis doc........................................................................................................ 50 2.4.2 Verzeichnis mod#..................................................................................................... 50 2.4.3 Verzeichnis modfunc#.............................................................................................. 51 2.4.4 Verzeichnis pi#......................................................................................................... 52 2.4.5 Verzeichnis Static..................................................................................................... 52 2.4.6 Datei Changelog....................................................................................................... 53 2.4.7 Datei README.txt .................................................................................................. 53 2.4.8 Datei ext_icon.gif ..................................................................................................... 53 2.4.9 Datei ext_localconf.php ........................................................................................... 53 2.4.10 Datei ext_tables.php ................................................................................................. 53 2.4.11 Datei ext_tables.sql .................................................................................................. 54 2.4.12 Datei ext_tables_static+adt.sql ................................................................................. 55 2.4.13 Dateien Icon_tx_extkey_tabellenname.gif ............................................................... 56 2.4.14 Datei locallang xml .................................................................................................. 56 2.4.15 Datei locallang_db xml ............................................................................................ 56 2.4.16 Datei tca.php ............................................................................................................ 56 Backend-Module erstellen .................................................................................... 65 Module konfigurieren und im Hauptmenü anordnen ............................................................. 65 Einen eigenen Navigationsbaum erstellen ............................................................................. 69 Backend-Modul erstellen ....................................................................................................... 75 3.3.1 Das Modul initialisieren ........................................................................................... 75 3.3.2 Den Modulinhalt aufbauen....................................................................................... 79 3.3.3 Extension-Konfiguration über ext_conf_template.txt .............................................. 80 3.3.4 Backend-Formulare aufrufen ................................................................................... 82 3.3.5 Eine Datensatzliste mit Bearbeitungsfunktionen erstellen........................................ 84 3.3.6 Aufgabe: Module für Kommentare, Blog und Blogroll............................................ 90 Backend User Object – $BE_USER ...................................................................................... 91 Das Systemlog ....................................................................................................................... 92 Frontend-Plug-ins.................................................................................................. 95 Das Frontend-Plug-in im Überblick....................................................................................... 95 Feldinhalte für die Ausgabe aufbereiten .............................................................................. 103 4.2.1 Das Bild für Teaser Image...................................................................................... 104 4.2.2 Ausgabe des Haupttextes in der Listenansicht, wenn erwünscht........................... 105 4.2.3 Haupttext mit RTE formatieren.............................................................................. 105 4.2.4 Haupttext statt Teasertext anzeigen, falls dieser nicht verfügbar ist...................... 106 4.2.5 Verlinken des Autorennamens mit der Mail-Adresse des Autors.......................... 106 4.2.6 Kategorien als Namen anzeigen und verlinken (Relationen).................................. 107 HTML-Templates für das Plug-in........................................................................................ 109 Die Kommentarfunktion mit AJAX und eID ....................................................................... 114 4.4.1 Ausgabe vorhandener Kommentare ....................................................................... 115
Inhalt
4.5 4.6 4.7 5 5.1 5.2
5.3
4.4.2 Das Kommentarformular hinzufügen .....................................................................118 Was sind Hooks?..................................................................................................................123 Flexforms .............................................................................................................................125 4.6.1 Erzeugen der Flexform ...........................................................................................126 Das Plug-in pi2.....................................................................................................................132 Dokumentation und Abschluß ............................................................................ 133 Code dokumentieren mit extdeveval ....................................................................................133 Extension-Dokumentation schreiben....................................................................................134 5.2.1 Die Vorlage ............................................................................................................135 5.2.2 Der Aufbau der Dokumentation .............................................................................135 5.2.3 Vorlagenstile ..........................................................................................................136 5.2.4 Die Dokumentation verfassen ................................................................................136 Upload ins TER....................................................................................................................137
Teil II – Funktionsreferenz zur klassischen Extensionprogrammierung 6 6.1
6.2
Datenbank ............................................................................................................ 141 $GLOBALS['TYPO3_DB'] .................................................................................................141 6.1.1 exec_SELECTquery ...............................................................................................141 6.1.2 exec_SELECT_queryArray....................................................................................141 6.1.3 exec_SELECTgetRows ..........................................................................................142 6.1.4 exec_SELECT_mm_query.....................................................................................142 6.1.5 exec_INSERTquery................................................................................................143 6.1.6 exec_UPDATEquery..............................................................................................143 6.1.7 exec_DELETEquery...............................................................................................143 6.1.8 sql_fetch_assoc.......................................................................................................143 6.1.9 sql_fetch_row .........................................................................................................144 6.1.10 searchQuery............................................................................................................144 6.1.11 listQuery .................................................................................................................144 6.1.12 splitGroupOrderLimit.............................................................................................145 6.1.13 quoteStr ..................................................................................................................145 6.1.14 fullQuoteStr............................................................................................................145 6.1.15 fullQuoteArray .......................................................................................................146 6.1.16 escapeStrForLike....................................................................................................146 6.1.17 cleanIntArray..........................................................................................................147 6.1.18 cleanIntList.............................................................................................................147 6.1.19 debug_lastBuiltQuery.............................................................................................147 tslib_pibase ..........................................................................................................................148 6.2.1 pi_exec_query ........................................................................................................148 6.2.2 pi_getPidList ..........................................................................................................149 6.2.3 pi_getRecord ..........................................................................................................150 6.2.4 pi_prependFieldsWithTable ...................................................................................150
VII
Inhalt
VIII
6.3
cObj ..................................................................................................................................... 151 6.3.1 DBgetDelete........................................................................................................... 151 6.3.2 DBgetInsert ............................................................................................................ 151 6.3.3 DBgetUpdate.......................................................................................................... 152 6.3.4 enableFields ........................................................................................................... 153
7 7.1
Dateisystem.......................................................................................................... 155 t3lib_div............................................................................................................................... 155 7.1.1 dirname .................................................................................................................. 155 7.1.2 fixWindowsFilePath............................................................................................... 155 7.1.3 formatSize .............................................................................................................. 156 7.1.4 get_dirs................................................................................................................... 156 7.1.5 getAllFilesAndFoldersInPath................................................................................. 157 7.1.6 getFileAbsFileName............................................................................................... 158 7.1.7 getFilesInDir .......................................................................................................... 158 7.1.8 getURL................................................................................................................... 159 7.1.9 isAbsPath ............................................................................................................... 159 7.1.10 isAllowedAbsPath.................................................................................................. 159 7.1.11 mkdir ...................................................................................................................... 160 7.1.12 mkdir_deep............................................................................................................. 160 7.1.13 removePrefixPathFromList .................................................................................... 160 7.1.14 resolveBackPath..................................................................................................... 161 7.1.15 rmdir....................................................................................................................... 161 7.1.16 split_fileref ............................................................................................................. 162 7.1.17 tempnam................................................................................................................. 162 7.1.18 unlink_tempfile ...................................................................................................... 162 7.1.19 upload_copy_move ................................................................................................ 162 7.1.20 upload_to_tempfile ................................................................................................ 163 7.1.21 verifyFilenameAgainstDenyPattern ....................................................................... 163 7.1.22 writeFile ................................................................................................................. 164 7.1.23 writeFileToTypo3tempDir ..................................................................................... 164
8 8.1
Strings, Arrays und Umgebungsvariablen ........................................................ 165 Allgemeine Funktionen........................................................................................................ 165 8.1.1 _GET...................................................................................................................... 165 8.1.2 _GETset ................................................................................................................. 165 8.1.3 _GP ........................................................................................................................ 166 8.1.4 _POST.................................................................................................................... 166 8.1.5 callUserFunction .................................................................................................... 166 8.1.6 clientInfo ................................................................................................................ 167 8.1.7 compat_version ...................................................................................................... 167 8.1.8 compileSelectedGetVarsFromArray ...................................................................... 168 8.1.9 getHostname........................................................................................................... 168 8.1.10 getIndpEnv ............................................................................................................. 168 8.1.11 getThisUrl .............................................................................................................. 168 8.1.12 linkThisScript......................................................................................................... 169
Inhalt
8.2
8.1.13 linkThisUrl .............................................................................................................169 8.1.14 locationHeaderUrl ..................................................................................................169 8.1.15 makeInstance..........................................................................................................170 8.1.16 makeInstanceService ..............................................................................................170 8.1.17 rmFromList.............................................................................................................170 8.1.18 sysLog ....................................................................................................................171 String-Funktionen ................................................................................................................171 8.2.1 calcParenthesis .......................................................................................................171 8.2.2 cmpFQDN ..............................................................................................................171 8.2.3 cmpIP .....................................................................................................................172 8.2.4 convUmlauts...........................................................................................................172 8.2.5 csvValues ...............................................................................................................172 8.2.6 deHSCentities.........................................................................................................173 8.2.7 expandList ..............................................................................................................173 8.2.8 fixed_lgd ................................................................................................................173 8.2.9 fixed_lgd_pre .........................................................................................................174 8.2.10 formatForTextarea..................................................................................................174 8.2.11 generateRandomBytes............................................................................................174 8.2.12 get_tag_attributes ...................................................................................................175 8.2.13 htmlspecialchars_decode ........................................................................................175 8.2.14 implodeArrayForUrl...............................................................................................175 8.2.15 implodeAttributes...................................................................................................176 8.2.16 inList ......................................................................................................................176 8.2.17 int_from_ver...........................................................................................................177 8.2.18 intInRange ..............................................................................................................177 8.2.19 intval_positive ........................................................................................................178 8.2.20 isFirstPartOfStr.......................................................................................................178 8.2.21 md5int ....................................................................................................................178 8.2.22 milliseconds............................................................................................................179 8.2.23 modifyHTMLColor ................................................................................................179 8.2.24 modifyHTMLColorAll ...........................................................................................179 8.2.25 normalizeIPv6 ........................................................................................................180 8.2.26 removeXSS.............................................................................................................180 8.2.27 revExplode .............................................................................................................180 8.2.28 rm_endcomma ........................................................................................................181 8.2.29 shortMD5 ...............................................................................................................181 8.2.30 split_tag_attributes .................................................................................................181 8.2.31 splitCalc..................................................................................................................182 8.2.32 strtolower................................................................................................................183 8.2.33 strtoupper................................................................................................................183 8.2.34 substUrlsInPlainText ..............................................................................................183 8.2.35 testInt......................................................................................................................184 8.2.36 trimExplode............................................................................................................184 8.2.37 uniqueList...............................................................................................................185 8.2.38 validEmail ..............................................................................................................185 8.2.39 validIP ....................................................................................................................185
IX
Inhalt
8.3
8.4
9 9.1 9.2
9.3
10 10.1
X
8.2.40 validIPv4 ................................................................................................................ 186 8.2.41 validIPv6 ................................................................................................................ 186 Array-Funktionen................................................................................................................. 186 8.3.1 addSlashesOnArray................................................................................................ 186 8.3.2 array_merge ........................................................................................................... 187 8.3.3 array_merge_recursive_overrule............................................................................ 187 8.3.4 array2json............................................................................................................... 188 8.3.5 array2xml ............................................................................................................... 188 8.3.6 arrayToLogString ................................................................................................... 189 8.3.7 explodeUrl2Array .................................................................................................. 190 8.3.8 inArray ................................................................................................................... 190 8.3.9 print_array.............................................................................................................. 190 8.3.10 removeArrayEntryByValue.................................................................................... 191 8.3.11 slashArray .............................................................................................................. 191 8.3.12 view_array.............................................................................................................. 192 8.3.13 xml2array ............................................................................................................... 192 8.3.14 xml2tree ................................................................................................................. 193 8.3.15 xmlGetHeaderAttribs ............................................................................................. 194 String-Funktionen in Frontend-Plug-ins .............................................................................. 195 8.4.1 calcAge .................................................................................................................. 195 8.4.2 checkEmail............................................................................................................. 195 8.4.3 codeString .............................................................................................................. 195 8.4.4 encryptEmail .......................................................................................................... 196 8.4.5 HTMLcaseshift ...................................................................................................... 196 8.4.6 keywords ................................................................................................................ 196 8.4.7 linebreaks ............................................................................................................... 197 8.4.8 processParams ........................................................................................................ 197 8.4.9 uniqueHash............................................................................................................. 198 8.4.10 URLqMark ............................................................................................................. 198 Bilder .................................................................................................................... 199 Einbinden............................................................................................................................. 199 Bearbeiten ............................................................................................................................ 200 9.2.1 Bild umrechnen (fürs Web optimieren).................................................................. 200 9.2.2 Abmessungen ändern ............................................................................................. 201 9.2.3 Zuschneiden ........................................................................................................... 201 9.2.4 Graustufen.............................................................................................................. 202 Erzeugen .............................................................................................................................. 203 9.3.1 Bild in bestehendes Bild einfügen.......................................................................... 203 9.3.2 Text erzeugen......................................................................................................... 204 AJAX im Frontend ............................................................................................... 205 eID ....................................................................................................................................... 205 10.1.1 Konfiguration ......................................................................................................... 205 10.1.2 Basisdatei ............................................................................................................... 206
Inhalt 10.2
Zusammenspiel AJAX & eID ..............................................................................................206 10.2.1 Aufbau der XML-Response....................................................................................206 10.2.2 AJAX-Request und Verarbeitung...........................................................................207
11 11.1
Frontend-Plug-ins ................................................................................................ 209 Cache ...................................................................................................................................209 11.1.1 cacheExpires...........................................................................................................209 11.1.2 clearPageCacheContent..........................................................................................209 11.1.3 clearPageCacheContent_pidList.............................................................................209 11.1.4 get_cache_timeout..................................................................................................210 11.1.5 set_cache_timeout_default .....................................................................................210 11.1.6 set_no_cache ..........................................................................................................210 Content-Elemente.................................................................................................................211 11.2.1 cImage ....................................................................................................................211 11.2.2 cleanFormName .....................................................................................................211 11.2.3 cObjGet ..................................................................................................................211 11.2.4 cObjGetSingle ........................................................................................................212 11.2.5 currentPageUrl........................................................................................................212 11.2.6 fileResource............................................................................................................213 11.2.7 getImgResource......................................................................................................213 11.2.8 getSlidePids............................................................................................................213 11.2.9 gifBuilderTextBox..................................................................................................214 11.2.10 stdWrap ..................................................................................................................214 Links ....................................................................................................................................215 11.3.1 baseUrlWrap...........................................................................................................215 11.3.2 getMailTo ...............................................................................................................215 11.3.3 getTypoLink ...........................................................................................................216 11.3.4 getTypoLink_URL .................................................................................................216 11.3.5 http_makelinks .......................................................................................................217 11.3.6 imageLinkWrap......................................................................................................217 11.3.7 mailto_makelinks ...................................................................................................218 11.3.8 pi_getPageLink.......................................................................................................218 11.3.9 pi_linkToPage ........................................................................................................218 11.3.10 pi_linkTP................................................................................................................219 11.3.11 pi_linkTP_keepPIvars ............................................................................................219 11.3.12 pi_linkTP_keepPIvars_url ......................................................................................219 11.3.13 pi_openAtagHrefInJSwindow ................................................................................220 11.3.14 prefixLocalAnchorsWithScript...............................................................................220 Listen ...................................................................................................................................220 11.4.1 pi_list_browseresults ..............................................................................................221 11.4.2 pi_list_linkSingle....................................................................................................222 11.4.3 pi_list_makelist ......................................................................................................222 11.4.4 pi_list_modeSelector ..............................................................................................223 11.4.5 pi_list_searchBox ...................................................................................................223
11.2
11.3
11.4
XI
Inhalt 11.5
11.6
11.7
11.8
XII
JavaScript............................................................................................................................. 224 11.5.1 additionalHeaderData............................................................................................. 224 11.5.2 additionalJavaScript ............................................................................................... 224 11.5.3 JSeventFuncCalls ................................................................................................... 225 11.5.4 minifyJavaScript .................................................................................................... 225 11.5.5 quoteJSvalue .......................................................................................................... 226 11.5.6 rawUrlEncodeJS..................................................................................................... 226 11.5.7 setJS ....................................................................................................................... 227 11.5.8 wrapJS.................................................................................................................... 227 CSS ...................................................................................................................................... 228 11.6.1 additionalCSS......................................................................................................... 228 11.6.2 additionalHeaderData............................................................................................. 228 11.6.3 pi_getClassName.................................................................................................... 229 11.6.4 pi_setClassStyle ..................................................................................................... 229 11.6.5 setCSS .................................................................................................................... 229 Mehrsprachigkeit ................................................................................................................. 230 11.7.1 getLLL ................................................................................................................... 230 11.7.2 pi_getLL................................................................................................................. 230 11.7.3 readLLfile............................................................................................................... 231 Umgebungsvariablen und allgemeine Funktionen ............................................................... 232 11.8.1 absRefPrefix........................................................................................................... 232 11.8.2 additionalHeaderData............................................................................................. 232 11.8.3 all ........................................................................................................................... 232 11.8.4 anchorPrefix ........................................................................................................... 233 11.8.5 applicationData ...................................................................................................... 233 11.8.6 ATagParams........................................................................................................... 233 11.8.7 baseUrl ................................................................................................................... 234 11.8.8 baseUrlWrap .......................................................................................................... 234 11.8.9 beUserLogin........................................................................................................... 234 11.8.10 clientInfo ................................................................................................................ 234 11.8.11 content.................................................................................................................... 235 11.8.12 defaultBodyTag...................................................................................................... 235 11.8.13 domainStartPage .................................................................................................... 235 11.8.14 extTarget ................................................................................................................ 236 11.8.15 fePreview ............................................................................................................... 236 11.8.16 id ........................................................................................................................... 236 11.8.17 imagesOnPage........................................................................................................ 237 11.8.18 intTarget ................................................................................................................. 237 11.8.19 lang......................................................................................................................... 237 11.8.20 lastImageInfo ......................................................................................................... 238 11.8.21 loginUser................................................................................................................ 238 11.8.22 no_cache................................................................................................................. 238 11.8.23 page ........................................................................................................................ 239 11.8.24 printError................................................................................................................ 239 11.8.25 rootLine.................................................................................................................. 240 11.8.26 siteScript ................................................................................................................ 240
Inhalt 11.8.27 tmpl->config, tmpl->setup......................................................................................241 11.8.28 type.........................................................................................................................241 11.8.29 TYPO3_CONF_VARS ..........................................................................................241 11.8.30 uniqueString ...........................................................................................................242 11.9 Konfiguration mit Flexforms ...............................................................................................242 11.9.1 Erstellen einer Plug-in_Flexform ...........................................................................242 11.9.2 Auslesen der Formulardaten...................................................................................243 11.10 Konfiguration mit TypoScript ..............................................................................................244 11.11 Konfiguration im Extension-Manager..................................................................................244 12 12.1 12.2
13 13.1
13.2
13.3 13.4 13.5
Frontend-User & Sessions .................................................................................. 245 Frontend-User ......................................................................................................................245 12.1.1 Daten des aktuell angemeldeten Users ...................................................................245 Sessions................................................................................................................................246 12.2.1 Daten speichern ......................................................................................................246 12.2.2 Daten auslesen........................................................................................................246 12.2.3 Warenkorb aufbauen ..............................................................................................246 Backend & Services............................................................................................. 249 Eigene Flexforms .................................................................................................................249 13.1.1 Mehrsprachigkeit....................................................................................................250 13.1.2 Tabs ........................................................................................................................251 13.1.3 Elemente.................................................................................................................252 13.1.4 Flexform-Daten im Frontend..................................................................................256 Backend-Module..................................................................................................................257 13.2.1 Dokumententypen für $this->doc ...........................................................................257 13.2.2 TypoScript einer Seite auslesen..............................................................................257 13.2.3 AJAX im Backend..................................................................................................257 Services................................................................................................................................259 cli .........................................................................................................................................259 Debugging............................................................................................................................260 13.5.1 debug ......................................................................................................................260 13.5.2 debug_ordvalue ......................................................................................................261 13.5.3 debug_trail..............................................................................................................261 13.5.4 debugRows .............................................................................................................261 13.5.5 devLog....................................................................................................................262
Teil III – Extbase und Fluid 14 14.1
Der neue Weg der Extension-Programmierung ................................................ 265 Grundlagen der objektorientierten Programmierung............................................................267 14.1.1 Klassen und Objekte...............................................................................................267 14.1.2 Vererbung von Klassen ..........................................................................................271
XIII
Inhalt
14.2
15 15.1 15.2 15.3 15.4
15.5
15.6
15.7
16 16.1
XIV
14.1.3 Kontrollierte Vererbung – abstrakte und finale Klassen......................................... 273 14.1.4 Sichtbarkeiten: public, private und protected ......................................................... 274 14.1.5 Interfaces................................................................................................................ 275 14.1.6 Type Hints.............................................................................................................. 277 14.1.7 Statische Methoden und Eigenschaften.................................................................. 277 14.1.8 Namespaces............................................................................................................ 278 Neue Konzepte..................................................................................................................... 279 14.2.1 Domain Driven Design........................................................................................... 280 14.2.2 Model-View-Controller.......................................................................................... 281 14.2.3 Modellierung.......................................................................................................... 282 14.2.4 Gemeinsamens Vokabular – Ubiquitous Language................................................ 282 14.2.5 Die Elemente des Modells...................................................................................... 285 Ein Rundgang durchs System............................................................................ 287 Installation von Extbase und Fluid....................................................................................... 287 Installation der Extension blog_example ............................................................................. 289 Datenstruktur im Blog-Example .......................................................................................... 291 Namenskonventionen........................................................................................................... 293 15.4.1 Verzeichnis- und Dateinamen ................................................................................ 294 15.4.2 Klassennamen ........................................................................................................ 294 15.4.3 Controller und Actions ........................................................................................... 295 Die Dateistruktur im Extension-Root-Verzeichnis .............................................................. 295 15.5.1 Die Datei ext_emconf.php...................................................................................... 296 15.5.2 Die Datei ext_tables.php ........................................................................................ 297 15.5.3 Die Datei ext_localconf.php................................................................................... 301 15.5.4 Die Dateien ext_tables.sql und ext_icon.gif ........................................................... 302 Die Verzeichnisstruktur ....................................................................................................... 302 15.6.1 Das Verzeichnis Classes......................................................................................... 303 15.6.2 Das Verzeichnis Configuration .............................................................................. 304 15.6.3 Das Verzeichnis Module ........................................................................................ 305 15.6.4 Das Verzeichnis Resources .................................................................................... 305 15.6.5 Weitere Verzeichnisse............................................................................................ 305 Der prinzipielle Ablauf ........................................................................................................ 305 15.7.1 Aufruf des Dispatchers (Schritt 1).......................................................................... 306 15.7.2 Aufruf des Controllers (Schritt 2)........................................................................... 309 15.7.3 Ansprechen des Respositorys (Schritt 3)................................................................ 309 15.7.4 Zurückliefern der Blog-Objekte (Schritt 4) ............................................................ 309 15.7.5 Das Objekt wird dem View zugeordnet (Schritt 5) ................................................ 311 15.7.6 Rückgabe der Template-Ausgabe an den Controller (Schritt 6)............................. 313 15.7.7 Rückgabe der Ausgabe an den Dispatcher (Schritt 7) ............................................ 314 15.7.8 Rückgabe der Ausgabe an TYPO3 (Schritt 8)........................................................ 314 Entwicklung eines eigenen Plug-ins.................................................................. 315 Aufbau einer minimal funktionstüchtigen Extension........................................................... 315 16.1.1 Extension-Key........................................................................................................ 315 16.1.2 Verzeichnisse anlegen ............................................................................................ 316
Inhalt
16.2 16.3 16.4
16.5 16.6 16.7 16.8
16.9 16.10 16.11 16.12
16.13
16.14 16.15 16.16 16.17 16.18
16.1.3 Die Datei ext_emconf.php......................................................................................316 16.1.4 Die Dateien ext_localconf.php und ext_tables.php ................................................317 16.1.5 Einrichten eines Standard-Controllers ....................................................................318 16.1.6 Installieren der Extension und das erste Erfolgserlebnis ........................................319 Hinzufügen eines Views.......................................................................................................320 Entitäten einführen ...............................................................................................................322 Daten persistieren (Datenspeicher).......................................................................................324 16.4.1 Datenbankstruktur – die Datei ext_tables.sql .........................................................325 16.4.2 Datenbankstruktur – das TCA ................................................................................329 Anlegen eines Repositorys ...................................................................................................333 Anlegen einer neuen Action.................................................................................................335 16.6.1 Anlegen der Action addAction() ............................................................................336 Daten per Formular eingeben und auswerten .......................................................................337 Objekte aus dem Repository entfernen.................................................................................338 16.8.1 Zufügen der Action delete in der Konfiguration.....................................................338 16.8.2 Anpassen der Template-Datei index.html...............................................................338 Update von Objekten............................................................................................................339 16.9.1 Edit- und Update-Action hinzufügen......................................................................339 Der Query-Manager .............................................................................................................341 Eingabevalidierung ..............................................................................................................343 Validatoren...........................................................................................................................343 16.12.1 Vordefinierte Validatoren.......................................................................................343 16.12.2 Eigene Validatoren .................................................................................................344 16.12.3 Ausgabe der Fehler.................................................................................................347 16.12.4 Optionale Argumente .............................................................................................347 Relationen zu anderen Tabellen ...........................................................................................348 16.13.1 Erweiterung des TCA .............................................................................................348 16.13.2 Die Domain-Klasse Tx_Simpleblog_Domain_Model_Post ...................................349 16.13.3 Registrieren der Actions in der Datei ext_localconf.php ........................................350 16.13.4 Erstellung des Post-Controllers ..............................................................................350 16.13.5 Neue Templates und Template-Änderungen ..........................................................353 16.13.6 Ändern der Blog-Identity........................................................................................354 16.13.7 Aufruf der Extension im Frontend..........................................................................356 Relationen zu anderen Tabellen m:n ....................................................................................356 Mehrsprachigkeit zufügen....................................................................................................361 Konfiguration mittels TypoScript ........................................................................................363 Backend-Module mit Extbase ..............................................................................................365 Der Extbase-Kickstarter .......................................................................................................366 16.18.1 Installation des Extbase-Kickstarters......................................................................367 16.18.2 Überblick über den Arbeitsbereich .........................................................................368 16.18.3 Eingabe der Extension-Konfiguration ....................................................................369 16.18.4 Modellierung ..........................................................................................................370 16.18.5 Anlegen des Post-Objekts.......................................................................................372 16.18.6 Anlegen des Tag-Objekts .......................................................................................372 16.18.7 Relationen festlegen ...............................................................................................373
XV
Inhalt 16.19 Weitere Extbase-Interna....................................................................................................... 374 16.19.1 StoragePid .............................................................................................................. 374 16.19.2 MVC-Request ........................................................................................................ 376 16.19.3 FlashMessages realisieren ...................................................................................... 377 17 17.1 17.2
17.3
17.4
17.5
17.6 17.7
Die Fluid-Template-Engine.................................................................................. 379 Vorbereitung ........................................................................................................................ 380 Basissyntax und einfache Ausgabe ...................................................................................... 382 17.2.1 Arrays..................................................................................................................... 382 17.2.2 Objekte................................................................................................................... 383 Fluid ViewHelper-Syntax .................................................................................................... 384 17.3.1 Namespace (Namensraum)..................................................................................... 384 17.3.2 Argumente.............................................................................................................. 385 ViewHelper-Übersicht ......................................................................................................... 387 17.4.1 alias ........................................................................................................................ 387 17.4.2 base ........................................................................................................................ 388 17.4.3 cObject ................................................................................................................... 388 17.4.4 count....................................................................................................................... 389 17.4.5 cycle ....................................................................................................................... 389 17.4.6 debug...................................................................................................................... 390 17.4.7 else ......................................................................................................................... 390 17.4.8 for........................................................................................................................... 390 17.4.9 form........................................................................................................................ 391 17.4.10 format..................................................................................................................... 402 17.4.11 groupedFor ............................................................................................................. 406 17.4.12 if ........................................................................................................................... 407 17.4.13 image...................................................................................................................... 408 17.4.14 layout...................................................................................................................... 409 17.4.15 link ......................................................................................................................... 409 17.4.16 render ..................................................................................................................... 414 17.4.17 renderFlashMessages ............................................................................................. 414 17.4.18 section .................................................................................................................... 415 17.4.19 then......................................................................................................................... 415 17.4.20 translate .................................................................................................................. 415 17.4.21 uri ........................................................................................................................... 416 Erstellen eines eigenen ViewHelpers................................................................................... 416 17.5.1 Der Dummytext-ViewHelper ................................................................................. 417 17.5.2 Zugriff auf die übergebenen Argumente ................................................................ 418 17.5.3 Zufügen von Argumenten ...................................................................................... 419 17.5.4 Tag-basierende ViewHelper................................................................................... 419 17.5.5 Der Variablen-Container ........................................................................................ 420 Verwendung von Fluid in klassischen Extensions ............................................................... 421 Layouts und Partials............................................................................................................. 423
Register............................................................................................................................ 427
XVI
Vorwort Das letzte Jahr war voll von Veränderungen und Neuerungen, die es nicht ganz leicht machten, dieses Buch zu vollenden. Ich danke daher unserem Lektor Fernando Schneider für seine Engelsgeduld mit uns. Besonderer Dank gebührt Börni, der sich in einer Nachtund-Nebel-Aktion ins Boot gewuchtet hat, um mit Patrick und mir dieses Projekt zu meistern. Seine Engagement und seine Ideen haben dem Buch den richtigen Impuls gegeben. Ich danke Pat für die vielen guten Ideen und die Rolle als treibende Kraft in so vielen Aspekten meiner beruflichen und auch privaten Laufbahn. Ich danke ebenso meinen Eltern und meiner Großmutter für ihren Rückhalt. Auch meinen Kolleginnen und Kollegen bei FTI, Chris, Bogomip, Matthias, Vivian, Silke, Nanni, Mirja, Emilios, Murat, Alf, Marita und allen anderen möchte ich meinen Dank aussprechen, haben sie mir doch im vergangenen Jahr ein neues berufliches, aber auch freundschaftliches Zuhause gegeben, in dem ich mich pudelwohl fühle. Meinen Teil widme ich meinem Großvater. Das hier hätte Dir gefallen.
Alexander Ebner
Dieses Buch hat eine lange und vielleicht auch etwas schwere Geburt hinter sich. Aber es hat sich durchaus gelohnt, so lange damit zu warten. Nur so hatten wir die Chance die Themen Extbase & Fluid hineinzunehmen, die im ursprünglichen Manuskript nicht vorgesehen waren, da diese hoch spannenden Technologien zu jenem Zeitpunkt noch nicht zur Verfügung standen. Allein dieser Umstand, so unsere Hoffnung, wird manchem Leser die lange Wartezeit im Nachhinein vielleicht ein wenig versüßen.
XVII
Vorwort Mein Dank geht natürlich auch an meinen Freund Alex, der dieses Projekt trotz widriger Umstände und meiner Gängeleien bestens gemeistert hat, und auch Börni, den wir komplett ins kalte Wasser schmissen, indem wir ihn fragten, ob er sich nicht zu uns gesellen will. Er hat seinen Erstling mit Bravour gemeistert. Es hat mir sehr viel Spaß gemacht, dieses Projekt mit Euch zu stemmen. Vor allem danke ich Fernando, unserem geschätzten Lektor. Er hat stets an uns und dieses Buch geglaubt und es so überhaupt noch möglich gemacht. Mein größter Dank allerdings gebührt der Liebe meines Lebens – meiner Frau Marina. Ohne Ihre Geduld und Ihren Glauben an mich und meine Arbeit hätte ich auch dieses Buch sicherlich nie zu Ende bringen können. Unzählige Stunden hat Sie (wieder einmal) auf mich verzichtet und ist vielleicht nun, da dieses Buch das Licht der Welt erblickt hat, etwas stolz. Und wenn sich auch am Ende nur eine kurze Erwähnung im Vorwort dazu findet – bei jedem Buchstabe, bei jedem Satz und bei jeder Seite waren meine Gedanken stets auch bei Dir.
Patrick Lobacher
Zunächst einmal möchte ich meinen beiden Autorenkollegen Patrick und Alex für das große Vertrauen danken, das sie in mich hatten – auf ihre ganz unkomplizierte und lockere Art und Weise haben sie mich mit ins Boot genommen. Alleine hätte ich mir das sicherlich nie zugetraut - vielen vielen Dank dafür! Es war für mich ein sehr spannendes, lehrreiches aber vor allem auch schönes erstes Buchprojekt. Mein größter Dank gilt aber natürlich meiner geliebten Frau Silvi. Sie hat mich von Anfang an zu hundert Prozent unterstützt und hat immer daran geglaubt, dass ich diese Aufgabe schaffen werde. Von unserer ohnehin schon knappen gemeinsamen Zeit hat sie mir an vielen Tagen und Wochenenden den Rücken vollkommen frei gehalten – ohne diese Unterstützung, mein Bär, hätte ich es sicher nie geschafft! Und schließlich widme ich dieses Buch unserer süßen Maus Marie. Auch sie musste viele viele Stunden auf ihren Papa verzichten und hat es sogar gelernt, die Tür zum Büro geschlossen zu lassen. Vielleicht findet ja auch sie eines Tages Gefallen an TYPO3 – ich arbeite daran ;-)
Bernhard Ulbrich
XVIII
I Teil I – Klassische Extensionprogrammierung
1 1 1.1
Grundlagen
Aufbau und Struktur von TYPO3 Um Extensions für TYPO3 entwickeln zu können, müssen Sie über den grundsätzlichen Aufbau von TYPO3 Bescheid wissen. Dazu gehört zum Beispiel, in welcher Reihenfolge TYPO3 die einzelnen Schritte, die nötig sind, um eine Webseite zu erstellen, abarbeitet. Der schematische Aufbau geht vom Webbrowser aus. Damit rufen Sie entweder das Backend oder das Frontend auf. Beide greifen wiederum auf die Extensions zu, die in dem System installiert sind. Selbst das CMS ist als Extension realisiert. Alle Extensions greifen über die Extension-API auf den TYPO3-Kern (Core) zu. Dieser beinhaltet nur die grundlegenden Funktionen. Der Kern, wie auch alle Extensions, sind in der Programmiersprache PHP geschrieben. Als Basis dienen ein Webserver (z.B. Apache, lighttpd, IIS) und eine Datenbank (z.B. MySQL, Oracle, PostreSQL). Es ist möglich, die TYPO3-Extension-API zu umgehen und beispielsweise Datenbankzugriffe nativ in PHP zu schreiben. Aber dieses „Zu-Fuß-Gehen“ ist nicht empfehlenswert. Über die API stehen Ihnen weitere Features wie Abstraktion, Validierungen etc. zur Verfügung. Um beim Beispiel Datenbankzugriff zu bleiben, über die API-Funktionen kann eine Extension auf verschiedenen Datenbanksystemen verwendet werden. Wenn Sie die mysql-Funktionen von PHP direkt verwenden, wird Ihre Extension auch nur mit MySQL zusammenarbeiten. Daher ist die API ein sehr wichtiger Schritt im Ablauf. Sehr interessant ist allerdings, was im Einzelnen denn nun genau passiert, wenn eine Webseite im Frontend aufgerufen wird. Jeder Aufruf im Frontend beginnt mit der Datei index.php im Rootverzeichnis (DocumentRoot). Ganz egal, ob Sie eine Seite tief im Seitenbaum aufrufen und wie viele Parameter Sie der URL anhängen, am Ende rufen Sie doch nur diese eine Datei auf. Das gilt auch beim Einsatz von Extensions wie realURL und CoolURI, die semantische URLs erzeugen. Durch die Direktiven der .htacces-Datei wird dennoch auf die index-php zugegriffen. In dieser ist der Pfad zur TypoScript-Library (PATH_tslib) hinterlegt, die damit inkludiert wird. Als Nächstes wird die Datei in-
3
1 Grundlagen dex_ts.php aus der Extension cms eingebunden, die den Rest der Ablaufsteuerung übernimmt. Ist diese nicht verfügbar, quittiert der Server die Anfrage mit einer Fehlermeldung und widmet sich anderen Dingen. In der index_ts.php kommt es zu folgendem Ablauf im Frontend-Rendering-Prozess: 1. Die Umgebungsparameter wie Betriebsystem, Webserver und Art der PHP-Unterstützung werden ermittelt. 2. Die Pfade zum typo3conf- und t3lib-Verzeichnis werden bestimmt. 3. Der Time-Tracker (PATH_t3lib.’class.t3lib_timetrack.php) startet. Der Time-Tracker loggt die Parse-Zeiten und Kommentare. Diese werden im Admin-Panel zur Verfügung gestellt. 4. Die obligatorischen Klassen _t3lib_div, die diverse allgemeine Funktionen zur Verfügung stellt, und t3lib_extmgm, die das Extension-Handling durchführt, werden geladen. 5. Nun beginnt die Konfigurationsphase. Es wird eine Standardkonfiguration aus PATH_t3lib.config_default.php geladen. Dann wird die eigentliche Konfigurationsdatei typo3conf/localconf.php aufgerufen. Als Letztes werden noch die Konfigurationen aus den Extensions geladen. Diese befinden sich in den ext_ localconf.php-Dateien in den jeweiligen Extension-Verzeichnissen. Der Datenbankzugriff aufgrund der Konfiguration wird überprüft. Ist auch die Extension cms korrekt geladen, kann es weiter gehen. 6. Wird als GET- oder POST-Parameter die eID übergeben, wird diese nun ausgewertet. Dazu ist ein Ausstiegspunkt definiert, der den Frontend-Rendering-Prozess abbricht. Der eID-Parameter kommt beispielsweise bei AJAX-Requests zum Tragen, wenn nicht die komplette Seite, sondern nur Teile des Inhalts benötigt werden. Der Parameter beinhaltet die eine Klasse, die an dieser Stelle aufgerufen wird und die restliche Ausgabe erledigt. Diese Klasse lädt die eID-Helper-Klasse nach, die eine Datenbankunterstützung zur Verfügung stellt und den möglichen Frontend-User definiert. 7. Wird der Vorgang nicht durch einen eID-Prozess abgebrochen, wird er fortgesetzt, indem folgende Frontend-Bibliotheken geladen werden:
PATH_tslib.’class.tslib_fe.php’
Klasse für das TypoScript-basierte Frontend
PATH_tslib.’class.tslib_page.php’
Klasse für die Seitenfunktionen
PATH_tslib.’class.tslib_userauth.php’
Klasse für die Authentifizierung von FE-Usern
PATH_tslib.’class.tslib_feuserauth.php’
Klasse für die Frontend-Session und das Login
PATH_tslib.’class.tslib_fe.php’
Klasse für die Template-Verarbeitung
PATH_tslib.’class.tslib_cs.php’
Klasse für die Zeichenkonvertierung von und zu UTF-8
4
1.1 Aufbau und Struktur von TYPO3 8. Initialisierung und Befüllung des $TSFE-Objektes (TypoScript-Frontend). Erste Werte, mit denen es befüllt wird, sind einige GBVars (GET-/POST-Variablen): id, type, no_cache, cHash, jumpurl, MP und RDCT. 9. Bei gesetztem RDCT-Parameter wird mittels des zugehörigen MD5-Hashwertes der entsprechende Link aus der Datenbank geholt und eine Weiterleitung dahin ausgelöst. 10. Die Kompression wird aktiviert, sofern die Gzip-Kompression in der Variablen $TYPO3_CONF_VARS[’FE’][’compressionLevel] gesetzt ist. 11. Initialisierung des Frontend-Users. Dazu wird die Session ausgelesen und überprüft,
ob der User sich neu einloggen muss. 12. Überprüfung des Cookies auf den Wert preBeUser. Ist dieser gesetzt, wird geprüft, ob ein Backend-User angemeldet ist, der dann initialisiert wird. Ist dies erfolgreich geschehen, werden weitere Klassen für BE-Funktionalitäten nachgeladen:
PATH_tslib.’class.tslib_befunc.php’
Klasse für Standardfunktionen des Backends.
PATH_tslib.’class.tslib_userauthgroup.php’
Klasse zur Authentifizierung und Initialisierung von BE-Usergroups
PATH_tslib.’class.tslib_beauthuser.php’
Klasse zur Authentifizierung von BE-Usern
PATH_tslib.’class.tslib_beauthuser.php’
Klasse zur Authentifizierung von BE-Usern (TSFE-spezifisch) 13. Wurde ein Workspace-Preview angefordert, wird dieses nun initialisiert. 14. Bestimmung der Page-ID (pid). Da jedes Element, jeder Datensatz einer pid zugeordnet ist, ist sie die zentrale Komponente im Rendering-Prozess. 15. Einlesen der $TCA (Table Configuration Array). Das TCA definiert die (veränderbaren) Datenbanktabellen und ihre Beziehung untereinander. Darüber hinaus definiert sie die Darstellung der einzelnen Formularelemente der Felder im Backend und im FEEditing. 16. Verfügbarkeit der Seite im Cache wird geprüft. 17. Überprüfung, ob das config-Array existiert. Gegebenenfalls wird es nachgeladen. 18. POST-Variablen werden in einen vorher definierten Zeichensatz konvertiert. 19. Setzen der Sprache im Frontend und einstellen der Locales (Datumsformat, Zeit, Währung etc.) 20. Ist JumpUrl aktiviert und die aktuelle Seite per TypoScript-Typolink als externe Seite definiert, wird nun die ZielURL ermittelt. Die Weiterleitung selbst wird erst in Schritt 27 erfolgen. Dadurch ist es möglich, Statistiken zu erhalten, wie oft beispielsweise ein Link angeklickt wurde. Die JumpUrl-Konfiguration erfolgt im Setup des Templates: config.jumpurl_enable = 1 (oder 0) config.jumpurl_mailto_disable = 0 (oder 1)
5
1 Grundlagen 21. Verarbeitung der Formulardaten. Dies schließt Formulare im Frontend sowie E-MailFormulare mit ein. 22. Die Seite wird generiert, aber noch nicht ausgegeben. Ist sie bereits im Cache vorhanden, wird die Version aus dem Cache verwendet, ansonsten wird sie neu gerendert, also zusammengebaut. 23. Einfügen weiterer Files. Beispielsweise Dateien, die über PHP_SCRIPT_INT definiert wurden (includeLibs). 24. Wurde keine JumpUrl definiert, erfolgt nun der Output der Seite. Alle Inhalte und Skripte werden im $TSFE-Objekt zusammengefügt und über echo ausgegeben. Wurde allerdings die Gzip-Komprimierung aktiviert, werden die Inhalte nur zusammengefügt, aber noch nicht ausgegeben. Das erfolgt dann in Schritt 31. 25. Die mögliche Frontend-Session, die in Schritt 11 ermittelt wurde, wird abgespeichert. 26. Die Statistik wird erstellt. Zum Beispiel wird die Parse-Zeit ermittelt. 27. Wurde eine JumpUrl definiert, wird auf diese nun weitergeleitet. 28. Da es möglich ist, Seiten auch statisch zu publizieren, wird dies hier durchgeführt, falls die Konfiguration dies verlangt. 29. Das Admin-Panel wird an den Quellcode angehängt und ausgegeben, sofern es aktiviert wurde und der angemeldete Backend-Benutzer die Rechte dazu hat. 30. Bei aktiviertem Deugging werden alle Debug-Messages ausgegeben. 31. Ausgabe der Daten, falls Gzip-Kompression aktiviert ist.
1.2
Aufbau einer Extension Eine Extension kann aus einem oder mehreren Abschnitten bestehen. Die FrontendAusgabe besteht (in der Regel) aus einem Plug-in. Davon können durchaus mehrere in einer Extension existieren. Sie liegen in eigenen Verzeichnissen mit der Bezeichnung p1#, wobei # für eine vorlaufende Nummer steht. Plug-ins können auf die TypoScriptKonfiguration zurückgreifen oder aber direkt konfiguriert werden, sofern ein Konfigurationsformular implementiert wird. Backend-Module dagegen integrieren sich in das Hauptmenü des Backends und geben keine Ausgabe an das Frontend weiter. Sie sind in Unterverzeichnissen mit der Bezeichnung mod# organisiert. Auch Services können in einer Extension existieren, um Funktionen bereitzustellen. Für AJAX-Requests und ähnliche Aufgaben können Skripte hinzugefügt werden, die über den eID-Parameter aufgerufen werden können und die meisten Funktionalitäten des TYPO3-Cores umgehen. Nur der Datenbankzugriff und das FEuser-Objekt sind hier verfügbar. Eine Dokumentation darf ebenfalls nicht fehlen.
6
1.3 Arten und Einteilung von Extensions
1.3
Arten und Einteilung von Extensions Es gibt drei Arten von Extensions:
Lokale Extensions Globale Extensions Systemextensions Die Reihenfolge spiegelt die Priorität wider. Ist eine Extension also beispielsweise lokal und global installiert, wird die lokale Version verwendet, da sie die höhere Priorität besitzt. Um Extensions etwas zu ordnen, sind sie in verschiedene Kategorien eingeteilt. Backend Extensions, die im Backend zum Tragen kommen, aber keinen eigenen Menüpunkt im Hauptmenü besitzen. Sie stellen in der Regel Erweiterungen bestehender Funktionalitäten oder Tools dar. Ein Beispiel ist rtehtmlarea. Backend-Modul Extensions mit einem eigenen Menüpunkt, also einem eigenen Modul. Als Beispiel wäre hier quixplorer zu nennen. Frontend Erweiterungen für das Frontend, die nicht unbedingt eine eigene Ausgabe erzeugen, diese aber durchaus beeinflussen und verändern können. Die bekannteste Extension dieser Art ist die css_styled_content. Frontend-Plug-in Eine Extension, die ein eigenes Plug-in mitbringt und eine Ausgabe im Frontend erzeugt. Eine der bekanntesten Extension dieser Kategorie ist tt_news. Services Services stellen Dienstleistungen und Funktionalitäten für andere Extensions bereit. Ein Service kann beispielsweise Daten über externe Schnittstellen weiterverarbeiten. Documentation Diese Extensions dienen zur Bereithaltung von Dokumentationen und Manuals. Diese werden in der Regel als OpenOffice-Dokumente bereitgestellt. Examples Tutorials und Beispiele für TYPO3 und Extensions.
7
1 Grundlagen Templates Fertige TYPO3-Templates. Diese stehen sowohl als HTML-/CSS-Templates wie auch für TemplaVoila und TemplateAutoparser bereit. Templates für timtab werden beispielsweise in dieser Kategorie im TER bereitgehalten. Miscellaneous Alles, was nicht in die eben genannten Kategorien fällt, wird hier eingeordnet. [] Diese Nichtkategorie sammelt Extensions, für die keine Kategorie angegeben wurde. Die Entscheidung, in welche Kategorie eine Extension fällt, ist nicht immer einfach. Hier sollten Sie den Hauptzweck der Extension hinterfragen und danach eine Bewertung vornehmen. Wenn eine Extension mit FE-Plug-ins, BE-Modulen und vielleicht noch Services daherkommt, ihre Hauptaufgabe aber darin besteht, ganz tolle Sachen auf der Webseite darzustellen, ist die treffendste Kategorie natürlich Frontend-Plug-ins. Miscellaneous sollte die Ausnahme darstellen. Die Zeit, sich etwas Gedanken über die eigene Extension zu machen, sollte man schon mitbringen
1.4
Der Extension-Key Bevor Sie auch nur eine Zeile Code schreiben, kommt die Wahl des richtigen ExtensionKeys. Und diese Wahl will gut überlegt sein. Denn „eineLustigeExtension_trallalalla“ sorgt für mehr Frust und ist die fünf Sekunden Lächeln nicht wert. Der Extension-Key muss einmalig, (möglichst) treffend und (idealerweise) kurz sein. Sonderzeichen sind nicht erlaubt. Der oft anzutreffende Underscore „_“ ist zwar nicht verboten, sollte aber nicht mehr verwendet werden, da dieser im Quellcode sowieso getilgt wird. Aus „elu_krass“ wird beispielsweise „class_elukrass_pi1“. Haben Sie sich für einen Extension-Key entschieden, sollten Sie den Key reservieren. Zum einen um auszuschließen, dass es bereits eine Extension mit dem Key gibt, und anderseits um Probleme zu vermeiden, wenn ein Zweiter den genialen Einfall hatte, den Sie gerade produziert haben. Sie können natürlich den Extension-Key später noch ändern – theoretisch. Glauben Sie uns, Sie möchten das nicht tun. Dazu wäre es nötig, den Key auch in allen Skripten der Extension zu ändern. Bei umfangreichen Extensions kann das eine ganze Weile dauern. Um einen Key zu registrieren, loggen Sie sich auf der Webseite http://typo3.org ein. Wenn Sie noch keinen Login besitzen, ist dies nun die perfekte Gelegenheit für eine Registrierung auf der Seite. Nach der Anmeldung navigieren Sie in den Menüpunkt Extensions. Hier ist die Unterseite Extension-Keys von Interesse. Auf dieser Seite können Sie im Reiter Register Keys einen neuen Key anlegen.
8
1.5 TYPO3 Coding Guidelines
Abbildung 1.1 Neuen Key registrieren
1.5
TYPO3 Coding Guidelines Man könnte prinzipiell loslegen und Extensions programmieren. Einmal quer durch die API pflügen, und am Ende steht eine Extension da, die vielleicht sogar funktioniert. Aus Gründen der Sicherheit, der Erweiterbarkeit und der Zukunftssicherheit sollte man sich aber doch an einige Regeln halten. Diese Regeln haben in den TYPO3 Coding Guidelines Gestalt angenommen1. Die CGLs beinhalten beispielsweise die Verzeichnisstruktur einer Extension. Hier ist auch nachzulesen, dass eine strikte Trennung zwischen dem TYPO3-Kern und allen übrigen Dateien einzuhalten ist. PHP-Dateien, die Klassen beinhalten, müssen mit class_ im Namen beginnen, Dateien mit PHP-Interfaces mit interface_. Jede Datei sollte nur eine Klasse oder nur ein Interface beinhalten. Die Benennung erfolgt nach diesem Beispiel: class__.php
Der Namespace ordnet Klassen und Funktionen logisch zu.
1
http://typo3.org/documentation/document-library/core-documentation/doc_core_cgl/4.3.0/view/
9
1 Grundlagen
1.5.1
Namespace
Eine Reihe von Namensräumen ist bereits vordefiniert. t3lib Dieser Namensraum definiert gemeinsame Dateien für das Frontend und das Backend. Diese stellen allgemeine Funktionalitäten bereit. Sie befinden sich im t3lib-Verzeichnis des Cores und sind in Unterverzeichnisse geordnet. Die Verzeichnishierarchie wird in die Benennung der Klassendateien mit aufgenommen. User-Dateien dürfen diesen Namensraum nicht nutzen. typo3 Dieser Namensraum wird von TYPO3-Backend-Dateien verwendet, die aus historischen Gründen auch andere Präfixe in ihrer Benennung nutzen können. Keine User-Dateien erlaubt. tslib Die TypoScript-Bibliotheken sind für das Frontend-Rendering verantwortlich und halten sich aus historischen Gründen nicht zwingend an die Namenskonvention. User-Dateien dürfen diesen Namensraum ebenfalls nicht nutzen. tx_ Extensions nutzen den Namensraum tx_, gefolgt vom Extension-Key, der um die Underscores bereinigt wurde. Beispiel tx_mykey_myclass, user_ Der Namensraum user_ gilt für PHP-Dateien ohne Klasse. Die Verwendung von user_ wird nicht empfohlen. Funktionen in klassenlosen PHP-Dateien werden von TYPO3 nicht ausgeführt, wenn sie den user_-Namespace nicht verwenden. Auch die Funktionen selbst müssen dieses Präfix im Namen enthalten. ux_ Dieser Namespace ist für XCLASS-Dateien in Extensions reserviert.
10
1.5 TYPO3 Coding Guidelines
1.5.2
PHP-Regeln
PHP-Tags Die PHP-Tags dürfen als Paar nur einmal in einer Datei auftreten. Das Tag muss geschlossen werden. Listing 1.1 Korrekte Verwendung
Nach dem schließenden Tag dürfen keine Leerzeichen oder Leerzeilen kommen. Dies würde die Kompression verhindern und AJAX-Requests stören. Nicht erlaubt ist dagegen die folgende Verwendung. Listing 1.2 Falsche Verwendung ###TITLE### ###SUBTITLE### ###CRDATE### ###TEASERIMG### ###TEASER### ###BODYTEXT### ###CATEGORY### ###AUTHOR###
Speichern Sie die Datei unter dem Namen tx_elublog_template.tpl im Verzeichnis pi1 ab. Nun muss das Plug-in diese Datei einlesen und die Werte substituieren. Folgende Eintragung in der Funktion main() definiert die Template-Vorlage:
109
4 Frontend-Plug-ins Listing 4.28 Template verwenden $this->templateFile = ($conf['templateFile']) ? $this->cObj-> fileResource($conf['templateFile']) : $this->cObj-> fileResource('EXT:elublog/pi1/tx_elublog_template.tpl');
Nun müssen den Markern die Inhalte zugewiesen werden. Dazu ändern wir die Funktion $this->pi_list_row(). Listing 4.29 pi_list_row() function pi_list_row($c) { $cObj = t3lib_div::makeInstance('tslib_cObj'); $markerArray['###BODYTEXT###'] = ($this->getFieldContent ('bodytextinlist') == 1) ? $cObj->stdWrap($this->getFieldContent ('bodytext'),$this->conf['listView.']['bodytext_stdWrap']) : ''; $markerArray['###TITLE###'] = $cObj->stdWrap($this-> getFieldContent('title'),$this->conf['listView.']['title_stdWrap.']); $markerArray['###CRDATE###'] = $cObj->stdWrap(htmlspecialchars($this-> getFieldContent('crdate')),$this->conf['listView.']['crdate_stdWrap.']); $markerArray['###SUBTITLE###'] = $cObj->stdWrap(htmlspecialchars ($this->getFieldContent('subtitle')),$this->conf['listView.'] ['subtitle_stdWrap.']); $markerArray['###TEASERIMG###'] = $cObj->stdWrap($this-> getFieldContent('teaserimg'),$this->conf['listView.'] ['teaserimg_stdWrap.']); $markerArray['###TEASERTEXT###'] = $cObj->stdWrap($this-> getFieldContent('teasertext'),$this->conf['listView.'] ['teasertext_stdWrap.']); $markerArray['###AUTHOR###'] = $cObj->stdWrap($this-> getFieldContent('author'),$this->conf['listView.']['author_stdWrap.']); $markerArray['###CATEGORY###'] = $cObj->stdWrap($this-> getFieldContent('category'),$this->conf['listView.'] ['category_stdWrap.']); $markerArray['###TAGS###'] = $cObj->stdWrap($this-> getFieldContent('tags'),$this->conf['listView.']['tags_stdWrap.']); $template['item'] = $this->cObj->getSubpart($this->templateFile, '###ITEM###'); return $this->cObj->substituteMarkerArrayCached$template['item'], $markerArray); }
Es wird ein Array namens $markerArray aufgebaut, dessen Keys den Markern in der Vorlage entsprechen. Diesem Array werden die Markerinhalte zugewiesen, nachdem mittels $this->cObj->stdWrap() die StdWrap-Eigenschaften zugewiesen wurden. Am Ende wird dem Subpart ###ITEM### das Array übergeben, und damit werden die Marker in diesem Subpart substituiert. Allerdings muss auch die Funktion $this->pi_make_list() der Klasse tslib_pibase überschrieben werden, da diese Funktion eine Tabelle aufbaut, die uns hier nichts nützt. Listing 4.30 Neue Funktion $this->pi_make_list() function pi_list_makelist($res,$tableParams='') { $this->internal['currentRow']=''; $template['total'] = $this->cObj->getSubpart($this->templateFile, '###LISTVIEW###'); $template['item'] = $this->cObj->getSubpart($this->templateFile, '###ITEM###'); $c=0; $fixedMarkerArray['###AT###'] = $this->pi_getLL('at'); $fixedMarkerArray['###FROM###'] = $this->pi_getLL('from'); $fixedMarkerArray['###IN###'] = $this->pi_getLL('in');
110
4.3 HTML-Templates für das Plug-in while($this->internal['currentRow'] = $GLOBALS['TYPO3_DB']-> sql_fetch_assoc($res)) { $markerArray = $this->pi_list_row($c); $markerArrayMerged = array_merge($markerArray,$fixedMarkerArray); $contentItem .= $this->cObj->substituteMarkerArrayCached ($template['item'],$markerArrayMerged); $c++; } $content = $this->cObj->substituteMarkerArrayCached($template['total'], array(), array('###ITEM###' => $contentItem)); return $content; }
Die Datenbankeinträge werden geholt. Bei jedem Durchlauf wird die Funktion $this>pi_list_row() aufgerufen und das Ergebnis der Variablen $contentItem hinzugefügt.
Diese wird letztendlich dem Subpart ###LISTVIEW### zugewiesen. Am Ende wird der Subpart substituiert. Im TypoScript fehlen noch die Eigenschaften des stdWrap der einzelnen Felder. Jedes Feld sollte mit einem -Container gewrapt werden. Listing 4.31 stdWrap im TypoScript plugin.tx_elublog_pi1.listView.title_stdWrap.wrap = | plugin.tx_elublog_pi1.listView.subtitle_stdWrap.wrap = | plugin.tx_elublog_pi1.listView.crdate_stdWrap.wrap = | plugin.tx_elublog_pi1.listView.teaserimg_stdWrap.wrap = | plugin.tx_elublog_pi1.listView.teasertext_stdWrap.wrap = | plugin.tx_elublog_pi1.listView.bodytext_stdWrap.wrap = | plugin.tx_elublog_pi1.listView.author_stdWrap.wrap = | plugin.tx_elublog_pi1.listView.category_stdWrap.wrap = | plugin.tx_elublog_pi1.listView.tags_stdWrap.wrap = |
Das Ergebnis sehen Sie in der folgenden Abbildung.
111
4 Frontend-Plug-ins
Abbildung 4.4 Die Ausgabe der Listenansicht per Template
Auch die Ausgabe im SingleView, also der Artikel allein, muss angepasst werden. Es werden auch die Marker für die Kommentare und das Kommentarformular gesetzt. Diese werden aus eigenen Funktionen kommen, werden aber im Moment nur als Dummy gebaut. Listing 4.32 Templating der Einzelansicht function singleView($content, $conf) { $this->conf = $conf; $this->pi_setPiVarDefaults(); $this->pi_loadLL(); if ($this->internal['currentRow']['title']) $GLOBALS['TSFE']-> indexedDocTitle=$this->internal['currentRow']['title']; $content=''; $cObj = t3lib_div::makeInstance('tslib_cObj'); $markerArray['###BODYTEXT###'] = $cObj->stdWrap($this->getFieldContent ('bodytext'),$this->conf['singleView.']['bodytext_stdWrap']); $markerArray['###TITLE###'] = $cObj->stdWrap($this->getFieldContent ('title'),$this->conf['singleView.']['title_stdWrap.']); $markerArray['###CRDATE###'] = $cObj->stdWrap(htmlspecialchars ($this->getFieldContent('crdate')),$this->conf['singleView.'] ['crdate_stdWrap.']); $markerArray['###SUBTITLE###'] = $cObj->stdWrap(htmlspecialchars ($this->getFieldContent('subtitle')),$this->conf['singleView.'] ['subtitle_stdWrap.']);
112
4.3 HTML-Templates für das Plug-in $markerArray['###TEASERIMG###'] = $cObj->stdWrap($this-> getFieldContent('teaserimg'),$this->conf['singleView.'] ['teaserimg_stdWrap.']); $markerArray['###TEASERTEXT###'] = $cObj->stdWrap($this-> getFieldContent('teasertext'),$this->conf['singleView.'] ['teasertext_stdWrap.']); $markerArray['###AUTHOR###'] = $cObj->stdWrap($this->getFieldContent ('author'),$this->conf['singleView.']['author_stdWrap.']); $markerArray['###CATEGORY###'] = $cObj->stdWrap($this-> getFieldContent('category'),$this->conf['singleView.'] ['category_stdWrap.']); $markerArray['###TAGS###'] = $cObj->stdWrap($this->getFieldContent ('tags'),$this->conf['singleView.']['tags_stdWrap.']); $markerArray['###COMMENTS###'] = $cObj->stdWrap($this->getComments(), $this->conf['singleView.']['comments_stdWrap.']); $markerArray['###COMMENTFORM###'] = ($this->getFieldContent ('lockcomments') == 1) ? $cObj->stdWrap($this->pi_getLL ('commentsNotAllowed'),$this->conf['singleView.']['commentForm_stdWrap.'] ) : $cObj->stdWrap($this->getCommentForm(),$this->conf['singleView.'] ['commentForm_stdWrap.']); $markerArray['###AT###'] = $this->pi_getLL('at'); $markerArray['###FROM###'] = $this->pi_getLL('from'); $markerArray['###IN###'] = $this->pi_getLL('in'); $markerArray['###BACKLINK###'] = $cObj->stdWrap($this-> pi_list_linkSingle($this->pi_getLL('back','Back'),0),$this->conf ['singleView.']['backLink_stdWrap.']); $template['item'] = $this->cObj->getSubpart($this->templateFile, '###SINGLEVIEW###'); $content .= $this->cObj->substituteMarkerArrayCached ($template['item'],$markerArray); $content .= ""; $this->pi_getEditPanel(); return $content; }
Die Funktion sieht $this->pi_list_row() sehr ähnlich. Allerdings fehlt die if-Abfrage beim bodytext, der stdWrap wird durch den TypoScript-Hive singleView konfiguriert, und das Einbinden der Kommentarfunktion ist vorbereitet. Allerdings müssen wir zwei Funktionen anlegen, da sonst ein Fehler gemeldet würde. Sie müssen erst einmal nur existieren, ausprogrammiert werden sie im nächsten Schritt. Listing 4.33 Funktions-Dummys anlegen function getComments() {} function getCommentForm() {}
Da wir die Ausgabe des Funktionsselektors nicht benötigen, entfernen Sie aus der Funktion $this->listView folgende Zeilen: Listing 4.34 Funktionsselektor $fullTable.=$this->pi_list_modeSelector($items);
Wir haben die Listenansicht und die Einzelansicht mit Templates belegt. Durch Änderungen an diesen mit CSS und TypoScript haben wir nun die Möglichkeit, die Ausgabe individuell anzupassen. Im Folgenden wurde das Template in eine (sehr einfache) Seite mit drei Spalten eingebaut und gestylt.
113
4 Frontend-Plug-ins
Abbildung 4.5 Der Blog mit angepasstem Styling
4.4
Die Kommentarfunktion mit AJAX und eID Bei jedem Blog ist die Kommentarfunktion wichtig. Es gehört zum guten Ton des Web 2.0, die Besucher zu integrieren und Interaktivitäten zu ermöglichen. Um das Ganze ein wenig aufzupeppen, sollen die Kommentare über AJAX versendet werden. Der Schüssel dazu liegt im eID-Mechanismus. Dadurch sind Datenbankmanipulationen möglich, ohne den kompletten Rendering-Prozess von TYPO3 zu durchlaufen.
114
4.4 Die Kommentarfunktion mit AJAX und eID
Abbildung 4.6 Der Ablauf beim Abschicken eines Kommentars
4.4.1
Ausgabe vorhandener Kommentare
Wir beginnen also mit der Ausgabe eventuell vorhandener Kommentare und des Kommentarformulars. Dazu kommt ein wenig JavaScript für den AJAX-Request und das Einfügen des neuen Kommentars in die Kommentarliste.
115
4 Frontend-Plug-ins Um die vorhandenen Kommentare auszugeben, verwenden wir die Funktion $this-> getComments(), die wir vorhin als Dummy angelegt haben. Listing 4.35 Funktion $this->getComments() function getComments() { $template['comment'] = $this->cObj->getSubpart($this->templateFile, '###COMMENT###'); $template['item'] = $this->cObj->getSubpart($this->templateFile, '###COMMENTITEM###'); $contentItem = ''; $c=1; $cObj = t3lib_div::makeInstance('tslib_cObj'); // Datenbankabfrage nach allen Kommentaren zu dem Blogeintrag $res = $this->pi_exec_query('tx_elublog_blogcomments', 0, "AND blogentry=".$this->internal['currentRow']['uid']); // Übersetzungsmarker, die sich nicht ändern, setzen. $fixedMarkerArray['###AT###'] = $this->pi_getLL('at'); // Datensätze durchlaufen und Marker zuweisen while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { $markerArray['###NUMBER###'] = $cObj->stdWrap($c,$this->conf ['singleView.']['comment.']['number_stdWrap.']); $markerArray['###AUTHOR###'] = ($row['website'] != '') ? $cObj-> stdWrap("conf['singleView.'] ['comment.']['author_stdWrap.']."") : $cObj->stdWrap($row['author'], $this->conf['singleView.']['comment.']['author_stdWrap.']); $markerArray['###COMMENTTEXT###'] = $cObj->stdWrap(strip_tags ($row['comment']),$this->conf['singleView.']['comment.'] ['comment_stdWrap.']); $markerArray['###DATE###'] = $cObj->stdWrap($row['crdate'],$this-> conf['singleView.']['comment.']['crdate_stdWrap.']); $markerArray['###GRAVATAR###'] = $cObj->stdWrap('',$this->conf['singleView.']['comment.'] ['gravatar_stdWrap.']); // $markerArray mit den fixen Markern in $fixedMarkerArray zusammenführen $markerArrayMerged = array_merge($markerArray,$fixedMarkerArray); // Marker substituieren $contentItem .= ''.$this-> cObj->substituteMarkerArrayCached($template['item'], $markerArrayMerged). ''; $c++; } // Anzahl der Kommentare ermitteln und zuweisen. $count = $c-1; $marker['###COMMENTCOUNT###'] = $cObj->stdWrap('<span id="tx_elublog_commentcountnumber">'.$count.''.$this-> pi_getLL('comments'),$this->conf['singleView.']['comment.'] ['commentcount_stdWrap.']); $content = ($contentItem != '') ? $this->cObj-> substituteMarkerArrayCached($template['comment'], $marker, array('###COMMENTITEM###' => $contentItem)):$this->pi_getLL ("noComments"); return ''.$content.''; }
Es wird eine Abfrage gegen die Datenbank abgesetzt, die alle Kommentare aus der Tabelle tx_elublog_blogcomments sucht, die dem Beitrag zugeordnet sind. Die Ergebnisse werden durchlaufen und den Markern zugeordnet.
116
4.4 Die Kommentarfunktion mit AJAX und eID Listing 4.36 HTML-Template für die Kommentare ###COMMENTNUMBER### ###COMMENTAUTHOR### ###AT### ###COMMENTDATE### ###GRAVATAR### ###COMMENTTEXT###
Der Container mit ID tx_elublog_newcomment wird den neuen Kommentar anzeigen, den der Besucher hinterlässt. Eine Besonderheit ist der Marker ###GRAVATAR###. Ihm wird ein sogenannter Gravatar zugeordnet. Das ist ein Bild, auch als Avatar bekannt, das oft den Kommentarverfasser, aber auch beliebig andere Inhalte zeigt. Das Bild ist einer Mail-Adresse zugeordnet und wird unter http://www.gravatar.com verwaltet. Zur Zeit der Drucklegung ist dieser Dienst kostenlos (und wird es wohl auch bleiben). Die Gravatar-Bilder haben in der Regel eine Größe zwischen 40 und 120 Pixel. Über eine API-Schnittstelle wird der MD5-Hash der Mail-Adresse bei Gravatar.com abgefragt, ob dafür ein Bild existiert. Wenn ja, wird dieses in der angeforderten Größe zurückgesendet. Andernfalls wird ein Standardbild geliefert. Zwei Parameter müssen über TypoScript konfiguriert werden: Listing 4.37 Gravatar-Konfiguration // Größe des Gravatars in Pixel plugin.tx_elublog_pi1.singleView.comment.gravatar_size = 40 // URL des Standardbildes plugin.tx_elublog_pi1.singleView.comment.gravatar_default_url = http://example.com/fileadmin/elublog/gravatar.png
Diese Parameter werden an die API zusammen mit dem MD5-Hash der Mail-Adresse übermittelt. Das Ergebnis wird in ein -Tag eingebaut.
Abbildung 4.7 Die Ausgabe der Kommentare mit Gravataren
117
4 Frontend-Plug-ins
4.4.2
Das Kommentarformular hinzufügen
Auch für das Formular haben wir bereits eine Funktion vorbereitet. Diese heißt $this-> getCommentForm(). Das Formular selbst bauen wir als HTML-Vorlage auf. Darin werden
nur ein paar Labels zum Substituieren sein. Listing 4.38 $this->getCommentForm() function getCommentForm() { /* ###### Platzhalter für AJAX-Funktionalität ###### */ $markerArray['###LABEL_COMMENTFORM###'] = $this-> pi_getLL('label_commentform'); $markerArray['###LABEL_COMMENTFORM_AUTHOR###'] = $this-> pi_getLL('label_commentform_author'); $markerArray['###LABEL_COMMENTFORM_AUTHOREMAIL###'] = $this-> pi_getLL('label_commentform_authoremail'); $markerArray['###LABEL_COMMENTFORM_WEBSITE###'] = $this-> pi_getLL('label_commentform_website'); $markerArray['###LABEL_COMMENTFORM_COMMENT###'] = $this-> pi_getLL('label_commentform_comment'); $markerArray['###LABEL_COMMENTFORM_SUBMIT###'] = $this-> pi_getLL('label_commentform_submit'); $markerArray['###BID###'] = $this->internal['currentRow']['bid']; $markerArray['###BLOGENTRY###'] = $this->internal['currentRow']['uid']; $markerArray['###DATEFORMAT###'] = $this->conf['singleView.'] ['comment.']['dateFormat']; $template['commentform'] = $this->cObj->getSubpart($this-> templateFile,'###COMMENTFORMSET###'); $content = $this->cObj->substituteMarkerArrayCached ($template['commentform'],$markerArray); return $content; }
In den Platzhalter am Anfang der Funktion setzen wir gleich die AJAX-Funktionalität ein. Die Übersetzung der Labels kommt wieder aus locallang.xml. Listing 4.39 locallang.xml Senden
Das Formular selbst ist unspektakulär. Es enthält die erforderlichen Felder und Labels. Die einzige Besonderheit ist die Abwesenheit eines -Tags. Das Formular wird mit einem onclick-Event getriggert. Listing 4.40 HTML-Template-Vorlage
Nun fehlt allerdings noch die komplette AJAX-Funktionalität. Im Prinzip wollen wir die Eingaben des Formulars zum Server übertragen, wo sie in die Datenbank geschrieben werden. Quasi als Bestätigung, sollen die Daten zurück zum Skript geschickt und als neuer Kommentar dargestellt werden. Ab Version 4.3 wird TYPO3 mit dem ExtJS JavaScript-Framework ausgeliefert. ExtJS ist ein sehr mächtiges Framework, das wir für unsere Zwecke einsetzen möchten. Wir nutzen es für den AJAX-Request selbst, um dafür den zurückgelieferten Kommentar unter den bestehenden anzufügen. Der Vorteil, wie wir gleich sehen werden, ist der, dass wir dazu wieder das Template aus der Template-Vorlage verwenden können. Natürlich kann das Beispiel auch mit anderen Frameworks oder sogar nur mit eigenem JavaScript-Code umgesetzt werden. Fügen Sie Listing 4.41 und Listing 4.42 in den Platzhalter aus Listing 4.38 ein. Da wir die Template-Vorlage, die schon besteht, verwenden wollen, müssen wir diese laden und die Marker substituieren. Da die Inhalte aber erst auf dem Client nach dem AJAXRequest bereitstehen, substituieren wir sie wiederum mit eigenen Markern für ExtJS. Listing 4.41 Template-Vorlage für ExtJS erstellen $cObj = t3lib_div::makeInstance('tslib_cObj'); $gravatar_size = $this->conf['singleView.']['comment.'] ['gravatar_size']; $gravatar_default = $this->conf['singleView.']['comment.'] ['gravatar_default_url']; $template['comment'] = $this->cObj->getSubpart($this-> templateFile,'###COMMENT###'); $template['item'] = $this->cObj->getSubpart($this-> templateFile,'###COMMENTITEM###'); $fixedMarkerArray['###AT###'] = $this->pi_getLL('at'); $markerArray['###COMMENTNUMBER###'] = $cObj-> stdWrap('{commentnumber}',$this->conf['singleView.']['comment.']
119
4 Frontend-Plug-ins ['number_stdWrap.']); $markerArray['###COMMENTAUTHOR###'] = $cObj->stdWrap('{commentauthor}', $this->conf['singleView.']['comment.']['author_stdWrap.']); $markerArray['###COMMENTTEXT###'] = $cObj->stdWrap('{comment}',$this-> conf['singleView.']['comment.']['comment_stdWrap.']); $markerArray['###COMMENTDATE###'] = $cObj->stdWrap('{commentdate}', $this->conf['singleView.']['comment.']['crdate_stdWrap.']); $markerArray['###GRAVATAR###'] = $cObj->stdWrap('{commentemail}', $this->conf['singleView.']['comment.']['gravatar_stdWrap.']); $markerArrayMerged = array_merge($markerArray,$fixedMarkerArray); $html = str_replace("\n",'','' .$this->cObj->substituteMarkerArrayCached($template['item'], $markerArrayMerged).'');
Wir lesen die Einstellungen für die Gravatar-Darstellung ein. Dann geht es an das Substituieren. Am Beispiel ###COMMENT### sieht man, dass der Marker durch {comment} ersetzt wird, nachdem ein stdWrap darauf angewendet wurde. Auch ist ersichtlich, dass der Subpart ###COMMENT### nicht verwendet wird, sondern nur der tiefer liegende ###ITEM###. Listing 4.42 Das JavaScript $js = "<script type=\"text/javascript\">/*
120
4.4 Die Kommentarfunktion mit AJAX und eID Ext.get('tx_elublog_commentform_author').dom.value = ''; Ext.get('tx_elublog_commentform_authoremail').dom.value = ''; Ext.get('tx_elublog_commentform_website').dom.value = ''; Ext.get('tx_elublog_commentform_comment').dom.value = ''; } else { Ext.get('tx_elublog_comment_status').update('<span class=\"comment_update_fail\">".$this->pi_getLL ('comment_status_dbfail')."'); } }, failure: function(xhr,params) { Ext.get('tx_elublog_comment_status').update('<span class=\"comment_update_fail\">".$this->pi_getLL ('comment_status_fail')."'); }}) }); });// --> ";
Da JavaScript nur am Rande mit der Extension-Programmierung zu tun hat, gehen wir auf das Skript nur kurz ein. Die Funktion Ext.Ajax.request() löst einen AJAX-Request mit den übergebenen Parametern aus. Der Parameter params enthält ein Array mit den zu übergebenden Parameter an das Zielskript. Diese werden aus den Values der Input-Felder ausgelesen. Im Erfolgsfall wird das Template, das zuvor erzeugt und in die Variable $html geschrieben wurde, mit den Rückgabeparametern befüllt und in den Div-Container tx_elublog_ newcomment eingehängt. Im Fehlerfall wird die Statusmeldung mit einem Fehler ausgegeben. Der AJAX-Request wird an die URL index.php?eID=tx_elublog_eid gesendet. Der Parameter eID stellt eine Besonderheit dar. Ist er gesetzt, wird der Frontend-RenderingProzess abgebrochen und die Klasse tslib_eidtools eingebunden. eID-Skripte sind etwas schwieriger zu programmieren, da viele Klassen nicht zur Verfügung stehen, dazu gehören zum Beispiel auch die tslib_pibase und tslib_cObj. Da wir aber nur den Zugriff auf die Datenbank und den FE-User benötigen, stellt das kein Problem dar. Neu in TYPO3 4.3
Wie gesagt, stehen in eID-Skripten nicht alle Funktionen zur Verfügung. Mit „FOUR3“ kommen aber ein paar Änderungen: Mit tslib_eidtools::initLanguage() wird die Sprachunterstützung bereitgestellt. Mit tslib_eidtools::initTCA() wird das TCA geladen. Und mit tslib_eidtools::getTSFE() wird die Frontend-Klasse geladen. Somit können diese Funktionalitäten ebenfalls in eID-Skripten verwendet werden.
Listing 4.43 Die eID-Datei
Als Ergebnis liefert das Skript einen JSON-String zurück, der von JavaScript mittels eval() in ein Array zurückverwandelt und ausgegeben wird. Da eID-Skripte nicht den ganzen Rendering-Prozess durchlaufen, und nur ein ganz kleiner Teil des TYPO3-Frameworks geladen wird, sind sie bedeutend schneller und ressourcen-
122
4.5 Was sind Hooks? schonender, als wenn wir direkt ein Plug-in abgefragt hätten. Das prädestiniert sie für AJAX-Abfrageskripte, auch wenn nicht die ganze Funktionalität verfügbar ist. Es besteht natürlich immer noch die Möglichkeit, einzelne Klassen zu inkludieren.
Abbildung 4.8 Ein neuer Kommentar wurde eingegeben.
4.5
Was sind Hooks? Es kann nötig sein, eine bestehende Extension um Funktionalität zu erweitern oder bestehende Funktionen zu ändern. Damit andere Programmierer das möglichst einfach tun können, werden sogenannte Hooks eingebaut. Hooks sind im Grunde Einsprungmarken, über die eine Extension erweitert wird. Wenn eine Extension eine andere Extension – oder auch den Core – mit einer Hook-Funktion erweitert, wird diese in der Datei ext_localconf.php
123
4 Frontend-Plug-ins registriert. Das Plug-in, das erweitert wird, führt eine Schleife über die Registrierung aus und ruft über t3lib_div::callUserFunc() die entsprechende Funktion auf. Listing 4.44 Registrierung einer Hook-Funktion $TYPO3_CONF_VARS['EXTCONF']['hooked_extkey']['nameDesHooks'] [$_EXTKEY] = 'EXT:'.$_EXTKEY. '/class.tx_extkey_hooks.php:tx_extkey_hooks->hookFunc';
“hooked_extkey” ist hierbei durch den Extension-Key der zu hookenden Extension zu ersetzen. Damit Hooks überhaupt verwendet werden können, müssen sie erst einmal vorhanden sein. Hier beginnen die Überlegungen, wo Hooks überhaupt sinnvoll sind. Da wäre zum Beispiel:
Hooks, um Marker in der Einzel- und Listenansicht hinzuzufügen oder zu ändern. Ein Hook, bevor ein Kommentar in die Datenbank geschrieben wird. Eine Möglichkeit, die sofort ins Auge springt, ist die Überprüfung der Mail-Adresse. Wir wollen sichergehen, dass auch wirklich eine Mail-Adresse eingegeben wird. Mit einer Regex-Überprüfung ist das schnell erledigt. In diesem Fall müssen wir unsere eID-Funktion hooken. Der Hook kommt direkt nach dem Befüllen des Arrays $fields. Listing 4.45 Hook einbauen 'cruser_id' => $GLOBALS['TSFE']->fe_user->user['uid'], 'pid' => $this->extconf['storageId'] ); $checkError = 0; if (isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['elublog'] ['commentCheck'])){ foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['elublog'] ['commentCheck'] as $userFunc) { $params = array( 'fields' => $fields, 'pObj' => &$this ); $checkError = $checkError + t3lib_div::callUserFunction($userFunc,$params,$this); } } if ($checkError > 0) {die(json_encode(array('fail' => 1)));} if ($res = $GLOBALS['TYPO3_DB']->exec_INSERTquery ('tx_elublog_blogcomments',$fields)) {
Jede Hook-Funktion muss 0 zurückliefern, wenn alles in Ordnung ist. Jeder Fehler erhöht die Variable $checkError. Ist sie, nachdem alle Hook-Funktionen abgearbeitet sind, größer als 0, wird der Kommentar nicht in die Datenbank eingetragen. Um unseren Hook zu testen, legen wir eine neue Extension namens elublogmailcheck an. Dazu muss im Kickstarter nur der Punkt General info ausgefüllt werden. Speichern Sie die Extension ab, und legen Sie eine neue Datei namens ext_localconf.php im Verzeichnis der Extension an. Diese füllen Sie mit folgendem Inhalt:
124
4.6 Flexforms Listing 4.46 ext_localconf.php
Der Teil zwischen den PHP-Tags kommt in eine Zeile. Wie zu sehen ist, verweist die Hook-Registrierung auf die Datei class.tx_elublogmailcheck_hooks.php, der sich aus dem Dateinamen ergebenden Klasse und der Funktion hookFunc. Legen Sie also eine Datei namens class.tx_elublogmailcheck_hooks.php an. Listing 4.47 class.tx_elublogmailcheck_hooks.php
Die Funktion hookFunc() prüft die übermittelte Mail-Adresse mit einem RegexAusdruck. Wird damit eine Mail-Adresse erkannt, liefert die Funktion 0, ansonsten 1 zurück. Somit ist es möglich, verschiedenste Arten von Prüfungen zu realisieren.
4.6
Flexforms Es wäre toll, wenn sich einige Einstellungen leichter konfigurieren ließen als über TypoScript. Und vor allem für einzelne Plug-ins, wenn sich also Einstellungen im Plug-in selbst setzen ließen. Mit Flexforms ist das möglich. Folgende Einstellungen wollen wir hier konfigurierbar machen:
Die BlogID Seite für Einzelansicht (bei Listenansicht) Seite für Listenansicht (bei Einzelansicht) Anzahl der Beiträge pro Seite Länge der Voransicht Haupttext immer in Listenansicht anzeigen
Gerade der letzte Punkt ist wichtig, werden im Moment noch die Beiträge aller eingerichteten Blogs angezeigt. Eine Möglichkeit wäre, die Tabelle tt_content um die entsprechenden Felder zu erweitern. Allerdings darf man laut den TYPO3 Coding Guidelines ei-
125
4 Frontend-Plug-ins nige Tabellen nicht mehr auf Feldbasis erweitern. Wirft man einen Blick in die Feldstruktur von tt_content, sieht man auch den Grund: Die Tabelle ist so schon sehr groß, würde jede Extension weitere Felder hinzufügen, wächst die Tabelle extrem an. Die andere Möglichkeit bieten Flexforms. Dadurch werden alle Felder als XML-Struktur in dem Feld pi_flexform der tt_content-Tabelle gespeichert. Die Definition, wie die Felder angelegt werden – im Grunde handelt es sich um eine XML-Version der TCA –, wird als Flexform bezeichnet – für flexible Forms. Die XML-Struktur, die in der Datenbank abgespeichert wird und die Daten enthält, die durch die Flexform eingegeben wurden, nennt man DS bzw. Datenstruktur. Die DS kann von dem Plug-in wieder ausgelesen werden.
4.6.1
Erzeugen der Flexform
Um eine Flexform verwenden zu können, muss sie erst einmal aktiviert werden. Das geschieht in der Datei ext_tables.php. Fügen Sie folgende Zeilen am Ende der Datei, vor dem schließenden PHP-Tag, ein. Listing 4.48 Flexform aktivieren $TCA['tt_content']['types']['list']['subtypes']['subtypes_addlist'] [$_EXTKEY.'_pi1'] = 'pi_flexform'; t3lib_extMgm::addPiFlexFormValue($_EXTKEY.'_pi1', 'FILE:EXT:'.$_EXTKEY.'/flexform_ds_pi1.xml');
Um die Flexform zu erstellen, können Sie sich am TCA orientieren, da der Aufbau der Felder im Grunde gleich ist. Listing 4.49 Input-Feld im TCA 'author' => array ( 'exclude' => 0, 'label' => 'LLL:EXT:elublog/locallang_db.xml:tx_elublog_blogentrys.author', 'config' => array ( 'type' => 'input', 'size' => '30', ) ),
Listing 4.50 Input-Feld als Flexform LLL:EXT:elublog/locallang.xml:label.author input <size>30
Die Grundstruktur der Flexform sieht folgendermaßen aus:
126
4.6 Flexforms Listing 4.51 Grundstruktur array <el> < … Elemete … >
Der Node <el> ist ein Platzhalter für den Namen des Elements. Im Beispiel des Elements aus Listing 4.50 wäre das . Es ist möglich, die Elemente auf verschiedenen Tabs aufzuteilen: Listing 4.52 Struktur mit Tabs <sheets> <sheet1> <sheetTitle>Sheet 1 array <el> < … Elemente … > <sheet2> <sheetTitle>Sheet 2 array <el> < … Elemente … >
Abbildung 4.9 Tabs im Flexform von tt_news
127
4 Frontend-Plug-ins Erstellen Sie für die Flexform die Datei flexform_ds_pi1.xml im Extension-Verzeichnis. Listing 4.53 flexform_ds_pi1.xml array <el> LLL:EXT:elublog/locallang.xml:fflabel.blogid select LLL:EXT:elublog/locallang.xml:fflabel.allBlogs 0 tx_elublog_blogs <listPage> LLL:EXT:elublog/locallang.xml:fflabel.listPage group db pages <size>1 <minitems>0 <maxsize>1 <show_thumbs>1 1 <singlePage> LLL:EXT:elublog/locallang.xml:fflabel.singlePage group db pages <size>1 <minitems>0 <maxsize>1 <show_thumbs>1 1 <entrysperpage> LLL:EXT:elublog/locallang.xml:fflabel.entrysperpage input <size>20 <max>40 <eval>int 1
128
4.6 Flexforms LLL:EXT:elublog/locallang.xml:fflabel.teaserCrop input <size>20 <max>40 <eval>trim 1 LLL:EXT:elublog/locallang.xml:fflabel.fullTextInList check
Die Labels werden wieder aus einer Übersetzungsdatei gefüllt. Öffnen Sie die Datei locallang.xml, und fügen Sie folgende Zeilen in die entsprechenden Übersetzungen ein. Listing 4.54 Übersetzung default Crop Teasertext after ...
Listing 4.55 Übersetzung Deutsch Angezeigter Blog Alle Blogs Seite für 'zurück' in Einzelansicht (leer für aktuelle Seite) Seite für Einzelansicht (leer für aktuelle Seite) Beiträge pro Seite in Listenansicht (0 für alle Teasertext nach ... Zeichen abschneiden
In Abbildung 4.10 sehen Sie das Ergebnis.
129
4 Frontend-Plug-ins
Abbildung 4.10 Flexform-Plug-in-Konfiguration
Nun müssen die Werte umgesetzt werden. In der Listenansicht sind alle Einstellungen bis auf „Seite für ‚zurück’ in Einzelansicht“ von Bedeutung. Um auf den Wert eines FlexForm-Feldes zuzugreifen, wird die Funktion pi_getFFvalue() verwendet. Listing 4.56 Zugriff auf die Flexform $var = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'element','sDEF');
Das Wort element entspricht dabei dem Namen des Feldes. In der Funktion $this-> listView() wird bestimmt, welcher Blog abgefragt wird, wie viele Beiträge pro Seite an-
gezeigt werden und auf welche Seite für die Einzelansicht verlinkt wird. Listing 4.57 Parameter bestimmen $entrysperpage = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'entrysperpage','sDEF'); $entrysperpage ($entrysperpage > 0) ? $entrysperpage : $this-> conf['listView.']['entrysPerPage']; $entrysperpage ($entrysperpage > 0) ? $entrysperpage : 10; $bid = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'bid', 'sDEF'); $bidmm = ($bid > 0) ? 'AND tx_elublog_blogentrys.bid='.$bid : ''; $bid = ($bid > 0) ? 'AND bid='.$bid : ''; $singleViewPID = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'singlePage','sDEF'); $singleViewPID = ($singleViewPID) ? $singleViewPID : $this-> conf['singleViewPID']; $this->singleViewPID = ($singleViewPID) ? $singleViewPID : 0;
Wenn in der Plug-in-Konfiguration kein Wert für die Beiträge pro Seite eingegeben wurde, wird der Wert aus der TypoScript-Konfiguration übernommen. Ist auch dieser leer, wird der Wert 10 verwendet. Genauso verhält es sich bei der Seiten-ID der Einzelansicht.
130
4.6 Flexforms Die Blog-ID (bid) der Plug-in-Konfiguration liefert die ID des darzustellenden Blogs. Diese wird in eine Erweiterung der WHERE-Klausel eingebaut, die bei der SQL-Abfrage nach den Blogbeiträgen angehängt wird. Diese Klausel sorgt dafür, dass nur Beiträge des gewählten Blogs selektiert werden. Wird der Wert 0 (alle Blogs) geliefert, wird nichts angehängt und die SQL-Abfrage demnach auch nicht auf einen Blog eingeschränkt. Damit der Wert in $entrysperpage verwendet wird, müssen wir folgende Änderung in derselben Funktion durchführen: Listing 4.58 Entrys per Page setzen // Suchen Sie folgende Zeile: $this->internal['results_at_a_time']=t3lib_div::intInRange($lConf ['results_at_a_time'],0,1000,3);
Die „3“ am Ende der Zeile ersetzen Sie mit $entrysperpage. Um die Blog-ID an die SQL-Abfrage zu übergeben, modifizieren Sie folgende Zeilen: Listing 4.59 Blog-ID setzen $res = $GLOBALS['TYPO3_DB']->exec_SELECT_mm_query('count (tx_elublog_blogentrys.uid)','tx_elublog_blogentrys','tx_elublog_blogentr ys_category_mm','tx_elublog_blogcategorys',$bidmm.' AND tx_elublog_blogentrys_category_mm.uid_foreign='.$this->piVars ['showCat']); $res = $this->pi_exec_query('tx_elublog_blogentrys',1,$bid); $res = $GLOBALS['TYPO3_DB']->exec_SELECT_mm_query('tx_elublog_blogentrys .*','tx_elublog_blogentrys','tx_elublog_blogentrys_category_mm','tx_elubl og_blogcategorys',$bidmm.' AND tx_elublog_blogentrys_category_mm .uid_foreign='.$this->piVars['showCat']); $res = $this->pi_exec_query('tx_elublog_blogentrys',0,$bid);
Fügen Sie jeweils die fett geschriebenen Teile hinzu. In der Funktion $this->getFieldContent() ändern Sie die Titelverarbeitung: Listing 4.60 Titel mit SingleViewPID verlinken case "title": return $this->pi_list_linkSingle($this->internal['currentRow'] [$fN],$this->internal['currentRow']['uid'],1,'','',$this->singleViewPID); break;
Um den „Zurück“-Link in der Einzelansicht mit der Seite für die Listenansicht zu verknüpfen, fügen Sie in die Funktion $this->singleView() folgende Zeilen am Anfang ein: Listing 4.61 Konfiguration auslesen $listViewPID = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'listPage','sDEF'); $listViewPID = ($listViewPID) ? $listViewPID : $this->conf ['listViewPID']; $listViewPID = ($listViewPID) ? $listViewPID : 0;
131
4 Frontend-Plug-ins Ist weder im Plug-in noch im TypoScript eine Seite für die Listenansicht definiert, wird 0 zurückgegeben. Das entspricht der aktuellen Seite. Auch der Marker für den Link muss angepasst werden. Listing 4.62 „Zurück“-Marker anpassen $markerArray['###BACKLINK###'] = $cObj->stdWrap($this-> pi_linkToPage($this->pi_getLL('back','Back'),$listViewPID),$this-> conf['singleView.']['backLink_stdWrap.']);
Ob in der Listenansicht der Teasertext beschnitten wird, wird ebenso wie die Anzeige des kompletten Blogbeitrags in der Funktion $this->pi_list_row() abgefragt. Folgende Zeilen gehören an den Anfang der Funktion: Listing 4.63 Die Konfiguration einlesen $tcrop = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'teaserCrop','sDEF'); $fullTextInList = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'fullTextInList','sDEF');
Dadurch ist eine Änderung der Marker-Zuweisung nötig. Listing 4.64 Marker neu zuweisen $markerArray['###BODYTEXT###'] = (($this->getFieldContent ('bodytextinlist') == 1) || ($fullTextInList == 1)) ? $cObj->stdWrap ($this->getFieldContent('bodytext'),$this->conf['listView.'] ['bodytext_stdWrap']) : ''; … $markerArray['###TEASERTEXT###'] = $cObj->stdWrap($this->cObj>crop($this->getFieldContent('teasertext'),$tcrop),$this>conf['listView.']['teasertext_stdWrap.']);
Damit ist das Plug-in fertig für den Einsatz.
4.7
Das Plug-in pi2 Nun sollten Sie in der Lage sein, das Plug-in selbst zu erstellen. Ein paar Hinweise und Anregungen. Das Plug-in soll folgende Module bereitstellen können:
Eine Liste aller Kategorien Eine Liste aller Tags Die letzten Kommentare Die Blogroll
Verwenden Sie die Plug-in-Konfiguration, um festzulegen, welches Modul dargestellt werden soll und von welchem Blog. Werten Sie die Modulwahl mit switch/case aus, und erstellen Sie für jedes Modul eine eigene Funktion. Alle Module lassen sich mit den eben gelernten Standard-Datenbankabfragen erstellen.
132
5 5
Dokumentation und Abschluß
Jede Extension sollte ausreichend dokumentiert sein. Das betrifft nicht nur die ExtensionDokumentation, die genau erklären muss, wie die Extension verwendet wird, sondern auch den Code, der auch für andere Entwickler nachvollziehbar sein soll.
5.1
Code dokumentieren mit extdeveval Die Extension extdeveval bringt viele nützliche Funktionen für Extension-Entwickler mit. Dazu gehört auch eine Hilfe für die Code-Dokumentation nach dem phpDoc-Format. Nach der Installation finden Sie ein neues Modul bei den Admin-Werkzeugen:
Abbildung 5.1 extdeveval im Menü
Wählen Sie im Funktionsmenü des Moduls PHP script documentation help. Sie werden nun aufgefordert, eine Extension – in diesem Fall elublog – zu wählen. Dann erhalten Sie eine Liste aller Dateien. Nun können Sie alle relevanten Dateien, wie Plug-in-Klassendateien und Moduldateien, durchgehen. Die Änderungen, die ausgeführt werden, werden anhand verschiedener Farben dargestellt. Es wird ein Inhaltsverzeichnis aller Funktionen angelegt. Jede Funktion erhält einen Kommentarkopf mit einer Dummy-Beschreibung aller Parameter und des Rückgabewertes. Die korrekte Beschreibung muss nur noch hinzugefügt werden. Wenn Sie später Änderungen hinzufügen, führen Sie die Funktion einfach wieder aus, um den Funktionsindex zu aktualisieren. Durch die Zeilenangabe findet man gerade in großen Extensions leichter das Gesuchte. Die Beschreibung der Parameter und Rückgabewerte ist wichtig, um nicht erst die ganze Funktion zerpflücken zu müssen, um herauszufinden, was die Funktion erwartet und zurückgibt.
133
5 Dokumentation und Abschluß Listing 5.1 Funktionsübersicht der Datei mod2/index.php /** * [CLASS/FUNCTION INDEX of SCRIPT] * * * * 59: class tx_elublog_module2 extends t3lib_SCbase * 67: function init() * 84: function menuConfig() * 100: function main() * 125: function jumpToUrl(URL) * 168: function printContent() * 179: function moduleContent() * 196: function getNewPostButton() * 213: function getPostList() * 273: function getFunctions($table,$row) * * TOTAL FUNCTIONS: 9 * (This index is automatically created/updated by the extension "extdeveval") * */
Innerhalb der Funktion sollten Sie ebenfalls Kommentare hinterlassen, um bestimmte Abschnitte zu dokumentieren.
5.2
Extension-Dokumentation schreiben Auch wenn man gerade Männern nachsagt, nie Handbücher zu lesen, so ist eine ausführliche Dokumentation unerlässlich. Sie zeigt dem Leser nicht nur auf, wie eine Extension funktioniert, sondern auch, welche Möglichkeiten der Konfiguration zur Verfügung stehen. Nicht wenige Integratoren lehnen es ab, Extensions ohne Dokumentation zu installieren. Verwenden Sie also auf die Dokumentation dieselbe Sorgfalt wie auf die Programmierung.
Abbildung 5.2 Extensions ohne swx-Datei im /doc-Verzeichnis erzeugen einen Render-Fehler im TER.
134
5.2 Extension-Dokumentation schreiben
5.2.1
Die Vorlage
Die Dokumentation wird nicht nur in der Extension mitgeliefert, sondern auch online verfügbar gemacht. Dazu rendert das TER die Dokumentation. Nach dem Upload einer Extension steht sie nach kurzer Zeit automatisch unter http://typo3.org/documentation/document-library/extension-manuals und bei den einzelnen Extensions unter http://typo3.org/extensions/repository zur Verfügung. Aus diesem Grund muss die Dokumentation aus einer eigenen Vorlage heraus erstellt werden. Um diese Vorlage nutzen zu können, benötigen Sie OpenOffice1. Laden Sie die Vorlage von http://typo3.org/documentation/document-library/core-documentation/doc_template/current/ herunter, öffnen Sie sie in OpenOffice, und speichern Sie sie als Vorlage ab. Dokumentationen werden im /doc-Verzeichnis der Extension als OpenOffice 1.0-Dokument (.swx) abgelegt.
5.2.2
Der Aufbau der Dokumentation
Die Dokumentation hat einen vorgegebenen Aufbau, von dem nicht abgewichen werden sollte. Sie sollten nicht benötigte Abschnitte aber entfernen. Das Dokument gliedert sich in folgende Abschnitte:
Inhaltsangabe Introduction: Eine kurze Erklärung, was die Extension macht. Hier können auch Screenshots, beispielsweise von der Frontend-Ausgabe, hinterlegt werden.
Users Manual: Erklärt, wie die Extension vom Integrator und von den FrontendBenutzern verwendet wird.
Administration: Erklärt Installation, Systemvoraussetzungen und Wartung für den Administrator, einschließlich der Extension-Konfiguration über den Extension-Manager.
Configuration: In diesem Abschnitt wird die Konfiguration erklärt. Dazu gehört eine vollständige Auflistung aller TypoScript-Eigenschaften und der Plug-in-Konfiguration.
Tutorial: Eine kurze und einfache Einführung in die Extension. Am besten anhand eines Beispiels.
Known Problems: Probleme und Inkompatibilitäten, die dem Autor bekannt sind. To-Do list: Eine optionale Liste der Aufgaben und Features, die noch offen sind und in einer der späteren Versionen gelöst sein sollen.
Changelog: Dieser Abschnitt enthält die Änderungen an der Extension, sollte aber nicht mehr verwendet werden. Verwenden Sie für das Changelog stattdessen die Datei Change Log im Extension-Verzeichnis. Weisen Sie in der Dokumentation nur auf diese Datei hin. 1
http://www.openoffice.org
135
5 Dokumentation und Abschluß Nicht jede Extension benötigt alle diese Abschnitte. Wird ein Abschnitt nicht benötigt, löschen Sie ihn. Das sorgt wiederum für Übersicht in der Online-Dokumentation.
5.2.3
Vorlagenstile
Das TER rendert die Vorlage auf Basis der eingesetzten Stile. Dazu wurde ein Satz eigener Stile erstellt, der zu verwenden ist. Alle anderen Stile werden beim Rendern ignoriert. Tabelle 5.1 Stile in der Vorlagendatei Stil
Verwendung
Text body
Der Standardstil. Dieser kommt im normalen Text zum Tragen.
Table heading
Wird für Tabellenüberschriften verwendet
Table contents
Stil für den Tabelleninhalt
Preformatted text
Codebeispiele, TypoScript u.Ä. werden mit diesem Stil ausgezeichnet.
Heading 1
Überschriften für die Hauptabschnitte. Das TER rendert für jeden Hauptabschnitt eine neue HTML-Seite.
Heading 2
Für die Abschnitte innerhalb der Hauptabschnitte
Heading 3
Weitere Untergliederung
Heading 4
Letzte Ebene der Untergliederung
Source text
Eingefügte Codefragmente werden in diesem Stil dargestellt.
Die Verwendung von Bildern in der Dokumentation erfordert, dass die Bilder in das Dokument eingefügt werden und nicht nur darauf verwiesen wird. Dazu wählen Sie im Menü Bearbeiten > Inhalte einfügen. In dem folgenden Dialog wählen Sie Bitmap.
5.2.4
Die Dokumentation verfassen
Wenn Sie sich schließlich an das Schreiben der Dokumentation machen, behalten Sie immer im Hinterkopf, dass nicht alle Leser denselben Wissensstand wie Sie selbst haben. Gerade Anfänger sind schnell frustriert, wenn Wissen vorausgesetzt wird, das ein Anfänger noch nicht haben kann. Sie müssen keinen ausgewachsenen Roman schreiben, aber wenn Sie unsicher sind, ob Sie ein bestimmtes Detail beschreiben sollen oder nicht, sollten Sie es lieber tun. Auch Screenshots sollten nicht fehlen. Versuchen Sie, die Extension allgemeinverständlich zu beschreiben.
136
5.3 Upload ins TER
5.3
Upload ins TER Ist die Extension fertig und dokumentiert, wird es Zeit, sie in TER hochzuladen. Klicken Sie im Extension-Manager auf Ihre Extension, und wählen Sie im Extension-Menü Upload to TER. Im folgenden Dialog sollten Sie eine kurze Zusammenfassung der Änderungen formulieren. Hier wird auch die Versionsnummer gesetzt. Wenn Ihre Extension genau das tut, was Sie von ihr erwarten, scheuen Sie sich nicht, eine Hauptversion 1.0.0. zu setzen. Sollten Bugs auftauchen (was bei praktisch jeder größeren Software der Fall ist), können Sie die Versionsnummer immer noch als Bug-Fix-Version anheben.
Abbildung 5.3 Upload ins TER
Nach dem Upload wird die Extension im TER zur Verfügung gestellt und taucht im Extension-Manager auf, sofern die Extension-Liste upgedatet wurde. Bis die Dokumentation online erscheint, kann es aber ein wenig dauern. Gratulation, Ihre Extension ist fertig!
137
II Teil II – Funktionsreferenz zur klassischen Extensionprogrammierung
6 6
Datenbank
6.1 $GLOBALS['TYPO3_DB'] Insbesondere beim Zugriff auf Datenbanken ist darauf zu achten, dass ausschließlich die TYPO3-eigenen Datenbank-Handler verwendet werden. Die Klasse t3lib_DB bildet hierfür das sogenannte Datenbank-Abstraktions-Layer (DBAL). Sie ist sowohl im Backend als auch im Frontend in $GLOBALS['TYPO3_DB'] instanziiert.
6.1.1
exec_SELECTquery
$GLOBALS['TYPO3_DB']->exec_SELECTquery($select_fields, $from_table, $where_clause, $groupBy='', $orderBy='', $limit='');
Diese Methode führt eine Select-Abfrage aus und gibt ein Datenbankobjekt zurück. Das Objekt kann dann mittels sql_fetch_assoc oder sql_fetch_row in ein assoziatives Array umgewandelt werden (nicht mysql_fetch_assoc). Listing 6.1 Abfrage aller Frontend-User, die gerade angemeldet sind $selectRes = $GLOBALS['TYPO3_DB']->exec_SELECTquery('username', 'fe_users', 'disable = 0 AND is_online = 1');
6.1.2
exec_SELECT_queryArray
$GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($queryParts);
Dies ist eine Abwandlung von exec_SELECTquery, durch die gute Lesbarkeit vor allem für komplexere Abfragen sehr zu empfehlen.
141
6 Datenbank Listing 6.2 Abfrage aller Frontend-User, die gerade angemeldet sind $selectRes = $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray(array( 'SELECT' => 'username', 'FROM' => 'fe_users', 'WHERE' => 'disable = 0 AND is_online = 1', 'GROUPBY' => '', 'ORDERBY' => '', 'LIMIT' => '' ));
6.1.3
exec_SELECTgetRows
$GLOBALS['TYPO3_DB']->exec_SELECTgetRows($select_fields, $from_table, $where_clause, $groupBy='', $orderBy='', $limit='', $uidIndexField='');
Führt eine Select-Abfrage aus und gibt ein assoziatives Array mit allen Ergebnissen zurück. Sehr interessant ist vor allem der letzte Parameter $uidIndexField. Falls die Abfrage ein eindeutiges Feld enthält wie z.B. uid, so werden die Keys des ausgegebenen Arrays mit diesem Feld gefüllt. Listing 6.3 Abfrage aller Frontend-User, die gerade angemeldet sind $selectRows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid, username', 'fe_users', 'disable = 0 AND is_online = 1', '', '', '','uid');
6.1.4
exec_SELECT_mm_query
$GLOBALS['TYPO3_DB']->exec_SELECT_mm_query($select, $local_table, $mm_table, $foreign_table, $whereClause='', $groupBy='', $orderBy='', $limit='');
Dient zur Abfrage von n-n-Beziehungen zwischen $local_table und $foreign_table. Verknüpft sind die beiden Tabellen über $mm_table. Zu beachten ist vor allem bei gleichnamigen Feldern in $local_table und $foreign_table wie etwa uid oder pid, dass hierfür entsprechende Aliasse in $select vergeben werden. Listing 6.4 Beispiel $selectRes = $GLOBALS['TYPO3_DB']->exec_SELECT_mm_query( 'product, name', 'tx_extkey_products', 'tx_extkey_products_category_mm', 'tx_extkey_categories'); while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($selectRes)) { $content.= $row['product'].':'.$row['name'].'
'; } /* Ergebnis in $content: Kaffee:Arabica Kaffee:Robusta */
142
6.1 $GLOBALS['TYPO3_DB']
6.1.5
exec_INSERTquery
$GLOBALS['TYPO3_DB']->exec_INSERTquery($table, $fields_values, $no_quote_fields=FALSE);
Fügt einen Datensatz in die Tabelle $table mit den im Array $field_values definierten Werten ein. Listing 6.5 Beispiel $GLOBALS['TYPO3_DB']->exec_INSERTquery('fe_users', array( 'username' => 'mickey', 'password' => 'start123', 'usergroup' => '4', 'name' => 'Mickey Maus', 'tstamp' => time() ));
6.1.6
exec_UPDATEquery
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, $where, $fields_values, $no_quote_fields=FALSE);
Führt ein SQL Update auf $table aus. Die Bedingungen werden in $where definiert und die zu aktualisierenden Felder im Array $fields_values. Listing 6.6 Beispiel $GLOBALS['TYPO3_DB']->exec_UPDATEquery('fe_users', 'username = \'mickey\'', array('disable' => '1'));
6.1.7
exec_DELETEquery
$GLOBALS['TYPO3_DB']->exec_DELETEquery($table, $where);
Führt ein SQL Delete auf $table aus. Die Bedingungen werden in $where definiert. Listing 6.7 Beispiel $GLOBALS['TYPO3_DB']->exec_DELETEquery('fe_users', 'username = \'mickey\'');
6.1.8
sql_fetch_assoc
$GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
Pendant zu mysql_fetch_assoc; um den Datenbank-Handler geschlossen im TYPO3-Core zu belassen, sollte auch unbedingt diese Methode genutzt werden.
143
6 Datenbank Listing 6.8 Beispiel: alphabetisch sortierte Liste aller User, die derzeit online sind $selectRes = $GLOBALS['TYPO3_DB']->exec_SELECTquery('username', 'fe_users', 'disable = 0 AND is_online = 1', '', 'username'); $usersOnline = array(); while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($selectRes)) { $usersOnline[] = $row['username']; }
6.1.9
sql_fetch_row
$GLOBALS['TYPO3_DB']->sql_fetch_row($res);
Siehe mysql_fetch_assoc, Pendant zu mysql_fetch_row.
6.1.10
searchQuery
$GLOBALS['TYPO3_DB']->searchQuery($searchWords,$fields,$table);
Erzeugt eine SQL-Abfragebedingung, um in mehreren Datenbankfeldern $fields nach den Suchbegriffen $searchWords zu suchen. Listing 6.9 Suche in den Feldern „username“ und „name“ nach „peter“ und „muster“ $whereClause = $GLOBALS['TYPO3_DB']->searchQuery(array('peter', 'muster'),array('name', 'username'), 'fe_users'); /* Ergebnis in $whereClause: (fe_users.name LIKE '%peter%' OR fe_users.username LIKE '%peter%') AND (fe_users.name LIKE '%muster%' OR fe_users.username LIKE '%muster%') */
6.1.11
listQuery
$GLOBALS['TYPO3_DB']->listQuery($field, $value, $table);
Erzeugt eine SQL-Abfragebedingung, um in kommaseparierten Listen nach einem bestimmten Wert $value zu suchen. Die kommaseaprierte Liste steht hierbei im Feld $field in der Tabelle $table. Listing 6.10 Suche im Listenfeld „Hersteller“ nach der Herstellernummer „25“ $whereClause = $GLOBALS['TYPO3_DB']->listQuery('hersteller', '25', 'tx_t3ref_produkte'); /* Ergebnis in $whereClause:
144
6.1 $GLOBALS['TYPO3_DB'] (hersteller LIKE '%,25,%' OR hersteller LIKE '25,%' OR hersteller LIKE '%,25' OR hersteller='25') */
6.1.12
splitGroupOrderLimit
$GLOBALS['TYPO3_DB']->splitGroupOrderLimit($str);
Zerlegt eine SQL-Abfrage in ein Array, optimal für exec_SELECT_queryArray. Listing 6.11 Beispiel $selectArr = $GLOBALS['TYPO3_DB']->splitGroupOrderLimit( "hersteller = '25' and lagerbestand > 0 group by menge limit 0,100"); /* Ergebnis in $selectArr: Array ( [WHERE] => hersteller = '25' and lagerbestand > 0 [GROUPBY] => menge [ORDERBY] => [LIMIT] => 0,100 ) */
6.1.13
quoteStr
$GLOBALS['TYPO3_DB']-> quoteStr($str, $table);
Ersatz der PHP-Funktion addslashes(). Listing 6.12 Beispiel mit Suchtext: Peter „PM“ Muster $quoteString = $GLOBALS['TYPO3_DB']-> quoteStr('Peter "PM" Muster', 'fe_users'); /* Ergebnis in $quoteString: Peter \"PM\" Muster */
6.1.14
fullQuoteStr
$GLOBALS['TYPO3_DB']-> fullQuoteStr($str, $table);
Wie quoteStr, jedoch mit slashes vor und hinter dem String.
145
6 Datenbank Listing 6.13 Beispiel mit Suchtext: Peter „PM“ Muster $quoteString = $GLOBALS['TYPO3_DB']-> fullQuoteStr('Peter "PM" Muster', 'fe_users'); /* Ergebnis in $quoteString: 'Peter \"PM\" Muster' */
6.1.15
fullQuoteArray
$GLOBALS['TYPO3_DB']->fullQuoteArray($arr, $table, $noQuote=FALSE);
Erweitert fullQuoteStr um die Funktionalität, ein Array abzuarbeiten. Wird Parameter $noQuote gefüllt (String oder Array), so können bestimmte Keys im Array ausgeschlossen werden, z.B. für Datenbankfelder. Listing 6.14 Beispiel mit zwei Suchtexten $quoteArray = $GLOBALS['TYPO3_DB']-> fullQuoteArray(array('Peter "PM" Muster', 'Eva "EM" Muster'), 'fe_users'); /* Ergebnis in $quoteArray: Array ( [0] => 'Peter \"PM\" Muster' [1] => 'Eva \"EM\" Muster' ) */
Listing 6.15 Beispiel mit einem Suchtext und $noQuote $quoteArray = $GLOBALS['TYPO3_DB']-> fullQuoteArray(array('select' => 'name, username', 'where' => 'Peter "PM" Muster'), 'fe_users', 'select'); /* Ergebnis in $quoteArray: Array ( [select] => name, username [where] => 'Peter \"PM\" Muster' ) */
6.1.16
escapeStrForLike
$GLOBALS['TYPO3_DB']->escapeStrForLike($str, $table);
Die Zeichen _ und % werden maskiert. Listing 6.16 Beispiel mit 100% $escapeString = $GLOBALS['TYPO3_DB']->escapeStrForLike('100%', 'tx_t3ref_bewertungen');
146
6.1 $GLOBALS['TYPO3_DB'] /* Ergebnis in $escapeString: 100\% */
6.1.17
cleanIntArray
$GLOBALS['TYPO3_DB']->cleanIntArray($arr);
Alle Werte in einem eindimensionalen Array werden in Integer-Werte umgewandelt. Listing 6.17 Beispiel $intArr = $GLOBALS['TYPO3_DB']->cleanIntArray(array(100,'69.99','5,5')); /* Ergebnis in $intArr: Array ( [0] => 100 [1] => 69 [2] => 5 ) */
6.1.18
cleanIntList
$GLOBALS['TYPO3_DB']->cleanIntList($list);
Alle Werte in einer kommaseparierten Liste werden in Integer-Werte umgewandelt. Listing 6.18 Beispiel $intList = $GLOBALS['TYPO3_DB']->cleanIntList('100,69.99,5a2'); /* Ergebnis in $intList: 100,69,5 */
6.1.19
debug_lastBuiltQuery
$GLOBALS['TYPO3_DB']->debug_lastBuiltQuery;
Enthält die letzte erzeugte SQL-Abfrage. Hierfür muss eine der beiden folgenden Optionen gesetzt sein: $GLOBALS['TYPO3_DB']->store_lastBuiltQuery = true; oder $GLOBALS['TYPO3_DB']->debugOutput = true;
147
6 Datenbank Listing 6.19 Beispiel $debugQuery = $GLOBALS['TYPO3_DB']->debug_lastBuiltQuery; /* Ergebnis in $debugQuery: SELECT uid,username FROM fe_users WHERE disable = 0 AND is_online = 1 */
6.2 tslib_pibase Standardmäßig erweitert jedes Frontend-Plug-in die Klasse tslib_pibase. Hier finden sich einige praktische Funktionen, mit denen es möglich ist, bestimmte Abfragen in wenigen Zeilen Quellcode auszuführen.
6.2.1
pi_exec_query
$this->pi_exec_query($table, $count=0, $addWhere='', $mm_cat='', $groupBy='', $orderBy='', $query='');
Führt eine SQL-Abfrage aus, primär gedacht, um Datensätze innerhalb einer Seite abzufragen. Ist $query nicht gesetzt, so wird immer nur die aktuelle pid abgefragt mit allen aktiven Elementen, je nachdem, welche Felder in der Tabelle vorhanden sind, werden auch deleted, hidden, starttime, endtime etc. mit berücksichtigt. Listing 6.20 Beispiel: Tabelle pages: $result = $this->pi_exec_query('pages', 0); while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) $items[] = array('uid' => $row['uid'], 'title' => $row['title']); /* Ergebnis in $items: Array ( [0] => Array ( [uid] => 41 [title] => subpage 1 ) [1] => Array ( [uid] => 42 [title] => subpage 2 ) ) Ausgeführte SQL-Abfrage: SELECT pages.* FROM pages WHERE pid IN (25) AND pages.deleted=0 AND pages.t3ver_statepi_exec_query('pages', 1); $item = $GLOBALS['TYPO3_DB']->sql_fetch_row($result); /* Ergebnis in $item: Array ( [0] => 2 ) Ausgeführte SQL-Abfrage: SELECT count(*) FROM pages WHERE pid IN (25) AND pages.deleted=0 AND pages.t3ver_statepi_exec_query('fe_users', 0, '', '', '' ,'', 'FROM fe_users'); while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) $items[] = array('username' => $row['username'], 'name' => $row['name']); /* Ergebnis in $item: Array [0] [1] [2] )
( => Array ( [username] => test [name] => ) => Array ( [username] => max [name] => ) => Array ( [username] => eva [name] => )
Ausgeführte SQL-Abfrage: SELECT fe_users.* FROM fe_users LIMIT 0,20 */
6.2.2
pi_getPidList
$this->pi_getPidList($pid_list, $recursive = 0)
Erzeugt eine kommaseparierte Liste von Seiten-IDs innerhalb der ebenfalls kommaseparierten Liste $pid_list. Mit einem Wert größer 0 für $recursive kann auch um diesen Wert rekursiv gesucht werden. Listing 6.23 Beispiel: Suche alle Seiten innerhalb der Page-IDs 12 und 24 $pages = $this->pi_getPidList('24,12',2); /* Ergebnis in $pages:
149
6 Datenbank 44,25,41,42,26,24,36,12 */
6.2.3
pi_getRecord
$this->pi_getRecord($table,$uid,$checkPage=0)
Es wird ein einzelner Datensatz aus Tabelle $table abgefragt, es gibt nur die Bedingung auf eine gezielte $uid. Mit $checkPage kann zusätzlich abgefragt werden, ob dieser Datensatz auf der jeweiligen Seite verfügbar ist. Listing 6.24 Beispiel $product = $this->pi_getRecord('tx_extkey_products', 1); /* Ergebnis in $products: Array ( [uid] => 1 [pid] => 6 [tstamp] => 1255874092 [crdate] => 1255874092 [cruser_id] => 1 [product] => Kaffee [category] => 2 )
6.2.4
pi_prependFieldsWithTable
$this->pi_prependFieldsWithTable($table,$fieldList)
Fügt allen Feldern in der kommaseparierten Liste $fieldList den Tabellennamen $table vorne an. Listing 6.25 Beispiel $fields = $this->pi_prependFieldsWithTable('tx_extkey_products', 'name, category, price'); /* Ergebnis in $fields: tx_extkey_products.name,tx_extkey_products.category, tx_extkey_products.price */
150
6.3 cObj
6.3 cObj
6.3.1
DBgetDelete
$this->cObj->DBgetDelete($table, $uid, $doExec=FALSE)
„Löscht“ einen Datensatz aus Tabelle $table mit $uid als Bedingung. Sofern die Tabelle das Feld „deleted“ enthält, wird der Datensatz nicht physikalisch gelöscht, sondern es wird lediglich das Feld „deleted“ auf „1“ gesetzt. Bleibt $doExec false, so gibt die Funktion die SQL-Abfrage zurück, die ausgeführt werden würde – dies dient allerdings nur zur Information. Die SQL-Abfrage sollte immer mit $doExec = true ausgeführt werden. Im Erfolgsfall wird „1“ zurückgegeben. Listing 6.26 Beispiel $delete = $this->cObj->DBgetDelete('fe_users', '1', false); /* Ergebnis in $delete: UPDATE fe_users SET deleted='1' WHERE uid=1 */ $deleted = $this->cObj->DBgetDelete('fe_users', '1', true); /* Ergebnis in $deleted: 1 */
6.3.2
DBgetInsert
$this->cObj->DBgetInsert($table, $pid, $dataArr, $fieldList, $doExec=FALSE)
Generiert einen SQL-Insert-Befehl, der alle Systemfelder wie „tstamp“, „crdate“, „cruser_id“, „fe_cruser_id“ und „fe_crgroup_id“ automatisch berücksichtigt, sofern sie in der Tabelle vorhanden sind. Es werden ausschließlich die Werte aus dem Array $dataArr in die Tabelle $table eingefügt, die in der kommaseparierten Liste $fieldList stehen. Listing 6.27 Beispiel $dataArr = array( 'username' => 'mickey', 'password' => 'start123', 'name' => 'Mickey Maus', 'usergroup' => '2',
151
6 Datenbank 'address' => 'Entenstr. 9' ); $insert = $this->cObj->DBgetInsert('fe_users', '6', $dataArr, 'username,password,name,usergroup', false); /* Ergebnis in $insert: INSERT INTO fe_users ( username, password, name, usergroup, tstamp, crdate, cruser_id, fe_cruser_id, pid ) VALUES ( 'mickey', 'start123', 'Mickey Maus', '2', '1255884274', '1255884274', '0', '0', '6' ) */ $inserted = $this->cObj->DBgetInsert('fe_users', '6', $dataArr, 'username,password,name,usergroup', true); /* Ergebnis in $inserted: 1 */
6.3.3
DBgetUpdate
$this->cObj->DBgetUpdate($table, $uid, $dataArr, $fieldList, $doExec=FALSE)
Generiert einen SQL-Update-Befehl, der das Feld „tstamp“ automatisch berücksichtigt, sofern es vorhanden ist. Zum Ausführen muss $doExec = true gesetzt werden. Listing 6.28 Beispiel $dataArr = array( 'address' => 'Entenstr. 9' ); $update = $this->cObj->DBgetUpdate('fe_users', '11', $dataArr, 'address', false) /* Ergebnis in $update: UPDATE fe_users SET address='Entenstr. 9', tstamp='1255884909' WHERE uid=11 */ $updated = $this->cObj->DBgetUpdate('fe_users', '11', $dataArr, 'address', true) /* Ergebnis in $updated: 1 */
152
6.3 cObj
6.3.4
enableFields
$this->cObj->enableFields($table,$show_hidden=0)
Erzeugt die für SQL-Abfragen benötigten Bedingungen, um nur die aktuell „aktiven“ Datensätze zu bekommen. Es werden nur Bedingungen erzeugt für Systemfelder, die in der abgefragten Tabelle vorhanden sind. Listing 6.29 Beispiele $whereCategories = $this->cObj->enableFields('tx_extkey_categories'); /* Ergebnis in $whereCategories: AND tx_extkey_categories.deleted=0 */ $whereTTContent = $this->cObj->enableFields('tt_content', 1); /* Ergebnis in $whereTTContent; AND tt_content.deleted=0 AND tt_content.t3ver_state [1] => [2] => [3] => [4] => [5] => )
flags scripts struktur styles templates user_upload
*/
7.1.5
getAllFilesAndFoldersInPath
t3lib_div::getAllFilesAndFoldersInPath(array $fileArr,$path,$extList='', $regDirs=0,$recursivityLevels=99,$excludePattern='')
Ermittelt innerhalb von $path alle Dateien und Verzeichnisse. Über das Array $fileArr können bereits zuvor ausgelesene Verzeichnisse dem Ergebnis vorangestellt, über die kommaseparierte Liste $extList bestimmte Dateierweiterungen gefiltert werden. $regDirs steuert, ob im Ergebnis-Array auch die Verzeichnisnamen separat aufgeführt werden sollen. Wie viele Ebenen rekursiv ausgelesen werden sollen, steuert $recursivityLevels. Mit Hilfe eines regulären Ausdrucks in $excludePattern können bestimmte Dateien oder Verzeichnisse ausgeschlossen werden. Listing 7.5 Beispiel $files = t3lib_div::getAllFilesAndFoldersInPath( array(), 'fileadmin/', '', 1 ); /* Auszug aus $files: Array ( [0] => fileadmin/ [65a5bd5b6c270c9628c3e90ca979996b] [1] => fileadmin/flags/ [472a2f8cda5b585bb8cb64b349e1f61c] [5cd2cbdc135d3c3a90f65b756877db77] [814da70ac0d558d15295303e3f7e249b] [6f7e898514e7baa8558a535608fbe699] [b6d02f3ee6b3ceb12644cb022bf7b444] [...] => ... )
=> fileadmin/logfile.log => => => => =>
fileadmin/flags/ar.gif fileadmin/flags/ar.png fileadmin/flags/ar_d.gif fileadmin/flags/bg.gif fileadmin/flags/bg.png
Der Array-Key ist der jeweilige md5-hash der Datei. */
157
7 Dateisystem
7.1.6
getFileAbsFileName
t3lib_div::getFileAbsFileName($filename, $onlyRelative=TRUE,$relToTYPO3_mainDir=FALSE)
Gibt den absoluten Dateipfad zur Datei in $filename an, wobei $filename auch ein Verzeichnis sein kann. $onlyRelative steuert, ob nur Dateien innerhalb des aktuellen Seitenpfades berücksichtigt werden. Standardmäßig bezieht sich der relative Dateipfad in $filename auf den aktuellen Seitenpfad, alternativ kann sich der Pfad mit $relToTYPO3_mainDir = true auf das TYPO3Core-Verzeichnis beziehen. Listing 7.6 Beispiel $file = t3lib_div::getFileAbsFileName('fileadmin/logfile.log'); /* Ergebnis in $file: /srv/www/domain.com/htdocs/fileadmin/logfile.log */
7.1.7
getFilesInDir
t3lib_div::getFilesInDir($path,$extensionList='',$prependPath=0, $order='',$excludePattern='')
Liest alle Dateien innerhalb des Verzeichnisses $path ein. $extensionList ist eine optionale kommaseparierte Liste, um nur bestimmte Dateierweiterungen einzulesen. Wird $prependPath = 1 gesetzt, so wird allen Dateinamen der Pfad vorangestellt. Mit $order = 1 wird die Dateiliste alphabetisch sortiert, $order = 'mtime' nach dem Aktualisierungsdatum. Listing 7.7 Beispiel $files = t3lib_div::getFilesInDir('fileadmin/flags/', 'png', 0, 1); /* Ergebnis in $files: Array ( [5cd2cbdc135d3c3a90f65b756877db77] [b6d02f3ee6b3ceb12644cb022bf7b444] [df58e1c2dd9a87f2b86b33b0e2cfe688] [f0aa7d05b27a5a85716c911f7e34556c] [...] => ... ) */
158
=> => => =>
ar.png bg.png bs.png ca.png
7.1 t3lib_div
7.1.8
getURL
t3lib_div::getURL($url, $includeHeader = 0, $requestHeaders = false, &$report = NULL)
Liest eine Datei oder URL aus und gibt den Dateiinhalt zurück. Optional wird der httpHeader mit ausgelesen ($includeHeader = 1). Auch der http-Header der Anfrage kann mittels $requestHeaders angepasst werden. Die Funktion nutzt cURL, setzt also ein installiertes cURL-Paket voraus. Listing 7.8 Beispiel $rss = t3lib_div::getURL('http://snippets.typo3.org/snippets.xml'); /* Ergebnis in $rss: <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
7.1.9
isAbsPath
t3lib_div::isAbsPath($path)
Überprüft systemunabhängig, ob der Pfad $path absolut oder relativ ist. Gibt true oder false zurück. Listing 7.9 Beispiel $isAbsolute = t3lib_div::isAbsPath('d:/path/to/file.txt'); /* Ergebnis in $isAbsolute: true */
7.1.10 isAllowedAbsPath t3lib_div::isAllowedAbsPath($path)
Überprüft, ob der Pfad $path absolut und innerhalb des Seitenpfades ist. Gibt im Erfolgsfall true zurück.
159
7 Dateisystem Listing 7.10 Beispiel $allowed = t3lib_div::isAllowedAbsPath( '/srv/www/domain.com/htdocs/fileadmin/ '); /* Ergebnis in $allowed: true */
7.1.11 mkdir t3lib_div::mkdir($path)
„Ersatz“ für die PHP-Funktion mkdir, mit dem Zweck, dass Verzeichnisrechte und Inhaber einheitlich nach der Konfiguration $GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask'] und $GLOBALS['TYPO3_CONF_VARS']['BE']['createGroup']
angelegt werden. $path muss hierbei absolut sein. Die Funktion gibt im Erfolgsfall true zurück. Listing 7.11 Beispiel $created = t3lib_div::mkdir('/srv/www/domain.com/htdocs/fileadmin/ext');
7.1.12 mkdir_deep t3lib_div::mkdir_deep($destination,$deepDir)
Erzeugt einen gesamten Verzeichnispfad auf einmal, falls notwendig. Lediglich das Verzeichnis $destination muss absolut sein und bereits existieren. Listing 7.12 Beispiel $created = t3lib_div::mkdir_deep('/srv/www/domain.com/htdocs/fileadmin/', 'ext/all/folders/to/files/');
7.1.13 removePrefixPathFromList t3lib_div::removePrefixPathFromList(array $fileArr,$prefixToRemove)
Entfernt von allen Dateipfaden im Array $fileArr den absoluten Pfad $prefixToRemove. Haben nicht alle Dateipfade den gleichen absoluten Pfad, so gibt die Funktion eine Fehlermeldung zurück.
160
7.1 t3lib_div Listing 7.13 Beispiel $files = array( '/srv/www/domain.com/htdocs/fileadmin/file1.csv', '/srv/www/domain.com/htdocs/fileadmin/ext/file2.csv' ); $relFiles = t3lib_div::removePrefixPathFromList( $files, '/srv/www/domain.com/htdocs/'); /* Ergebnis in $relFiles: Array ( [0] => fileadmin/file1.csv [1] => fileadmin/ext/file2.csv ) */
7.1.14 resolveBackPath t3lib_div::resolveBackPath($pathStr)
Löst überflüssige relative Rücksprünge im Pfad $pathStr auf. Listing 7.14 Beispiel $path = t3lib_div::resolveBackPath( 'fileadmin/first/path/../../second/path/'); /* Ergebnis in $path: fileadmin/second/path/ */
7.1.15 rmdir t3lib_div::rmdir($path,$removeNonEmpty=false)
Erweitert die PHP-Funktion rmdir um die Möglichkeit, rekursiv Verzeichnisse löschen zu können inklusive aller enthaltenen Dateien. Im Erfolgsfall gibt die Funktion true zurück. $path muss absolut sein. Listing 7.15 Beispiel $deleted = t3lib_div::rmdir('/srv/www/domain.com/htdocs/fileadmin/ext/', true);
161
7 Dateisystem
7.1.16 split_fileref t3lib_div::split_fileref($fileref)
Bricht den Pfad zu einer Datei in Pfad, Datei, Dateiname und Erweiterung auf. Listing 7.16 Beispiel $filerefParts = t3lib_div::split_fileref('fileadmin/logfile.log'); /* Ergebnis in $filerefParts: Array ( [path] => fileadmin/ [file] => logfile.log [filebody] => logfile [fileext] => log ) */
7.1.17 tempnam t3lib_div::tempnam($filePrefix)
Ersetzt die PHP-Funktion tempnam(). Alle Dateinamen werden innerhalb des Verzeichnisses typo3temp erzeugt. Listing 7.17 Beispiel $tmpfile = t3lib_div::tempnam('ext'); /* Ergebnis in $tmpfile: /path/to/typo3/htdocs/typo3temp/ext076.tmp */
7.1.18 unlink_tempfile t3lib_div::unlink_tempfile($uploadedTempFileName)
Löscht die temporäre Datei $uploadedTempFileName im Verzeichnis „typo3temp/“ und wird üblicherweise nach der Funktion t3lib_div::upload_to_tempfile() aufgerufen. Es können nur Dateien innerhalb des Verzeichnis „typo3temp/“ gelöscht werden.
7.1.19 upload_copy_move t3lib_div::upload_copy_move($source,$destination)
162
7.1 t3lib_div Verschiebt eine hochgeladene Datei in den absoluten Pfad $destination. Wird als $source keine hochgeladene Datei angegeben, wird eine Kopie der Datei erstellt. Listing 7.18 Beispiel $source = $_FILES['uploadedfile']['tmp_name']; $destination = t3lib_div::getFileAbsFileName('uploads'). '/'.$this->extKey.'/'. str_replace(" ","_",$_FILES['uploadedfile']['name']); $uploaded = t3lib_div::upload_copy_move($source,$destination); /* Ergebnis in $uploaded: true */
7.1.20 upload_to_tempfile t3lib_div::upload_to_tempfile($uploadedFileName)
Verschiebt eine hochgeladene Datei ins Verzeichnis typo3temp mit temporärem Dateinamen. Der Rückgabewert enthält im Erfolgsfall den Dateinamen. Listing 7.19 Beispiel $source = $_FILES['uploadedfile']['tmp_name']; $filename = t3lib_div::upload_to_tempfile($source); /* Ergebnis in $filename: /srv/www/domain.tld/htdocs/typo3temp/upl1D5.tmp */
7.1.21 verifyFilenameAgainstDenyPattern t3lib_div::verifyFilenameAgainstDenyPattern($filename)
Überprüft den übergebenen Dateinamen gegen die Konfiguration in $GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern']
und gibt false zurück, sobald der Dateiname übereinstimmt.
163
7 Dateisystem
7.1.22 writeFile t3lib_div::writeFile($file,$content)
Schreibt den String $content in die Datei $file. Existiert $file bereits, so wird die Datei überschrieben. Listing 7.20 Beispiel $written = t3lib_div::writeFile('fileadmin/data.txt','hello world'); /* Ergebnis in $written: true */
7.1.23 writeFileToTypo3tempDir t3lib_div::writeFileToTypo3tempDir($filepath,$content)
Schreibt $content in eine Datei innerhalb des Verzeichnisses typo3temp. $filepath muss den absoluten Pfad enthalten, es werden auch Verzeichnisse unterhalb von typo3temp unterstützt. Im Erfolgsfall gibt die Funktion false zurück. Listing 7.21 Beispiel $written = t3lib_div::writeFileToTypo3tempDir( PATH_site.'typo3temp/data.txt','hello world' ); /* Ergebnis in $written: false */
164
8 8
8.1
Strings, Arrays und Umgebungsvariablen
Allgemeine Funktionen
8.1.1
_GET
t3lib_div::_GET($var=NULL)
Gibt alle Werte des globalen GET-Arrays zurück. Da die Werte normalisiert und alle Escape-Zeichen entfernt werden, sollte jeder Zugriff auf GET-Variablen über diese Methode erfolgen. Wird $var gesetzt, erfolgt als Rückgabe nur der Wert von $var. Listing 8.1 Aufruf einer URL mit „&showArticle=54“ $articleID = t3lib_div::_GET('showArticel'); $getVars = t3lib_div::_GET(); /* Ergebnis in $articleID: 54 Ergebnis in $getVars: Array ( [id] => 40 [showArticle] => 54 ) */
8.1.2
_GETset
t3lib_div::_GETset($inputGet,$key='')
Schreibt Eingabe Werte in $_GET
165
8 Strings, Arrays und Umgebungsvariablen Wird $key nicht gesetzt, so wird das gesamte Array $_GET überschrieben! Mit definiertem $key wird nur dieser Bereich neu geschrieben. Listing 8.2 Beispiel t3lib_div::_GETset(array("name" => "mickey maus"));
8.1.3
_GP
t3lib_div::_GP($var,$strip=0)
Gibt den Wert von $var zurück, wobei $var sowohl eine GET- als auch eine POSTVariable sein kann. Sollten beide Variablen vorhanden sein, so wird die POST-Variable zurückgegeben. Mit $strip=1 werden nur Arrays normalisiert. Listing 8.3 Beispiel $name = t3lib_div::_GP('name'); /* Ergebnis in $name: mickey maus */
8.1.4
_POST
t3lib_div::_POST($var=NULL)
Gleiche Funktionalität wie _GET für _POST-Variablen Listing 8.4 Beispiel $articleID = t3lib_div::_POST('showArticel'); $getVars = t3lib_div::_POST(); /* Ergebnis in $articleID: 54 Ergebnis in $getVars: Array ( [id] => 40 [showArticle] => 54 ) */
8.1.5
callUserFunction
t3lib_div::callUserFunction( $funcName,&$params,&$ref,$checkPrefix='user_',$errorMode=0 )
166
8.1 Allgemeine Funktionen Führt eine benutzerdefinierte Funktion aus. Standardmäßig sollten diese Funktionen mit dem Präfix „user_“ beginnen. Die Parameter werden als Referenz übergeben. Listing 8.5 Beispiel $userVar = array (); t3lib_div::callUserFunction('user_Func',$userVar,$this); function user_Func($refVar) { $refVar = array(1 => 'hello world'); } /* Ergebnis in $userVar: Array ( [1] => hello world ) */
8.1.6
clientInfo
t3lib_div::clientInfo($useragent='')
Basisinformationen über den Browser und das Betriebssystem des Clients. Listing 8.6 Beispiel $client = t3lib_div::clientInfo(); /* Ergebnis in $client: Array ( [BROWSER] => net [VERSION] => 5 [SYSTEM] => win [FORMSTYLE] => 1 ) */
8.1.7
compat_version
t3lib_div::compat_version($verNumberStr)
Überprüft die Kompatibilität zur übergebenen TYPO3-Version Listing 8.7 Beispiel $check = t3lib_div::compat_version("4.2.0"); /* Ergebnis in $check: 1 */
167
8 Strings, Arrays und Umgebungsvariablen
8.1.8
compileSelectedGetVarsFromArray
t3lib_div::compileSelectedGetVarsFromArray( $varList,array $getArray,$GPvarAlt=1 )
Bildet einen Auszug aus einem eindimensionalen Array, gesteuert über eine kommaseparierte Liste von keys. Wird kein Array definiert, so werden die GET- und POST-Variablen verwendet (Reihenfolge siehe _GP). Listing 8.8 Beispiel $vars = t3lib_div::compileSelectedGetVarsFromArray('name,email',array()); /* Ergebnis ind $vars: Array ( [name] => mickey maus [email] =>
[email protected] ) */
8.1.9
getHostname
t3lib_div::getHostname()
Gibt den Fully Qualified Domain Name zurück. Listing 8.9 Beispiel t3lib_div::getHostname()
8.1.10 getIndpEnv t3lib_div::getIndpEnv($getEnvName)
Pendant zu $_SERVER, allerdings systemunabhängig. Listing 8.10 Gültige Werte für $getEnvName: SCRIPT_NAME, SCRIPT_FILENAME, REQUEST_URI, PATH_INFO, REMOTE_ADDR, REMOTE_HOST, HTTP_REFERER, HTTP_HOST, HTTP_USER_AGENT, HTTP_ACCEPT_LANGUAGE, QUERY_STRING, TYPO3_DOCUMENT_ROOT, TYPO3_HOST_ONLY, TYPO3_HOST_ONLY, TYPO3_REQUEST_HOST, TYPO3_REQUEST_URL, TYPO3_REQUEST_SCRIPT, TYPO3_REQUEST_DIR, TYPO3_SITE_URL, _ARRAY
8.1.11 getThisUrl t3lib_div::getThisUrl()
Gibt den Host und Pfad zur aktuellen Seite zurück.
168
8.1 Allgemeine Funktionen Listing 8.11 Beispiel $url = t3lib_div::getThisUrl(); /* Ergebnis in $url: domain.com/path/to/script/ */
8.1.12 linkThisScript t3lib_div::linkThisScript(array $getParams = array())
Erzeugt die vollständige URL zum aktuellen Skript, über das Array $getParams können die mit zu übergebenden GET-Parameter gesteuert werden. Ein leeres Array entfernt alle GET-Parameter. Listing 8.12 Beispiel $url = t3lib_div::linkThisScript(array()); /* Ergebnis in $url: /index.php?id=40 */
8.1.13 linkThisUrl t3lib_div::linkThisUrl($url,array $getParams=array())
Die in $url übergebene vollständige URL wird geparst und mit den in $getParams übergebenen Parametern ergänzt, bestehende werden überschrieben. Listing 8.13 Beispiel $url = t3lib_div::linkThisUrl('http://www.domain.com/produkte.html?productid=lee r',array('productid' => '354', 'category' => 'coffee')) /* Ergebnis in $url: http://www.domain.com/produkte.html?productid=354&category=coffee */
8.1.14 locationHeaderUrl t3lib_div::locationHeaderUrl($path)
Erzeugt aus relativen und absoluten Pfaden vollständige URLs.
169
8 Strings, Arrays und Umgebungsvariablen Listing 8.14 Beispiel $url = t3lib_div::locationHeaderUrl('/absolute/path/to/script.html'); /* Ergebnis in $url: http://www.domain.com/absolute/path/to/script.html */ $url = t3lib_div::locationHeaderUrl('relativepath/script.html'); /* Ergebnis in $url: http://www.domain.com/current/path/relativepath/script.html */
8.1.15 makeInstance t3lib_div::makeInstance($className)
Erzeugt eine neue Instanz der Klasse $className – sollte unbedingt statt der PHPMethode „new“ verwendet werden. Listing 8.15 Beispiel $obj =
t3lib_div::makeInstance('tx_extkey_functions');
8.1.16 makeInstanceService t3lib_div::makeInstanceService($serviceType, $serviceSubType='', $excludeServiceKeys=array())
Erzeugt eine neue Instanz eines Service und gibt die Service-Class als Objekt zurück Listing 8.16 Beispiel if (is_object($service = t3lib_div::makeInstanceService('myService'))) { $content = $serviceObj->main($value); }
8.1.17 rmFromList t3lib_div::rmFromList($element,$list)
Löscht den Inhalt von $element aus der kommaseparierten Liste $list.
170
8.2 String-Funktionen Listing 8.17 Beispiel $newList = t3lib_div::rmFromList('24', '12,26,24,1,4'); /* Ergebnis in $newList: 12,26,1,4 */
8.1.18 sysLog t3lib_div::sysLog($msg, $extKey, $severity=0) Schreibt den Inhalt von $msg in den syslog des Servers. Listing 8.18 Gültige Werte für $severity: 0 1 2 3 4
8.2
= = = = =
info, notice, warning, error, fatal error
String-Funktionen
8.2.1
calcParenthesis
t3lib_div::calcParenthesis($string)
Berechnet den übergebenen String unter der Berücksichtigung von Klammern. Listing 8.19 Beispiel $value = t3lib_div::calcParenthesis('(4+20)/4'); /* Ergebnis on $value: 6 */
8.2.2
cmpFQDN
t3lib_div::cmpFQDN($baseIP, $list)
171
8 Strings, Arrays und Umgebungsvariablen Vergleicht den Fully Qualified Domain Name der $baseIP mit einer in $list übergebenen kommaseparierten Liste. Diese Liste darf Wildcards enthalten. Bei Übereinstimmung gibt die Funktion true zurück, ansonsten false. Listing 8.20 Beispiele für $list: subdomain.*.com *.domain.com Falsch wäre: sub*.domain.com
8.2.3
cmpIP
t3lib_div::cmpIP($baseIP, $list)
Vergleicht die IP mit einer in $list übergebenen kommaseparierten Liste. Diese Liste darf Wildcards enthalten. Bei Übereinstimmung gibt die Funktion true zurück, ansonsten false. Es werden sowohl IPv4 als auch IPv6 unterstützt. Listing 8.21 Beispiel für $list 192.168.10.*,192.168.11.*
8.2.4
convUmlauts
t3lib_div::convUmlauts($str)
Wandelt die deutschen Umlaute um. Listing 8.22 Beispiel $string = t3lib_div::convUmlauts('Ä Ö Ü ä ö ü ß'); /* Ergebnis in $string: Ae Oe Ue ae oe ue ss */
8.2.5
csvValues
t3lib_div::csvValues(array $row,$delim=',',$quote='"')
Erzeugt aus einem eindimensionalen Array eine Zeile csv.
172
8.2 String-Funktionen Listing 8.23 Beispiel $csv = t3lib_div::csvValues(array('13','coffee','beans')); /* Ergebnis in $csv: "13","coffee","beans" */
8.2.6
deHSCentities
t3lib_div::deHSCentities($str)
Macht die Bearbeitung von HTML-Entities mit htmlspecialchars rückgängig. Listing 8.24 Beispiel $str = t3lib_div::deHSCentities("""); /* Ergebnis in $str: " */
8.2.7
expandList
t3lib_div::expandList($list)
Eine kommaseparierte Liste von Integer-Werten mit Bereichen „von-bis“ wird als erweiterte kommaseaprierte Liste zurückgegeben mit allen Einzelwerten innerhalb dieser Bereiche. Listing 8.25 Beispiel $list = t3lib_div::expandList("1,5,6-20,98"); /* Ergebnis in $list: 1,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,98 */
8.2.8
fixed_lgd
t3lib_div::fixed_lgd_cs($string,$origChars)
Kürzt den String $string am Ende mit $preStr ab, sofern dieser mehr Zeichen enthält als $origChars.
173
8 Strings, Arrays und Umgebungsvariablen Listing 8.26 Beispiel $str = t3lib_div::fixed_lgd_cs("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt", 30); /* Ergebnis in $str: Lorem ipsum dolor sit amet,... */
8.2.9
fixed_lgd_pre
t3lib_div::fixed_lgd_pre($string,$chars)
Kürzt den String $string am Ende mit „...“ ab, sofern dieser mehr Zeichen enthält als $origChars. Listing 8.27 Beispiel $str = t3lib_div::fixed_lgd_pre("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt.", 36); /* Ergebnis in $str: ...sed do eiusmod tempor incididunt. */
8.2.10 formatForTextarea t3lib_div::formatForTextarea($content)
Optimierte Variante von htmlspecialchars(), sollte für jede Textarea verwendet werden. Listing 8.28 Beispiel $content = t3lib_div::formatForTextarea($content);
8.2.11 generateRandomBytes t3lib_div::generateRandomBytes($count)
Erzeugt einen Zufalls-String mit der Anzahl von $count-Zeichen. Als Bereich werden die gesamten 8 Bit genutzt.
174
8.2 String-Funktionen Listing 8.29 Beispiel $random = t3lib_div::generateRandomBytes(20); /* Ergebnis in $random: uðU†+é /anmeldung.html [method] => get [target] => main )
8.2.13 htmlspecialchars_decode t3lib_div::htmlspecialchars_decode($value)
Umkehrfunktion zur PHP-Funktion htmlspecialchars(). Listing 8.31 Beispiel $value = t3lib_div::htmlspecialchars_decode('&'); /* Ergebnis in $value: & */
8.2.14 implodeArrayForUrl t3lib_div::implodeArrayForUrl($name,array $theArray, $str='',$skipBlank=0,$rawurlencodeParamName=0)
Erzeugt aus dem multidimensionalen Array $theArray einen String, der die Wertepaare des Arrays als GET-Parameter enthält.
175
8 Strings, Arrays und Umgebungsvariablen $name ist hierbei ein Präfix für alle Keys des Arrays. Wird $skipBlank gesetzt, so werden nur GET-Parameter geschrieben, die auch einen Wert übergeben. $rawurlencodeParamName steuert die PHP-Funktion rawurlencode() für die Keys. Listing 8.32 Beispiel $url = t3lib_div::implodeArrayForUrl('product', array( 'id' => '52345', 'category' => '', 'group' => 'coffee,beans' ), '', 1); /* Ergebnis in $url: &product[id]=52345&product[group]=coffee%2Cbeans */
8.2.15 implodeAttributes t3lib_div::implodeAttributes(array $arr, $xhtmlSafe=FALSE,$dontOmitBlankAttribs=FALSE)
Erzeugt aus einem Array Attribute für bspw. ein html-Tag. $xhtmlSafe = true wird hier empfohlen, da diese Option gleichzeitig eventuell doppelt vorkommende Attribute ignoriert (hier wird jeweils das erste verwendet) und die Werte durch htmlspecialchars() bereinigt. Standardmäßig werden leere Attribute nicht berücksichtigt; falls allerdings $dontOmitBlankAttributes gesetzt ist, werden auch leere Attribute zurückgegeben. Listing 8.33 Beispiel $attr = t3lib_div::implodeAttributes(array( 'action' => '/anmeldung.html', 'Method' => 'get', 'target' => 'anmeldeformular' ), true); /* Ergebnis in $attr: action="/anmeldung.html" method="get" target="anmeldeformular" */
8.2.16 inList t3lib_div::inList($list, $item)
Sucht nach dem Element $item in der kommaseparierten Liste $list. Ist das Element vorhanden, gibt die Funktion true zurück, ansonsten false.
176
8.2 String-Funktionen Listing 8.34 Beispiel $status = (t3lib_div::inList('1,5,8,13,29,rehw,r7345j', 'reh')) ? 'gefunden' : 'nicht gefunden'; /* Ergebnis in $status: nicht gefunden */
8.2.17 int_from_ver t3lib_div::int_from_ver($verNumberStr)
Erzeugt einen Integer-Wert aus einer Versionsnummer im Format „x.x.x“, wobei jeder Teil der Versionsnummer bis 999 zählt. Listing 8.35 Beispiel $ver = t3lib_div::int_from_ver('5.0.13'); /* Ergebnis in $ver: 5000013 */
8.2.18 intInRange t3lib_div::intInRange($theInt,$min,$max=2000000000,$zeroValue=0)
Überprüft, ob $theInt innerhalb der Werte $min und $max liegt. Ist der Wert kleiner oder größer, so wird entweder $min oder $max ausgegeben. Falls der Wert kein Integer-Wert ist, wird er durch $zeroValue ersetzt. Listing 8.36 Beispiele $res[0] = t3lib_div::intInRange(5, 10); $res[1] = t3lib_div::intInRange(5, 1, 10); $res[2] = t3lib_div::intInRange('v', 1, 10); $res[3] = t3lib_div::intInRange(100, 1, 10); /* Ergebnis in $res: Array ( [0] => [1] => [2] => [3] => )
10 5 1 10
177
8 Strings, Arrays und Umgebungsvariablen
8.2.19 intval_positive t3lib_div::intval_positive($theInt)
Falls $theInt negativ ist, wird 0 zurückgegeben, positive Werte bleiben unverändert. Listing 8.37 Beispiele $res[0] = t3lib_div::intval_positive(-5); $res[1] = t3lib_div::intval_positive(10); $res[2] = t3lib_div::intval_positive('v'); /* Ergebnis in $res: Array ( [0] => 0 [1] => 10 [2] => 0 )
8.2.20 isFirstPartOfStr t3lib_div::isFirstPartOfStr($str, $partStr)
Überprüft, ob $partStr mit dem Anfang von $str übereinstimmt, und gibt true oder false zurück. Listing 8.38 Beispiel $str = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt"; $partStr =
"Lorem ipsum dolor sit amet";
$isFirstPart = t3lib_div::isFirstPartOfStr($str, $partStr); /* Ergebnis in $isFirstPart: true */
8.2.21 md5int t3lib_div::md5int($str)
Wandelt die ersten sieben Stellen des md5-Hash von $str in den Integer-Wert um, quasi der Integer-Hash von $str.
178
8.2 String-Funktionen Listing 8.39 Beispiel $intHash = t3lib_div::md5int('coffee'); /* Ergebnis in $intHash: 38711389 */
8.2.22 milliseconds t3lib_div::milliseconds()
microtime() in Millisekunden Listing 8.40 Beispiel $ms = t3lib_div::milliseconds(); /* Ergebnis in $ms: 1256537906427 */
8.2.23 modifyHTMLColor t3lib_div::modifyHTMLColor($color,$R,$G,$B)
Berechnet eine neue Farbe, indem den jeweiligen Farben die Offsets $R, $G und $B dazugerechnet werden. Der gültige Wertebereich liegt zwischen 0 und 255. Listing 8.41 Beispiel $newColor = t3lib_div::modifyHTMLColor('#000000', '155', '0', '255'); /* Ergebnis in $newColor: #9b00ff */
8.2.24 modifyHTMLColorAll t3lib_div::modifyHTMLColorAll($color,$all)
Der Farbe $color wird ein gleichmäßiges Offset dazugerechnet (Aufhellung). Die Werte des Offsets $all können zwischen 0 und 255 liegen.
179
8 Strings, Arrays und Umgebungsvariablen Listing 8.42 Beispiel $newColor = t3lib_div::modifyHTMLColorAll('#000000', '155'); /* Ergebnis in $newColor: #9b9b9b */
8.2.25 normalizeIPv6 t3lib_div::normalizeIPv6($address)
Normalisiert eine komprimierte Darstellung einer IPv6-Adresse $address. Listing 8.43 Beispiel $ipv6 = t3lib_div::normalizeIPv6('3ffe:400:280::1'); /* Ergebnis in $ipv6: 3ffe:0400:0280:0000:0000:0000:0000:0001 *&
8.2.26 removeXSS t3lib_div::removeXSS($string)
Entfernt eventuellen Cross-Site-Scripting-Code im Input-Wert $string. Listing 8.44 Beispiel $input = t3lib_div::removeXSS("
Mit dieser TCA-Definition wird nun Folgendes erreicht:
Blogs werden in der Tabelle tx_simpleblog_domain_model_blog gespeichert. Posts werden einerseits in der Tabelle tx_simpleblog_domain_model_post gespeichert und andererseits im Feld posts der Tabelle tx_simpleblog_domain_model_ blog referenziert. Hierbei werden dort die UIDs der Post-Beiträge als kommaseparierte Liste gespeichert. Dies wird über die foreign_*-Optionen des TCA erreicht.
Tags werden einerseits in der Tabelle
tx_simpleblog_domain_model_tag gespei-
chert und andererseits im Feld tags der Tabelle tx_simpleblog_domain_model_ posts referenziert. Hier wird allerdings – im Gegensatz zu den Posts im Blog – ledig-
lich die Anzahl der Tags in der Tabelle tx_simpleblog_domain_model_posts im
332
16.5 Anlegen eines Repositorys Feld tags abgespeichert. Die dazugehörigen Referenzen werden in die MM-Tabelle tx_simpleblog_post_tag_mm eingetragen. Das Handling für 1:N oder M:M-Relationen ist also prinzipiell komplett identisch – lediglich das TCA gibt vor, wie Extbase damit umgehen soll.
16.5 Anlegen eines Repositorys Vorhin haben wir ein Blog derart erzeugt, indem wir schlicht die Klasse instanziiert haben. Dies ist natürlich nicht praktikabel, da wir das so erzeugte Objekt schlecht speichern können und auch Extbase von dessen Existenz schlicht nichts weiß. Um nun ein Objekt vorschriftsmäßig zu erzeugen, werden wir gemäß der Paradigmen des Domain Driven Designs ein sogenanntes Repository verwenden. Dieses stellt die Schnittstelle von Domain und Infrastruktur dar und wird im Verzeichnis typo3conf/ext/simpleblog/Classes/Domain/Repository mit dem Namen EntityRepository.php erwartet. Hat man also ein Repository für die Entität Blog, so lautet die zugehörige Datei BlogRepository.php, und genau diese legen wir nun an. Listing 16.14 Die Datei BlogRepository.php
Nanu, werden Sie sich jetzt fragen – die Klasse ist ja komplett leer. Das hat tatsächlich seine Richtigkeit. Dadurch, dass die Klasse Tx_Extbase_Persistence_Repository abgeleitet wird, enthält das Repository bereits alle für den Anfang notwendigen Funktionalitäten. So kann beispielsweise ein Objekt (in unserem Fall ein Blog) zum Repository mittels add() hinzugefügt oder mittels remove() entfernt werden. Darüber hinaus stehen bereits per Default Methoden zum Finden alle Objekte (findAll()) oder über die magische Funktion findByEigenschaft() eine Funktion zur Verfügung, die nur diejenigen Objekte findet, deren Eigenschaft einen bestimmten Wert aufweist. So lässt sich beispielsweise nach dem Titel eines Objekts suchen, indem man findByTitle() verwendet.
Anpassen des Blog-Controllers Damit unser Repository auch benutzt wird, müssen wir es im Blog-Controller direkt ansprechen:
333
16 Entwicklung eines eigenen Plug-ins Listing 16.15 Änderung an der Datei BlogController.php
Wir haben den Controller nun um eine zusätzliche „magische“ Methode erweitert, und zwar initializeAction(). Diese Methode wird immer dann aufgerufen, wenn eine Action angefordert wird. Dabei wird kurz zuvor diese Methode angesprungen, und die dort enthaltenen Anweisungen werden noch kurz vor der eigentlichen Action ausgeführt. In diesem Fall wird das Blog-Repository initialisiert. Auf dieses kann später mittels $this>repository zugegriffen werden. Anschließend wird nun auch die Index-Action entsprechend angepasst, indem beispielhaft eine Schleife drei Blogs erzeugt. Der Titel der Blogs wird entsprechend gesetzt und mittels add() im Repository gespeichert. Schließlich werden über die dem Repository eigene Funktion findAll() alle Blogs gesucht und dem View zugeordnet. Zusätzlich müssen wir hier also auch den View entsprechend anpassen: Listing 16.16 Änderungen an der View-Datei index.html
Blog hinzufügen
Hier wird ein neuer View-Handler verwendet, der ähnlich einer foreach-Schleife alle vorher angelegten und persistierten (gespeicherten) Blogs durchgeht und deren Titel in einer ungeordneten Liste zurückgibt. Das Ergebnis nach zweimaligem Neuladen der Seite kann sich durchaus sehen lassen:
334
16.6 Anlegen einer neuen Action
Abbildung 16.7 Ausgabe nach zweimaligem Reload der Seite
Allerdings werden nun bei jedem Reload drei neue Blogs erzeugt. Das ist unter Umständen nicht logisch, sodass es durchaus Sinn macht, das Hinzufügen in eine eigene Action auszulagern und die Index-Action lediglich zum Anschauen der bereits hinzugefügten Blogs zu nutzen. In der Anzeige haben wir ja bereits einen Link angelegt, der mit der Action add versehen wurde – diese werden wir nun mit Leben füllen. Denn bislang ist diese Action nicht definiert, daher springt der Dispatcher immer wieder in die Default-Action index.
16.6 Anlegen einer neuen Action Für eine neue Action brauchen wir zunächst einmal einen neuen Eintrag in der Datei ext_localconf.php. Dort verändern wir den Aufruf der Funktion configureDispatcher(): Listing 16.17 Änderung in der Datei ext_localconf.php Tx_Extbase_Utility_Plugin::configureDispatcher( $_EXTKEY, 'Pi1', array('Blog' => 'index,add'), array('Blog' => 'add') );
Da das Zufügen eines Blogs sicherlich nicht gechachet werden soll, wurde die Action zusätzlich noch einmal in der zweiten Zeile (hervorgehoben) zugefügt. Diese wird dann als USER_INT-Objekt im TypoScript-Code eingefügt. Aussagekräftige Fehlermeldungen Wenn Sie nun einmal probieren, die Website in diesem Stadium aufzurufen, bekommen Sie eine – wie wir finden – sehr anschauliche und aussagekräftige Fehlermeldung.
335
16 Entwicklung eines eigenen Plug-ins
Abbildung 16.8 Ausführliche Fehlermeldung mit Extbase
Dabei wird zunächst der Fehler angegeben – so fehlt dem Programm wohl eine Action mit dem Namen addAction(). Und etwas später sehen Sie dann auch, in welcher Klasse die Action fehlt, nämlich in Tx_Simpleblog_Controller_BlogController. So müssen wir, nach Lektüre dieser Meldung, die Action dort in der entsprechenden Datei einfach nur einfügen. Wichtig ist, dass Sie die Meldungen aufmerksamen studieren und interpretieren können – dies fällt aber aufgrund der Ausführlichkeit ziemlich leicht, sodass Ihnen Extbase eigentlich immer genau sagt, was es benötigt, um den Fehler zu beheben.
16.6.1
Anlegen der Action addAction()
Nun führen wir in der Controller-Klassendatei typo3conf/ext/simpleblog/Classes/ Controller/BlogController.php folgende Veränderung durch: Listing 16.18 Die geänderte Datei BlogController.php public function indexAction() { $this->view->assign('blogs', $this->blogRepository->findAll()); } public function addAction() { for ($i=0; $isetTitle('Das ist mein '.$i.'. Blog'); $this->blogRepository->add($myblog); } $this->redirect('index'); }
Wir haben nun in der Index-Action lediglich die Anzeige der Blogs untergebracht und in der neuen Add-Action das Anlegen der Blogs. Nach dem Anlegen schließlich wird mit dem API-Befehl redirect() wieder auf die Index-Action umgeleitet. Somit wird damit wieder die Liste der Blogs angezeigt. Das Template bleibt dabei unverändert.
336
16.7 Daten per Formular eingeben und auswerten
16.7 Daten per Formular eingeben und auswerten Störend ist natürlich jetzt noch, dass der Titel ausschließlich fest vorgegeben wird und nicht etwa vom User über ein Formular eingegeben werden kann. Da dies natürlich dringend notwendig ist, rüsten wir diese Funktionalität nun nach. Dafür müssen wir zunächst ein neues Template mit dem Namen add.html erstellen, das wir ebenfalls in das Verzeichnis typo3conf/ext/simpleblog/Resources/Private/ Templates/Blog legen. Listing 16.19 Das neue Template add.html Neues Blog anlegen Blogtitel: <span >(required)
Blog anlegen
Über einen neuen View-Handler können wir nun auch Formulare erzeugen lassen. Der Handler enthält auch gleich die notwendigen Parameter, damit der Dispatcher weiß, was er mit den Daten machen soll. So werden die Formulardaten durch den Controller Blog und die (für uns neue) Action create verarbeitet. Somit müssen wir zunächst diese Action in der Datei ext_localconf.php zufügen: Listing 16.20 Änderungen in der Date ext_localconf.php … Tx_Extbase_Utility_Plugin::configureDispatcher( $_EXTKEY, 'Pi1', array('Blog' => 'index,add,create'), array('Blog' => 'add,create') ); …
Im Blog-Controller nun müssen wir diese Action natürlich einfügen und die Add-Action entsprechend anpassen. Denn unser Plan ist, dass wir zunächst über den Link „Blog hinzufügen“ die Action add aufrufen, die das Formular enthält, in das wir den Namen des Blogs eingeben können. Beim Abschicken des Formulars wird die Action create aufgerufen, die das Blog dann schließlich anlegt. Sobald das Blog dann in das Repository gespeichert wurde, soll eine Weiterleitung auf die Action index erfolgen, die alle angelegten Blogs anzeigt. Nun müssen wir also noch die beiden Actions entsprechend einrichten:
337
16 Entwicklung eines eigenen Plug-ins Listing 16.21 Änderungen in der Datei BlogController.php public function addAction(Tx_Simpleblog_Domain_Model_Blog $newBlog = NULL) { $this->view->assign('newBlog', $newBlog); } public function createAction(Tx_Simpleblog_Domain_Model_Blog $newBlog) { $this->blogRepository->add($newBlog); $this->redirect('index'); }
Interessant sind in beiden Fällen die Parameter der jeweiligen Methoden. Bei der Methode addAction() wird ein leeres Blog übergeben, das allerdings vom Typ der Klasse Tx_Simpleblog_Domain_Model_Blog ist. Damit weiß Extbase automatisch, welche Eigenschaften verwaltet werden müssen. Die Create-Action schließlich bekommt das Objekt vom Formular zurück – allerdings mit gefülltem Titel – und fügt es zum Repository hinzu.
16.8 Objekte aus dem Repository entfernen Mit der Methode add() haben wir bislang Objekte dem Repository zufügen können, nun wollen wir diese natürlich auch wieder entfernen können. Dafür platzieren wir bei der Auflistung aller Blogs am Ende einen Link Delete, mit dem wir das spezielle Blog auch wieder entfernen können. Dies geschieht mit einer eigenen Action delete.
16.8.1
Zufügen der Action delete in der Konfiguration
In der Datei ext_localconf.php müssen wir nun also zunächst wieder unsere neue Action zufügen: Listing 16.22 Änderungen in der Datei ext_localconf.php Tx_Extbase_Utility_Plugin::configureDispatcher( $_EXTKEY, 'Pi1', array('Blog' => 'index,add,create,delete'), array('Blog' => 'add,create,delete') );
16.8.2
Anpassen der Template-Datei index.html
Weiter geht es mit der Template-Datei index.html, indem wir den Lösch-Link platzieren müssen: Listing 16.23 Änderungen in der Template-Datei index.html:
{blog.title} (Delete) 338
16.9 Update von Objekten Als Argument übergeben wir der Action delete schließlich das aktuelle Blog-Objekt (hintere blog-Bezeichnung) in der gleichnamigen Variablen blog (vordere blog-Bezeichnung). Extbase weiß automatisch, welches exakte Blog-Objekt gemeint ist, und extrahiert selbstständig die jeweilige ID heraus. 16.8.2.1
Zufügen der Action delete im Blog-Controller
Nun müssen wir noch den Blog-Controller anpassen, indem wir die Action delete zufügen, und schon haben wir (nach dem Löschen des Caches) unser Ziel erreicht: Listing 16.24 Zufügen der Action delete in der Datei BlogController.php public function deleteAction(Tx_Simpleblog_Domain_Model_Blog $blog) { $this->blogRepository->remove($blog); $this->redirect('index'); }
Über die API-Methode remove() wird nun das übergebene Blog aus dem Repository gelöscht. Nach dem Löschen wird wie gewohnt zur Action index weitergeleitet. Weitere API-Methoden im Repository lauten replace() und update() – diese werden im Referenz-Teil des Buches näher erläutert.
16.9 Update von Objekten Während wir nun sowohl Objekte angelegt wie auch gelöscht haben, wollen wir uns nun den dritten möglichen Fall der schreibenden Interaktion mit dem Repository ansehen – das Aktualisieren bzw. Update.
16.9.1
Edit- und Update-Action hinzufügen
Um ein Update durchführen zu können, müssen wir einerseits ein Änderungsformular präsentieren und andererseits diese Änderung dann auch im Repository durchführen. Dafür benötigen wir zwei Actions – einmal eine Edit-Action, die das Formular präsentiert, und dann die Update-Action, die die Änderung in das Repository schreibt. Wir müssen also nun die beiden Actions edit und update erst einmal in der ext_localconf.php registrieren und andererseits diese Action im Blog-Controller ausformulieren. Listing 16.25 Änderung in der Datei ext_localconf.php Tx_Extbase_Utility_Plugin::configureDispatcher( $_EXTKEY, 'Pi1', array( 'Blog' => 'index,add,create,edit,update,delete', ), array(
339
16 Entwicklung eines eigenen Plug-ins 'Blog' => 'add,create,edit,update,delete', ) );
Im Blog-Controller müssen wir zudem die beiden Actions ausformulieren: Listing 16.26 Änderungen in der Datei BlogController.php /** * Editiert einen bestehenden Blog * * @param Tx_Simpleblog_Domain_Model_Blog $blog Der ursprüngliche Blog * @return string Formular, um den Blog zu bearbeiten * @dontvalidate $blog */ public function editAction(Tx_Simpleblog_Domain_Model_Blog $blog) { $this->view->assign('blog', $blog); } /** * Aktualisiert einen bestehenden Blog * * @param Tx_Simpleblog_Domain_Model_Blog $blog Eine noch nicht gespeicherte, aber bereits modifierte Kopie des ursprünlichen Blogs * @return void */ public function updateAction(Tx_Simpleblog_Domain_Model_Blog $blog) { $this->blogRepository->update($blog); $this->redirect('index'); }
Nun brauchen wir einerseits einen Link zum Editieren des Blogs in der Template-Datei der Index-Action: Listing 16.27 Änderung in der Datei index.html
{blog.title} ( Edit Blog / Delete) ) Und andererseits ein eigenes Template mit dem Dateinamen edit.html im Verzeichnis: typo3conf/ext/simpleblog/Resources/Private/Templates/Blog/: Listing 16.28 Die Datei edit.html Edit Blog "{blog.title}"
Bitte geben Sie hier Ihre Änderungen ein:
Blogtitel
Edit
340
16.10 Der Query-Manager Wenn Sie nun das Beispiel im Frontend aufrufen, bekommen Sie hinter jedem Blog einen Link Edit Blog angezeigt, über den Sie ein Formular zum Ändern erhalten. Dort sind automatisch bereits die Eigenschaften in den Feldern vorbelegt – diese werden von Fluid an dieser Stelle automatisch aus dem übergebenen Blog-Objekt extrahiert. Nach der Änderung klicken Sie einfach auf den Button Edit, und schon wurde die Änderung auch im Blog-Repository persistiert.
16.10 Der Query-Manager Wir haben im Repository bislang nur die Methode findAll() verwendet, um alle gespeicherten Blogs zu erhalten. Wer bereits einige Blogs angelegt hat, dem fällt zunächst auf, dass diese in genau der Reihenfolge wieder ausgelesen wurden, in der sie hinzugefügt wurden. Dies und eben die Auswahl der Blogs selbst wollen wir nun mithilfe des Query-Managers anpassen. Dafür stehen uns weitere „magische“ Methoden des Repositorys zur Verfügung,
findByUid($uid)
Findet ein Objekt anhand einer übergebenen UID (die man natürlich kennen muss)
findBy[Eigenschaft]($search)
Findet alle Objekte, deren Eigenschaft den Wert $search haben. Dabei wir die Eigenschaft selbst Teil des Funktionsnamens. So lautet die Suche nach dem Titel findByTitle($search), wenn die Eigenschaft $title heißt.
findOneBy[Eigenschaft]($search)
Findet das erste auftretende Objekt, dessen Eigenschaft den Wert $search hat. Dabei wird die Eigenschaft selbst Teil des Funktionsnamens – exakt wie bei der vorherigen Funktion. Diese drei genannten Funktionen stehen in jedem Repository automatisch zur Verfügung. Was ist aber, wenn man eigene, individuelle Abfragen braucht? Dann kommt der QueryManager ins Spiel, der im sogenannten Persistence-Framework zu Hause ist – genauer in der Datei typo3conf/ext/extbase/Classes/Persistence/QueryFactory.php. Die Query-Factory schließlich implementiert das Interface Tx_Extbase_Persistence_ QueryInterface, und dieses enthält nun genau die Methoden, mit denen wir unsere Suchabfragen im Repository anpassen können. Um nun einen eigene Query abzusetzen, müssen wir das (bislang noch völlig leere) BlogRepository mit einer geeigneten Methode erweitern:
341
16 Entwicklung eines eigenen Plug-ins Listing 16.29 Eigene Query-Methode für die Datei BlogRepository.php public function findSpecial() { $query = $this->createQuery(); … $blogs = $query->execute(); return $blogs; }
Wir erzeugen in der Funktion findSpecial() zunächst ein Query-Objekt. Mit diesem werden wir gleich interessante Dinge anstellen, daher haben wir diesen Teil erst einmal mit drei Punkten angedeutet. Anschließend wird der Query ausgeführt, wobei alle gefundenen Objekte in der Variablen $blogs gespeichert werden, die dann auch zurückgegeben wird. In der Index-Action des BlogControllers müssen wir jetzt natürlich auch den Query-Aufruf entsprechend anpassen: Listing 16.30 Änderung in der Index_Action der Datei BlogController.php public function indexAction() { //$this->view->assign('blogs', $this->blogRepository->findAll()); $this->view->assign('blogs', $this->blogRepository->findSpecial()); }
Wir haben den ursprünglichen Aufruf auskommentiert und den Aufruf mit der neuen Methode zugefügt. Ruft man das Frontend nun auf, bekommt man genau dieselbe Anzeige wie vorher – das liegt primär daran, dass wir den Query noch nicht näher spezifiziert haben und somit das Default-Verhalten (finde alle Objekte) automatisch aktiviert wird. Nun fügen wir zur Query-Methode eine Möglichkeit hinzu, alle Blogs zu finden, in deren Titel der String „ist mein“ vorkommt (da wir vorhin Blogs mit dem Titel „Das ist mein x.Blog!“ angelegt hatten). Listing 16.31 Die überarbeitete Methode findSpecial() public function findSpecial() { $query = $this->createQuery(); $query->matching( $query->like('title', '%ist mein%') ); $blogs = $query->execute(); return $blogs; }
Über die Funktion matching() wird grundsätzlich eine Suche eingeleitet. In diesem Fall bemühen wir nun die Funktion like(), die ähnlich wie bei SQL Wortbestandteile finden kann. Da wir tatsächlich im Hintergrund eine MySQL-Datenbank verwenden, wird somit ein Query der Art: SELECT * FROM tx_simpleblog_domain_model_blog WHERE title LIKE '%ist mein%' abgesetzt, und die Ergebnisse der Abfrage werden als Objekt verpackt zurückgesendet. Der Query-Manager bietet hier noch zahlreiche andere Methoden, die einerseits beliebig kombiniert und andererseits in beliebiger Reihenfolge aufgerufen werden können.
342
16.11 Eingabevalidierung So gibt es setLimit(), setOrderings und setOffset(), die auf das ganze Ergebnis angewendet werden können, und logicalAnd(), logicalOr(), logicalNot(), equals(), lessThan(), lessThanOrEqual(), greaterThan() und greaterThanOrEqual() für die Teilergebnisse. Damit lassen sich praktisch alle wichtigen Abfragen datenherkunftsneutral beschreiben. Wenn Sie damit nicht zum erwünschten Ergebnis kommen, gibt es zusätzlich die Möglichkeit, einen SQL-Query (sofern eine Datenbank als Speichermedium verwendet wurde) abzusetzen: $query->statement(SELECT * FROM tx_simpleblog_domain_model_blog WHERE title LIKE '%ist mein%');
16.11 Eingabevalidierung Hin und wieder ist es hilfreich und auch nötig, eigene GET- oder POST-Variablen zu übermitteln und diese auszuwerten. Hier wurde mit Extbase ein leicht anderes Konzept eingeführt. So müssen alle Eingabevariablen zunächst sowohl registriert wie auch spezifiziert werden. Dies geschieht über die Annotation. Wollen wir beispielsweise in der Index-Action die GET-Variable $name auswerten, so geht das erst einmal nur im Namensraum der er Extension – sprich in unserem Fall würde die Variable tx_simpleblg_pi1[name] lauten. In der Extension selbst wird diese Variable aber auch immer mit $name angesprochen. Als Nächstes müssen wir die Variable als Input-Parameter an die Index-Action übergeben und eben in der zugehörigen Annotation die Variable registrieren und spezifizieren.
16.12 Validatoren Extbase enthält ein umfangreiches Validation-Framework, das ebenfalls von FLOW3 rückportiert wurde. Damit ist es möglich, eigene Validatoren sowie auch vordefinierte Validatoren verwenden. So kann man damit einfache Fälle, wie die Überprüfung auf Datentypen, Längen und Ähnliches, schnell lösen. Sobald man dann eigene Überprüfungen benötigt, kann man einen eigenen speziellen Validator einsetzen.
16.12.1 Vordefinierte Validatoren Um auf das Set an vordefinierten Validatoren zuzugreifen, müssen Sie diese über eine Annotation festlegen. Wir wollen beispielsweise sicherstellen, dass der Name eines Blogs sowohl ein Text sein soll wie auch die Mindestlänge von fünf Zeichen haben muss. Dafür fügen wir folgenden Kommentar in der Datei Blog.php vor der Definition der Eigenschaft $title ein.
343
16 Entwicklung eines eigenen Plug-ins Listing 16.32 Kommentar in der Datei Blog.php /** * Der Titel des Blogs * * @var string * @validate Text, StringLength(minimum = 5, maximum = 80) * @identity */ protected $title = '';
Die wirklich entscheidende Zeile haben wir hervorgehoben. Beachten Sie bitte, dass eine Annotation im Gegensatz zu einem reinen PHP-Kommentar mit der Zeichenkette /** eingeleitet wird. Geben Sie etwa nur /* an, so wird der Kommentar von Extbase überhaupt nicht ausgewertet. Über die Annotation @validate wird die Validierung nun eingeschaltet. Nachfolgend werden die möglichen Validatoren angegeben. Wenn es (wie hier) mehrere Validatoren sind, so werden diese per Komma voneinander getrennt und dann später bei der Validierung sequenziell von links nach rechts durchlaufen. An erster Stelle steht hier Text, was bedeutet, dass die Eigenschaft $title daraufhin geprüft wird, dass diese nur Text (darf keine Tags beinhalten) enthalten darf. Der nächste Validator, der auf die Eigenschaft angewendet wird, ist der StringLength-Validator. Dieser prüft die Länge der Eigenschaft und löst einen Fehler aus, wenn diese kürzer als zwei Zeichen und länger als 80 Zeichen ist. Alle verfügbaren, vordefinierten Validatoren finden Sie übrigens im Verzeichnis typo3conf/ext/extbase/Classes/Validation/Validator/ und natürlich im Referenzteil des Buches. Wenn Sie nun den Cache löschen, die Seite erneut aufrufen, auf den Link Blog einfügen klicken und dann einen Blognamen mit nur einem Buchstaben angeben, wird das Blog nicht eingetragen, sondern das Eingabefeld wird erneut angezeigt – allerdings rot unterlegt.
Abbildung 16.9 Der Name des Blogs muss fünf Buchstaben oder mehr haben.
16.12.2 Eigene Validatoren Um einen eigenen Validator in Aktion zu sehen, wollen wir festlegen, dass ein neuer Blog nicht den Namen „Extbase“ haben darf.
344
16.12 Validatoren Wir müssen hierfür zunächst eine Datei BlogValidator.php im Verzeichnis typo3conf/ext/simpleblog/Classes/Domain/Validator/ anlegen. Listing 16.33 Die Datei BlogValidator.php <meta type="array"> module <description>Sprachlabels für die Simpleblog Extension This blog contains the following posts: There are no posts in this blog! Add Blog Dieses Blog enthält die folgenden Posts: Keine Posts vorhanden! Blog hinzufügen
Wir haben hier je drei Labels für zwei Sprachen definiert. Mit der Angabe wird die Default-Sprache definiert – d.h. wenn keine andere spezielle Sprache im TYPO3 konfiguriert wurde oder wenn eine eventuell konfigurierte Sprache in den Sprachfiles nicht wieder gefunden wird. Über wird nun speziell die deutsche Sprache definiert. Letztlich kann man beliebige Bezeichner (Keys) für die Labels verwenden – wir empfehlen, einen strukturellen Namen zu verwenden. So haben wir hier beispielsweise blog.containpost verwendet, um darauf hinzudeuten, dass der Bezeichner im Umfeld der Blogs verwendet wird. Um nun darauf zuzugreifen, wird ein eigener View-Helper translate im Template verwendet – hier das Template index.html des Blogs: Listing 16.60 Änderung in der Blog-Template-Datei index.html …
…
…
Testen können Sie Ihr Setup sehr einfach, indem Sie in das Root-Template im Bereich Setup den folgenden TypoScript-Code platzieren:
362
16.16 Konfiguration mittels TypoScript Listing 16.61 TypoScript-Setup zur Änderung der Sprache config.language = de
16.16 Konfiguration mittels TypoScript TypoScript ist eine mächtige und komplexe Konfigurationsmöglichkeit, die zwar in TYPO3 4.x zur Verfügung steht – unter anderem aber TYPO3 5.x nicht mehr bzw. nicht in dieser Form. Selbstverständlich ist zwar geplant, TypoScript auch in TYPO3 5.x zur Verfügung zu stellen – sicher ist dies zum jetzigen Zeitpunkt allerdings nicht. Und so kann es passieren, dass Ihre Extension – wenn sie denn auf TypoScript basiert – mehr Änderung als normal benötigt, wenn Sie diese für FLOW3 (respektive TYPO3 5.x) fit machen wollen. Prinzipiell werden die TypoScript-Konfiguration im Pfad plugin.tx_extensionname ausgewertet. Dabei wird hier der Extension-Name in Kleinbuchstaben und ohne Underscores „_“ notiert. Extbase wertet dabei den folgenden TypoScript-Baum aus: Listing 16.62 TypoScript-Konfiguration // Das grundlegende TS-Element plugin.tx_extensionname { // Einstellungen für ganze Extensions. Diese sind unter // $this->settings im Controller und als {settings} // im FLUID-Template zugänglich. Hier kommen Ihre individuellen // Einstellungen hinein. settings { … } // Hier werden die Einstellungen für die Persistenzschicht getroffen // beispielsweise die storagePid persistence { // Automatisches Cache-Löschen aktivieren (1 - default) oder // deaktivieren enableAutomaticCacheClearing = 1 // StoragePid (siehe Kapitel 16.19.1) storagePid = … // Einstellungen für das Speichern neuer Datensätze classes { // kompletter Klassenname des Domain-Models [KlassenName] { // ID der Seite, auf der die neuen Datensätze gespeichert // werden sollen newRecordStoragePid = … mapping { // Name der Kind-Klasse (kann entweder per TCA // …['config']['foreign_class'] oder hier definiert werden tableName = … // Angabe der zu mappenden Spalten columns = … } } }
363
16 Entwicklung eines eigenen Plug-ins } // Einstellungen für den View und die Templates view { … } // Überschreiben der Lokalisierungen (Sprachlabels) _LOCAL_LANG { … } }
Um nun ein solches TypoScript zur Verfügung zu haben, werden wir das folgende in der Datei typo3conf/ext/simpleblog/Configuration/TypoScript/setup.txt speichern: Listing 16.63 TypoScript setup.txt für die Extension simpleblog plugin.tx_simpleblog { settings { key1 = value1 key2 = value2 key1.key3 = value3 controllers { Blog { maxItems = 5 } } } }
Damit das TypoScript nun auch geladen werden kann, erweitern wir die Datei ext_tables.php um die folgende Ladeanweisung: Listing 16.64 Ladeanweisung für das statische TypoScript t3lib_extMgm::addStaticFile($_EXTKEY, 'Configuration/TypoScript', 'Blog Example');
Durch diese Anweisung werden sowohl eine Datei setup.txt wie auch eine Datei constants.txt in dem angegebenen Verzeichnis spezifiziert, sofern diese vorhanden sind. Um diese nun in das System zu laden, müssen Sie im Modul Web > Template auf Ihr TypoScript-Template im Seitenbaum klicken und über Click here to edit whole template record den Datensatz bearbeiten. Im Tab Includes nun finden Sie im Abschnitt Include static (from extensions): auf der rechten Seite das statische Template. Mit einem Klick darauf und durch anschließendes Löschen des Caches ist dieses eingebunden.
364
16.17 Backend-Module mit Extbase
Abbildung 16.11 Zufügen des statischen Templates (vor dem Klick)
Um nun darauf zuzugreifen, gehen wir in den Blog-Controller zur Index-Action und geben dort das TypoScript-Settings-Array testweise komplett aus, um zu sehen, wie die Konfiguration dort genau ankommt: Listing 16.65 Ausgabe des Settings-Arrays in der Index-Action des Blog-Cotrollers … public function indexAction($name = 'Test') { debug($this->settings); $this->view->assign('blogs', $this->blogRepository->findAll()); …
Abbildung 16.12 Ausgabe des Debug-Statements
Nun könnten wir diese Konfigurationen direkt verwenden – beispielsweise: Listing 16.66 Zugriff auf die Settings-Konfiguration if ($this->settings['key2'] == 'value2') { … }
16.17 Backend-Module mit Extbase Extbase eignet sich nicht nur hervorragend, um Frontend-Plug-ins zu entwickeln – es ist natürlich auch möglich, damit Backend-Module zu entwerfen. Dies ist insofern eine revolutionäre Neuerung – war es doch bislang nicht möglich, im Backend ein vernünftiges Templating zu verwenden –, sodass zahlreiche Backend-Module die komplette Ausgabe in den Programmcode geschrieben haben.
365
16 Entwicklung eines eigenen Plug-ins Hierfür sind grundsätzlich einige zusätzliche Schritte notwendig. Zunächst muss das Backend-Modul in der Datei ext_tables.php registriert werden: Listing 16.67 Registrierung des Backend-Moduls in der Datei ext_tables.php … if (TYPO3_MODE === 'BE') { /** * Hiermit wird ein Backend-Modul registriert */ Tx_Extbase_Utility_Extension::registerModule( $_EXTKEY, 'web', // Modul soll Submodul von 'web' sein 'tx_simpleblog_m1', // Der Key des Submoduls '', // Position innerhalb des Moduls 'web' array( // Angabe sämtlicher Controller-Action // Kombinationen, die im Backend // erlaubt sein sollen 'Blog' => 'index,add,create,edit,update,delete', 'Post' => 'index,add,create,delete,addTag,createTag', 'Tag' => 'add,create' ), array( // Angabe von Zugriffsrechten, Icons // und Label-Datei 'access' => 'user,group', 'icon' => 'EXT:blog_example/ext_icon.gif', 'labels' => 'LLL:EXT:' . $_EXTKEY . '/Resources/Private/Language/locallang_mod.xml', ) ); /** * Hinzufügen eines Labels für die Context-Sensitive-Hilfe (CSH) */ t3lib_extMgm::addLLrefForTCAdescr('_MOD_web_BlogExampleTxBlogexampleM1', 'EXT:' . $_EXTKEY . '/Resources/Private/Language/locallang_csh.xml'); }
Im obigen Beispiel wird schlicht das gesamte bislang aufgebaute Simpleblog-Beispiel zusätzlich ins Backend verfrachtet, sodass man nun auch dort die Blogs, Posts und Tags anlegen kann. Selbstverständlich würde man dies bei einem reellen Beispiel trennen, sodass man eigene Backend-Actions eben nur im Backend registriert und damit aufrufbar macht.
16.18 Der Extbase-Kickstarter Gerade wenn Sie die letzten 100 Seiten dieses dritten Teils des Buches abgearbeitet haben, werden Sie sich sicherlich des Öfteren gefragt haben, ob man davon nicht einige Schritte automatisieren kann – beispielsweise in einer Art Kickstarter. Ingmar Schlecht hat tatsächlich im Sommer 2009 im Rahmen des Google Summer of Code (GSoC) damit begonnen, einen derartigen Kickstarter zu schreiben. Dieser ist bei Drucklegung zwar schon prinzipiell verwendbar – steckt aber noch komplett in den Kinderschuhen und verfügt daher über relativ wenige Features. Dies ist auch ein Grund, warum wir dieses Kapitel so weit hinten platziert haben. Wenn Sie die grundsätzliche Funktionsweise von
366
16.18 Der Extbase-Kickstarter Extbase von Grund auf erlernen, werden Sie es später auch leicht haben, den Kickstarter zu verwenden, um Ihnen Arbeit abzunehmen. Andersherum funktioniert dies natürlich nicht. Da wir denken, dass gerade bei den neuen Paradigmen wie MVC ein grundsätzliches Verständnis der Materie vonnöten ist, kann es nicht schaden, einen derartigen Kickstarter erst zu verwenden, wenn die Zusammenhänge komplett klar sind. Da zwischen Manuskriptabgabe und Erscheinen eines Buches bisweilen mehrere Monate liegen, kann es gut sein, dass der Extbase-Kickstarter dann bereits final veröffentlicht wurde und auch über andere oder tiefer gehende Features verfügt wie die, die wir Ihnen im Folgenden zeigen wollen. Aber sehr wahrscheinlich werden Sie nach der Lektüre dieses Buches leicht damit umgehen können. Wenn Sie trotzdem auf Probleme damit stoßen sollten – schreiben Sie uns einfach eine E-Mail:
[email protected] – wir helfen Ihnen dann gerne.
16.18.1 Installation des Extbase-Kickstarters Da der Extbase-Kickstarter zur Drucklegung noch nicht Teil des TYPO3-4.3-Pakets ist, muss dieser zunächst manuell aus dem Forge-SVN installiert werden.Die Adresse dabei lautet https://svn.typo3.org/TYPO3v4/Extensions/extbase_kickstarter/trunk. Unter Linux und Mac OS X können Sie einfach auf der Kommandozeile mittels svn co Adresse die Sourcen aus dem SVN auschecken. Unter Windows können Sie das Programm Tortoise verwenden. Nun kopieren Sie die Sourcen in ein Verzeichnis mit dem Namen extbase_kickstarter (wenn nicht schon bereits geschehen) und diesen Ordner in das Verzeichnis typo3conf/ ext/. Nun taucht der Extbase-Kickstarter im Extension-Manager unter Install Extensions bereits auf, und Sie können diesen mittels Klick auf das Plussymbol am Anfang direkt installieren.
Abbildung 16.13 Die Extension Extbase-Kickstarter im Extension-Manager
Nun erscheint im linken Funktionenmenü im Abschnitt Admin (da der Extbase-Kickstarter natürlich nur für Administratoren zugänglich ist) der Eintrag Extbase Kickstarter als letztes Element.
367
16 Entwicklung eines eigenen Plug-ins
Abbildung 16.14 Der Extbase-Kickstarter im Admin tools-Menü
Klicken Sie nun auf den Extbase-Kickstarter.
16.18.2 Überblick über den Arbeitsbereich Im nächsten Bild sehen Sie die vier grundsätzlichen Bereiche, die wir im Folgenden kurz anreißen wollen, bevor wir weiter in die Modellierung einsteigen: 1. Wenn Sie auf den Link unter 1 klicken, schiebt sich von links ein Bereich herein, in dem Sie die Extension-Konfiguration durchführen können. Dazu gehören der Name der Extension, der Extension-Key, der Status (alpha, beta, stable) und die Personen, die daran mitgewirkt haben. Wenn Sie die Extension nicht alleine entwickeln, sondern mit einem Team an Leuten, dann können Sie diese hier alle verewigen. 2. Auf der rechten Seite haben Sie ebenfalls einen Bereich, der Code Generator genannt wird. Zur Drucklegung war dieser Bereich allerdings noch leer und hatte keine Funktion. Gut denkbar, dass hier in Zukunft Möglichkeiten zur Steuerung der Codegenerierung zu finden sind. 3. Im unteren Bereich können Sie das erstellte Model abspeichern und wieder laden, ein neues anlegen sowie ein bestehendes löschen. Die momentane Codegenerierung findet beispielsweise erst statt, wenn Sie Ihr Modell abspeichern – darauf kommen wir in Kürze zu sprechen. 4. Hier schließlich startet die Modellierung. Das wird uns gleich im folgenden Unterkapitel beschäftigen.
368
16.18 Der Extbase-Kickstarter
Abbildung 16.15 Der Extbase-Kickstarter in seiner ganzen Pracht
16.18.3 Eingabe der Extension-Konfiguration Wir klicken nun also auf den Button für die Extension-Konfiguration (Nummer 1 in der vorhergehenden Abbildung). Nun können wir folgende Daten eingeben:
Einen aussagekräftigen Namen Den Extension-Key (wir haben hier natürlich einen beliebigen anderen genommen, damit uns keine Extension überschrieben wird)
Eine kurze Beschreibung Den Status (hier development) Einen Ansprechpartner – dieser kann über add angelegt werden Dort den Namen, die Rolle, E-Mail und Firma (sofern vorhanden) eintragen. – Teile dieser Informationen finden sich dann im Quellcode beispielsweise wieder. Nun sollte man zunächst erst einmal unten auf den Buttons Save klicken und warten, bis das Popup dies mit Saved! bestätigt hat.
369
16 Entwicklung eines eigenen Plug-ins
Abbildung 16.16 Eingabe der Extension Konfiguration
16.18.4 Modellierung Nun können wir mit der Modellierung starten. Zu Demonstrationszwecken und auch um einen Vergleich zu haben, wollen wir nun das Simpleblog-Beispiel 1:1 nachmodellieren, d h., wir benötigen ein Blog mit einem Titel, das kann Posts beinhalten (die ebenfalls einen Titel haben), und die Posts können mit einem Tag versehen werden (der einen Namen hat und zudem über eine M:M-Relation verknüpft ist). Gehen Sie nun mit der Maus auf die in Abbildung 16.15 unter Punkt 4 gezeigte grünblaue Fläche mit der Aufschrift New Model Object, klicken Sie mit der linken Maustaste darauf und ziehen nun nach unten auf die freie Fläche darunter, ohne die Maustaste währenddessen loszulassen. Wenn Sie nun mit der Maus stehen bleiben und die Maustaste loslassen, wurde ein neues Objekt erzeugt.
Abbildung 16.17 Ein neues Objekt wurde erzeugt.
370
16.18 Der Extbase-Kickstarter 16.18.4.1 Anlegen des Blog-Objekts Über einen Klick auf click to edit können Sie nun einen Namen für das Objekt vergeben – wir nehmen hier zunächst als Namen Blog. Über Klick auf OK wird der Name übernommen. Nun füllen wir die restlichen Elemente aus:
Bei Domain Object Settings wählen wir als Object Type Entity. Sie könnten hier auch Value Object auswählen, wenn Ihr Object einem solchen entsprechen würde. Zusätzlich wählen Sie Is aggregate root aus, da Sie wollen, dass Ihr Blog ein eigenes Repository erhält. Als Description könnten Sie nun auch eine kurze Beschreibung wie Das ist das Blog hinterlegen.
Sie können nun bei Default Actions eine Reihe von Actions auswählen, die Sie gerne vorbereitet hätten. Bei Drucklegung des Buches war dieser Bereich allerdings noch ohne Funktion, sodass Sie die Controller samt Actions später manuell anlegen mussten.
Nun folgen die Properties (Eigenschaften), die Sie mittels Add zufügen können. Als Property Name geben Sie den Namen der Eigenschaft an – bei uns Title. Der Property Type ist Text String. Als Description könnten Sie beispielsweise Titel des Blogs eingeben. Und da Sie sicherstellen sollten, dass das Attribut auch eingegeben wird, wählen Sie die Checkbox Is Required aus.
Schließlich brauchen Sie noch eine Relation, die Sie über Add im Abschnitt Relations anlegen können.
Hier tragen Sie als Name
Posts ein und als Type 0..* (foreign Key). Diese Einstellung entspricht der kommaseparierten Liste im Feld Posts.
Abbildung 16.18 Das Blog-Objekt
371
16 Entwicklung eines eigenen Plug-ins
16.18.5 Anlegen des Post-Objekts Letztlich wiederholen wir hier exakt die Schritte des vorherigen Kapitels, mit einer Ausnahme:
Die Relation zu Tags ist vom Typ 0..*
(aasociation table).
Abbildung 16.19 Das Post-Objekt
16.18.6 Anlegen des Tag-Objekts Auch hier halten wir uns wieder an die vorherige Anleitung mit dem Unterschied, dass wir hier keine Relation benötigen und der Bezeichner nicht Title, sondern Name heißt und das Objekt kein Aggregate Root ist.
Abbildung 16.20 Das Tag-Objekt
372
16.18 Der Extbase-Kickstarter
16.18.7 Relationen festlegen Nun, da wir alle drei relevanten Objekte positioniert haben, können wir die Relationen zwischen diesen festlegen. Dies erfolgt sehr einfach und vor allem sehr elegant. Gehen Sie mit der Maus auf den runden Kreis rechts neben dem Label Related Object im Post-Objekt. Nun klicken Sie darauf und lassen den Finger auf der linken Maustaste. Wenn Sie nun die Maus bewegen, sehen Sie eine blaue Pipe (eine dicke Linie), die sich mit Ihrer Maus mitbewegt. Nun bewegen Sie die Maus auf das Post-Objekt in die linke obere Ecke gleich rechts vom TYPO3-Logo – dort ist ebenfalls ein runder Kreis. Genau über diesem lassen Sie nun die Maustaste los. Jetzt sollten die beiden Objekte verbunden sein, und die Verbindung – die sogenannte Pipe – bewegt sich auch mit, wenn Sie die Objekte verschieben. Zusätzlich sehen Sie den Text [wired] rechts neben dem Kreis im Abschnitt Relations. Dasselbe wiederholen Sie mit den Posts – auch hier greifen Sie den Kreis im Relationsbereich des Post-Objects und ziehen diesen auf den Kreis in der linken oberen Ecke des TagObjekts. ACHTUNG – die Reihenfolge ist entscheidend Die Reihenfolge – also von welchem Element zu welchem Element Sie die Pipe ziehen – ist entscheidend. Versuchen Sie es genau andersherum, wie eben beschrieben, bekommen Sie eine Fehlermeldung und können Ihre Extension nicht abspeichern.
Abbildung 16.21 Fertig verknüpftes Domain-Model
373
16 Entwicklung eines eigenen Plug-ins Nun können Sie das Domain-Model über die Schaltfläche Save unten in der Mitte abspeichern.
Abbildung 16.22 Durch den Extbase-Kickstarter angelegte Verzeichnisse und Dateien
Wie Sie gut erkennen können, hat der Extbase-Kickstarter ganze Arbeit geleistet und nahezu alle wichtigen Verzeichnisse und Dateien angelegt. Lediglich die Controller fehlen bei Drucklegung noch – es ist aber damit zu rechnen, dass diese bei Erscheinen des Buches ebenfalls einwandfrei erzeugt werden. Aber selbst jetzt können Sie diese leicht durch das bisher erworbene Wissen anlegen. Eine Datei verdient eine besondere Hervorhebung – kickstarter.json. Diese ist dafür zuständig, dass eine derart erzeugte Extension mit dem Extbase-Kickstarter wieder gelesen und damit bearbeitet werden kann. Aber wie es bei Kickstarten so ist – dieser erzeugt den Code stets neu. Haben Sie also in den Dateien eine manuelle Änderung vorgenommen, so werden diese Änderungen beim erneuten Abspeichern allesamt wieder überschrieben. Legen Sie sich also in jedem Fall eine Sicherung davon an.
16.19 Weitere Extbase-Interna In diesem Kapitel sollen die Interna – meist Kleinigkeiten – aufgelistet werden, für die ein eigenes Kapitel zu überdimensioniert wäre.
16.19.1 StoragePid Jeder Datensatz liegt in TYPO3 auf einer einzelnen Seite. Diese Seite wiederum hat eine Seiten-ID, die als PID (Parent-ID) bezeichnet wird. Damit hat also auch jeder Datensatz eine ebensolche PID und ist damit einer speziellen Seite zuzuordnen.
374
16.19 Weitere Extbase-Interna Nun gibt es in Extbase einige Fälle, bei denen die Storage PID ermittelt werden muss:
Schreiben Aktualisieren Lesen 16.19.1.1 Schreibzugriffe Sobald Extbase versucht, Datensätze (beispielsweise neue Blog- oder Post-Einträge) abzuspeichern, muss ermittelt werden, welche PID diese bekommen sollen – dabei geht Extbase wie folgt vor: 1. Existiert der folgende TS-Schlüssel, so wird dieser verwendet: plugin. tx_[pluginName]. persistence. classes. [KlassenName]. newRecordStoragePid
Dabei ist anstelle von [pluginName] der komplette, kleingeschriebene Plug-in-Name ohne Unterstriche und anstelle von [KlassenName] der komplette Class-Name der Model-Datei einzugeben. 2. Existiert der folgende TS-Schlüssel, so wird dieser verwendet: config. tx_extbase. persistence. classes. [KlassenName]. newRecordStoragePid
Dabei ist anstelle von [KlassenName] der komplette Class-Name der Model-Datei einzugeben. 3. Existieren beide TS-Schlüssel nicht, wird der Datensatz auf der Seite mit der Weltkugel mit per PID = 0 gespeichert. 16.19.1.2 Aktualisieren Beim Aktualisieren wird die PID natürlich per Default nicht verändert. Wird also ein Datensatz auf der PID=5 angelegt, so wird dieser nach dem Aktualisieren dort auch wieder abgespeichert. Allerdings kann man den Speicherort in der Domäne verändern, wenn das Model die Eigenschaft $pid und entsprechende Getter- und Setter-Methoden hat. Damit ist es also möglich, einen Datensatz von einer Seite auf eine andere Seite zu verschieben.
375
16 Entwicklung eines eigenen Plug-ins 16.19.1.3 Lesen Auch das Lesen von Datensätzen gehorcht eigenen Regeln – diese werde wie folgt durchlaufen: 1. Falls das Feld Startingpoint im Backend der Plug-in-Konfiguration gesetzt ist, werden alle Datensätze, die dieses Plug-in betreffen, von der dort hinterlegten Seite geladen. 2. Wenn dies nicht der Fall ist, wird nach dem folgenden TS-Key gesucht und der dort hinterlegte Wert als PID verwendet: plugin. tx_[pluginName]. persistence. storagePid
Dabei ist anstelle von [pluginName] der komplette, kleingeschriebene Plug-in-Name ohne Unterstriche einzugeben. 3. Wenn dies auch nicht der Fall ist, wird nach dem folgenden TS-Key gesucht und der dort hinterlegte Wert als PID verwendet: config. tx_extbase. persistence. storagePid
4. Ist dies schließlich auch nicht der Fall, so wird für die PID der Wert 0 verwendet.
16.19.2 MVC-Request Nach einem MVC-Request landet man in einem Controller in einer bestimmten Action. Nun wäre es aber sehr brauchbar, wenn man auf genau diese Daten gesammelt zugreifen könnte. Dies ist über das $this->request-Objekt möglich. Die Eigenschaften dieses Objekts sind alle protected – insofern ist nur ein Zugriff mittels Getter möglich. Für alle Eigenschaften existieren aber natürlich entsprechende Getter – dafür müssen Sie einfach get vor die Eigenschaft stellen und den ersten Buchstaben der Eigenschaft großschreiben. Beispielsweise erreichen Sie die Eigenschaft pluginName über den Getter $this->request->getPluginName(). Tabelle 16.1 Eigenschaften des Request-Objekts
376
Eigenschaft
Beispielwert
Beschreibung
format
html
Das Ausgabeformat
method
GET
Die Übertragungsmethode (GET oder POST)
requestURI
http://….index.php?id=…
Die komplette URL des Requests
baseURI
http://127.0.0.1:8080/
Die URL des Hosts
16.19 Weitere Extbase-Interna Eigenschaft
Beispielwert
Beschreibung
controllerObjectNamePattern
Tx_@extension_Controller_ @controllerController
Die Vorlage zum Ermitteln des Controllers
pluginName
Pi1
Der Name des Plug-ins
controllerExtensionName
Simpleblog
Der Name der Extension
controllerName
Blog
Der Name des Controllers
controllerActionName
index
Der Name der Action
arguments
Array ( [blog] = 65 [action] = index [controller] = Blog
Alle GET-/POST-Parameter als Array
) dispateched
1
errors
Angabe, ob der Request durch den Dispatcher geschickt wurde Alle Fehlermeldungen als Array
16.19.3 FlashMessages realisieren Häufig möchte man den User über das informieren, was die Software im Hintergrund macht. Beispielsweise sind Statusmeldungen ein probates Mittel, um dem User mitzuteilen, was die letzte Action gerade gemacht hat. So präsentiert man z.B. ein Formular zum Anlegen eines Blog-Posts, und nach dem Abschicken wechselt man (im Erfolgsfall) per redirect() zur Index-Action, die die Liste aller Blogs anzeigt. Wenn nun auf dieser Seite ganz oben ein Hinweis in der Art „Ihr Post wurde erfolgreich angelegt“ angezeigt werden würde, wäre dies ein Schritt hin zu einer perfekten Benutzerführung. Der User wäre somit stets informiert, was die letzte Aktion gerade bewirkt hat. Sogenannte FlashMessages lösen diese Aufgabenstellung perfekt. Dazu gehört, dass man einen FlashMessage-Speicher zu jeder Zeit mit Nachrichten befüllen und diese dann gebündelt an einer anderen Stelle wieder ausgeben kann. Für das Handling von FlashMessages stehen Ihnen folgende Methoden zur Verfügung:
$this->flashMessages->add($message)
Zufügen einer Nachricht zum FlashMessage-Speicher
$this->flashMessages->getAll()
Ermittelt alle Nachrichten aus dem FlashMessage-Speicher und gibt diese zurück
$this->flashMessages->getAllAndFlush()
Ermittelt alle Nachrichten aus dem FlashMessage-Speicher, gibt diese zurück und löscht den Speicher anschließend
$this->flashMessages->flush()
Löscht den FlashMessage-Speicher
377
16 Entwicklung eines eigenen Plug-ins
$this->flashMessages->persist()
Normalerweise werden alle FlashMessages spätestens nach Ablauf des Skriptes wieder aus dem Speicher gelöscht. Diese Methode sorgt dafür, dass die FlashMessages in der Session des Users gespeichert werden und somit zu einem späteren Zeitpunkt immer noch vorhanden sind.
$this->flashMessages->loadFlashMessagesFromSession()
Hiermit werden die mittels persist() gespeicherten FlashMessages wieder aus der Session des Users ins Objekt geholt und stehen wieder über die obigen Befehle zur Verfügung.
378
17 17 Die Fluid-Template-Engine In einem MVC gesteuerten System kommt natürlich der View auch eine ganz besondere Aufmerksamkeit zuteil. Gerade durch die Trennung von Businesslogik und Darstellung, muss die View dieses auch ideal widerspiegeln können. Per Default besitzt die View lediglich eine sehr einfache Methode render() – die allerdings über keinerlei zusätzliche Funktionalitäten verfügt. Daher war schnell klar, dass man an dieser Stelle eine eigene Template-Engine benötigt, die sich perfekt in das MVC-Framework einpasst und zudem leistungsfähig genug ist, um auch komplizierteste Anwendungsfälle abdecken zu können. Zudem – und auch dies war eine Hauptforderung – sollte es möglich sein, dass Templates auch von einem Nichtprogrammierer (wie einem Designer) erstellt bzw. geändert werden können. Weiterhin sollte keine allzu exotische Sprache für das Template ersonnen werden, da diese ansonsten mit keiner der üblicherweise eingesetzten IDEs in irgendeiner Weise kompatibel gewesen wäre. Sebastian Kurfürst, der Erfinder von Fluid, hat im Herbst 2008, direkt nach den Berliner Transition Days, bestehende Systeme wie das klassische herkömmliche TYPO3 Templating (basierend auf Marker und Subparts), PHPTAL oder Smarty untersucht und verglichen und daraufhin schnell festgestellt, dass diese Systeme aus dem einen oder anderen Gründen nicht den Anforderungen entsprechen. Entweder musste man zur Verwendung über Programmierkenntnisse verfügen (wie dies beim klassischen System der Fall ist), oder man war zu eingeschränkt in den Möglichkeiten. Nachteile der klassischen Template-Engine
Basiert lediglich auf Marker und Subparts – dadurch überhaupt nicht flexibel genug Es gibt keinerlei Ablaufsteuerung (Control Flow) Keine Erweiterbarkeit Arbeitet ausschließlich mit Arrays – aber nicht mit Objekten
379
17 Die Fluid-Template-Engine Nachteile von Smarty
Basiert immer noch auf PHP4 Hat eine eigene proprietäre Syntax, die auf geschweiften Klammern beruht – damit ist keine Auto-Completion in einer IDE möglich
Die eingebauten Funktionen verfügen nicht über Namespaces – dadurch sind Kollisionen mit eigenen Funktionen möglich. Nachteile von PHPTAL
Das Markup basiert zwar auch wohlgeformtem XML – es ist aber nicht valide. Die Semantik ist sehr intuitiv und gewöhnungsbedürftig. PHP wird innerhalb des Templates verwendet – dadurch Trennung von Designer und Programmierer nicht haltbar
Keine Möglichkeit der Auto-Completion in IDEs Nur schwer mittels eigener Funktionen zu erweitern Die Lösung Und so war (wieder einmal) die Idee geboren, eine speziell angepasste und alle Vorteile vereinende Template-Engine selbst zu schreiben. Diese wurde vorläufig mit dem Arbeitstitel BEER3 bezeichnet – dann aber durch eine Community-Befragung in Fluid geändert. Fluid ist angetreten, um folgende Vorteile zu realisieren:
Die Templating-Engine soll einfach und elegant zu verwenden sein. Es soll ein einfaches und klares Interface existieren, mit dem man die Engine leicht erweitern kann.
Es sollen unterschiedliche Ausgabeformate – nicht nur HTML – damit unterstützt werden.
Die Engine soll den Template-Editor in vielerlei Hinsicht unterstützen – beispielsweise soll Auto-Completion in gängige IDEs möglich sein.
Programmiercode und Ausgabe müssen komplett getrennt sein.
17.1
Vorbereitung Damit es möglich ist, die nachfolgenden Beispiele allesamt gleich auszuprobieren, müssen wir zunächst eine kleine Testumgebung aufsetzen. Dafür installieren wir einerseits natürlich die Extensions extbase und fluid (die aber, wenn Sie das vorherige Kapitel verfolgt haben, bereits installiert sein sollten) und die Extension efempty (Extbase Fluid Empty) aus dem Extension Respository, die eine „leere“ Extension
380
17.1 Vorbereitung mit einem rudimentären Model Start (mit einer Eigenschaft title), einem Controller (StartController), einer Action (index) und einem dazugehörigen View zur Verfügung stellt. Nun platzieren Sie die Extension auf einer Seite, indem Sie das Content-Element-Plug-in auswählen und als Plug-in-Typ Empty Extbase/Fluid Container angeben.
Abbildung 17.1 Einfügen der Extension efempty als Content-Element
Wenn Sie nun die Extension im Frontend aufrufen, sollten Sie die folgende Ausgabe bekommen:
Abbildung 17.2 Ausgabe der Extension efempty im Frontend
Für die weiteren Ausführungen benötigen wir im Grunde zwei Dateien, einmal die Controller-Datei StartController.php im Verzeichnis typo3conf/ext/efempty/Classes/ Controller/ und dann die View-Datei index.html im Verzeichnis typo3conf/ext/ efempty/Resources/Private/Templates/Start/.
381
17 Die Fluid-Template-Engine
17.2
Basissyntax und einfache Ausgabe In der Controller-Datei – genauer in der Index-Action – wird nun über die Methode assign() ein Wert an die View übergeben: Listing 17.1 Einfache Zuweisung mittels assign() im Start-Controller public function indexAction() { … $this->view->assign('helloworld','Hello world!'); … }
Die entscheidende Stelle haben wir hier hervorgehoben. Die Methode assign() hat dabei zwei Parameter – über den ersten wird der Name festgelegt, unter dem der Wert der Zuweisung später im Template erreichbar sein soll, und über den ersten wird der Wert selbst spezifiziert. In unserem Beispiel wird also der Wert Hello world! an den Bezeichner helloworld übergeben. Nun betrachten wir uns die View-Datei, um zu sehen, wie das nun verarbeitet und ausgegeben wird: Listing 17.2 Ausgabe des Bezeichners helloworld in der View-Datei index.html This is the efempty extension! It works :-) {helloworld}
Der Bezeichner wird also lediglich in geschweifte Klammern geschrieben, und schon sorgt Fluid dafür, dass einerseits nachgesehen wird, welcher Wert für diesen Bezeichner vorhanden ist, und andererseits wird dafür gesorgt, dass der Wert ausgegeben wird.
17.2.1
Arrays
Um nun beispielsweise Arrays auszugeben, verwendet Fluid die sogenannte Punktsyntax (oder auch Objektzugriffssyntax). So kann über den Bezeichner mit dem Punkt auf den numerischen Index von Array zugegriffen werden. In den folgenden Codebeispielen notieren wir der Übersichtlichkeit halber oben die entscheidenden Codezeilen in der Action und darunter den Code im Template. Listing 17.3 Ausgabe eines numerischen Arrays // Code in der IndexAction des Start-Controllers $helloarray = array('Hello','World!'); $this->view->assign('helloworld',$helloarray); // Code im Index-Template {helloworld.0} {helloworld.1}
382
17.2 Basissyntax und einfache Ausgabe Man kann also über die Punktschreibweise ganz einfach auf den numerischen Index zugreifen. Natürlich funktioniert dies ähnlich für einen assoziativen Index: Listing 17.4 Ausgabe eines assoziativen Arrays // Code in der IndexAction des Start-Controllers $helloarray = array('hello' => 'Hello', 'world' => 'World!'); $this->view->assign('helloworld',$helloarray); // Code im Index-Template {helloworld.hello} {helloworld.world}
Hier wird einfach der assoziative Index angegeben, um darauf zuzugreifen. Mehrdimensionale Arrays erreichen Sie dementsprechend ganz ähnlich. Sie müssen nur einfach anstelle der Klammern in PHP Punkte notieren. $helloarray['foo'][1]['bar'] wird somit zu {helloworld.foo.1.bar}.
17.2.2
Objekte
Da Fluid grundsätzlich objektorientiert arbeitet, ist auch in diesem Bereich gute Unterstützung zu erwarten. Und tatsächlich sind das Ansprechen eines Objekts bzw. dessen Eigenschaften im Grunde exakt identisch zur Ansprache als Array. Listing 17.5 Anspache von Arrays // Code in der IndexAction des Start-Controllers $start = new Tx_Efempty_Domain_Model_Start; $start->setTitle("Hello World!"); $this->view->assign('helloworld', $start); // Code im Index-Template {helloworld.title}
Die Extension efempty enthält ja genau ein Model mit dem Namen Start, das als Klasse Tx_Efempty_Domain_Model_Start manifestiert wurde. Dort gibt es eine Eigenschaft title, und die wiederum wird mit dem Setter setTitle gesetzt. Nun wird also das ganze Objekt samt gesetztem Titel an die View übergeben, und dort wird der Titel mittels {helloworld.title} ausgegeben. Das klingt zunächst logisch und nachvollziehbar – ist aber nur die halbe Wahrheit. Im Model wird die Eigenschaft title nämlich als protected gekennzeichnet – d h., ein direkter Zugriff darauf ist somit natürlich nicht möglich. Daher wird auch in obigem Fall die Eigenschaft nicht direkt ausgelesen, sondern es wird stattdessen der im Model vorhandene Getter getTitle() verwendet. Und auch hier ist es einfach, auf Objekte zuzugreifen, die lediglich Unterobjekte sind. Trennen Sie diese einfach wieder mit einem Punkt. So könnte man mittels {blog.post.comment.0} auf den ersten Kommentar eines Posts zugreifen, der wiederum in einem Blog liegt.
383
17 Die Fluid-Template-Engine Das ist schon alles, was Sie über die Basissyntax von Fluid wissen müssen – das ist der sogenannte Core (auch Kern genannt). Alle weiteren Funktionalitäten werden von sogenannten ViewHelpern übernommen, die wir uns im Folgenden näher ansehen.
17.3
Fluid ViewHelper-Syntax Sämtliche Ausgabelogik nun wird von speziellen Tags, den sogenannten ViewHelpern, übernommen. Diese sorgen für Kontrollstrukturen, Schleifen, Links und ähnliche benötigte Funktionalitäten. Die Grundsyntax dabei ist wie folgt (beachten Sie, dass das kleine f und der Doppelpunkt sozusagen den Namensraum von Fluid angeben): …
Dabei entspricht jeder Tag (also jeder ViewHelper) einer eigenen ViewHelper-Klasse, die sich bei den mit Fluid mitgelieferten ViewHelpern im Verzeichnis typo3conf/ext/ fluid/Classes/ViewHelpers befindet. So gibt es beispielsweise den If-ViewHelper, der mit … spezifiziert wird. Die zugehörige Datei befindet sich also exakt hier: typo3conf/ext/fluid/Classes/ViewHelpers/IfViewHelper.php
Für einige ViewHelper sind komplexere Aufgaben vorgesehen (beispielsweise bei der Link-Erzeugung oder den Formularen). Hier wird ein eigenes, gleich benanntes Unterverzeichnis im ViewHelpers-Verzeichnis angelegt, das die zugehörigen ViewHelper enthält. Angesprochen werden diese dann über die Punktsyntax. So wird beispielsweise der Action-Link … über die folgende Datei verwaltet: typo3conf/ext/fluid/Classes/ViewHelpers/Link/ActionViewHelper.php
17.3.1
Namespace (Namensraum)
Wir haben nun immer ein kleines f: als Namensraum verwendet. Dies ist aber nicht ohne Grund so, sondern wurde implizit definiert. In jedem Fluid-Template kann man nämlich den verwendeten Namensraum mit folgendem Bezeichner definieren: Listing 17.6 Default-Deklaration des Fluid-Namensraumes {namespace f=Tx_Fluid_ViewHelpers}
Hier wird festgelegt, dass das kleine f letztlich immer als Abkürzung für Tx_Fluid_ViewHelper steht. Damit wird dann auch klar, warum bei f:for beispielsweise die Klasse Tx_Fluid_ViewHelper_For angesprochen wird.
384
17.3 Fluid ViewHelper-Syntax Sie können selbstverständlich auch Ihren eignen Namensraum festlegen – beispielsweise wenn Sie eigene ViewHelper schreiben. Dies wird uns in einem späteren Kapitel natürlich auch noch begegnen. Lassen Sie die Namespace-Deklaration weg, wird automatisch die obige DefaultDeklaration verwendet.
17.3.2
Argumente
Bei einigen ViewHelpern kann man Argumente übergeben, beispielsweise bei Links oder Formularen. Die Notation für solche Argumente folgt dabei der JSON-Syntax, die unter Umständen aus JavaScript bekannt ist. Dabei gilt folgende Festlegung:
Ein Objekt beginnt mit { und endet mit }. Es kann eine durch Kommata geteilte, ungeordnete Liste von Eigenschaften enthalten.
Eine Eigenschaft besteht aus einem Schlüssel und einem Wert, getrennt durch einen Doppelpunkt.
Ein Schlüssel ist eine Zeichenkette. Ein Wert ist ein Objekt, ein Array, eine Zeichenkette, eine Zahl oder einer der Ausdrücke TRUE oder FALSE Listing 17.7 Einige Beispiele für Argumente // über den Parameter arguments wird ein Argument übergeben ... read more // zwei oder mehr Argumente sind natürlich ebenfalls möglich Edit
17.3.2.1
Boolesche Ausdrücke
Beispielsweise kann dem If-ViewHelper ein Argument übergeben, das vom Typ Boolean sein soll und darauf geprüft wird. Die boolesche Bedingung wird dabei wie folgt behandelt:
Ist der übergebene Wert vom Typ Boolean (TRUE oder FALSE), wird dieser verwendet. Ist der übergebene Wert vom Typ String (eine Zeichenkette) und ist der String false oder leer, so wird der boolesche Wert FALSE verwendet.
Ist der übergebene Wert vom Typ Numeric (eine natürliche Zahl) und ist diese Zahl größer als null, so wird TRUE verwendet.
Ist der übergebene Wert vom Typ Array oder ist es ein Countable Object (zählbares Objekt), dann wird TRUE verwendet, wenn es mindestens ein Element oder Objekt enthält.
385
17 Die Fluid-Template-Engine
Ist der übergebene Wert vom Typ Object (ist es also ein Objekt), so wird TRUE zurückgegeben.
In allen anderen Fällen wird FALSE zurückgegeben. 17.3.2.2
Komplexe boolesche Ausdrücke
Oftmals kann es nötig sein, auch komplexere boolesche Ausdrücke zu evaluieren. Stellen wir uns einfach einmal vor, dass wir eine Art Menü haben, das alle verfügbaren Seiten anzeigt. Nun soll aber die aktuell ausgewählte Seite im Menü etwas hervorgehoben werden. Dies könnte man vielleicht wie folgt notieren: Listing 17.8 Beispiel für einen komplexen booleschen Ausdruck <strong>…
Hier wird mit dem Operator == geprüft, ob die Seite in der Schleife identisch mit der aktuellen Seite ist, und wenn dem so ist, wird die Ausgabe mit einem <strong>-Tag hervorgehoben. Ein komplexer boolescher Ausdruck kann dabei das folgende Format haben: Ausdruck1 Operator Ausdruck 2
Als Operatoren sind dabei folgende zugelassen:
== (identisch) > (größer) >= (größer oder gleich) < (kleiner) ...
Ein Objekt-Zugriffspfad (dies wird der übliche Zugriff sein) 17.3.2.3
Arrays
Für einige ViewHelper (wie dem SelectViewHelper, der eine Select-Box erzeugt) ist es notwendig, ein Array als Argument zu übergeben. Die grundlegende Syntax orientiert sich wieder an der JSON-Syntax. Dabei steht auf der linken Seite der Eigenschaft jeweils ein
386
17.4 ViewHelper-Übersicht Bezeichner, für den ausschließlich Buchstaben zugelassen sind. Auf der rechten Seite dagegen kann Folgendes stehen:
Eine Nummer {a : 1, b : 2, c Ein String {a : 'String1',
: 3}
b : "Ein zweiter String – hier müssen doppelte Anführungszeichen \" escapet werden, aber nicht einfache ' Anführungszeichen"}
Ein (verschachteltes) Array {a : {
a1 : "String1", a2 : "String2"
}, b : "String3" }
Eine Objekt-Zugriffspfad {a1 : objekt1.eigenschaft1,
17.4
a2: objekt2}
ViewHelper-Übersicht In Fluid sind, wie bereits erwähnt, zahlreiche nützliche ViewHelper bereits eingebaut. Im Folgenden finden Sie eine alphabetische Übersicht über alle verfügbaren ViewHelper, die mit der Installation der Extension fluid mitgeliefert werden. Sollten Ihnen diese nicht ausreichen, so können Sie ohne großen Aufwand eigene ViewHelper erstellen – dies wird im nachfolgenden Kapitel näher beleuchtet.
17.4.1
alias
Mit dem ViewHelper alias können Sie einen neuen Namen vergeben. Dies ist insbesondere dann hilfreich, wenn Sie damit längere Objektpfade abkürzen. Nehmen wir einmal an, der Objektpfad objekt.eigenschaft1.eigenschaft2 hat den Wert wert1. Dann gibt der folgende ViewHelper genau zweimal diesen Wert aus, da beide Zugriffe identisch sind: Listing 17.9 ViewHelper alias
Verwendung {x.eigenschaft2} ist das selbe wie {y}
387
17 Die Fluid-Template-Engine
// Ausgabe wert1 ist das selbe wie wert1
Tabelle 17.1 Argumente für den ViewHelper alias Name
Typ
benötigt
Default-Wert
Bemerkung
map
array
ja
-
-
17.4.2
base
Dieser ViewHelper sorgt für ein -Tag. Dabei kann kein Argument übergeben werden – der Inhalt des Tags ist immer die aktuelle Domain. Listing 17.10 ViewHelper base
// Verwendung // Ausgabe
17.4.3
cObject
Über diesen ViewHelper ist es möglich, ein TypoScript-Objekt auszugeben. Mit dem Argument typoscriptObjectPath können Sie dabei den Pfade spezifizieren und über currentValueKey den entsprechenden Namen desjenigen Schlüssels, der als current-Wert verwendet werden soll. Listing 17.11 ViewHelper cObject // TypoScript-Setup lib.test = TEXT lib.test.value = Diese Ausgabe kommt vom TypoScript! // Verwendung im Template Test // Ausgabe Diese Ausgabe kommt vom TypoScript!
Tabelle 17.2 Argumente für den ViewHelper cObject
388
Name
Typ
benötigt
Default-Wert
Bemerkung
typoscriptObjectPath
string
ja
–
Wenn der Pfad nicht existiert, wird eine Fehlermeldung ausgegeben.
currentValueKey
string
nein
–
–
17.4 ViewHelper-Übersicht
17.4.4
count
Mit diesem ViewHelper (der lediglich ein Wrapper der PHP-Funktion count() ist), kann die Anzahl von Elementen eines Objekts oder Arrays zurückgegeben werden. Listing 17.12 ViewHelper count // Verwendung // Ausgabe 2
Tabelle 17.3 Argumente für den ViewHelper count Name
Typ
benötigt
Default-Wert
Bemerkung
subject
array
ja
–
Array oder ObjectStorage, in dem die Elemente gezählt werden
17.4.5
cycle
Über diesen ViewHelper lässt sich eine sogenannte Rotation zwischen vorgegebenen Werten erzeugen. Damit kann man beispielsweise iterierende Zeilen realisieren, da diese immer zwischen einem Wert für die gerade Zeile und einem anderen Wert für die ungerade Zeile wechseln. Natürlich sind auch Rotationen mit mehr als zwei Elementen möglich. Listing 17.13 ViewHelper cycle // Verwendung
// Ausgabe
- 1 - odd
- 2 - even
- 3 - odd
- 4 - even
- 5 - odd
In diesem Beispiel wird über die For-Schleife (dem For-ViewHelper) das Array mit den fünf Werten durchgegangen. Innerhalb dieser Schleife entscheidet der Cycle-ViewHelper, welcher Wert jeweils dafür existieren soll. Da dort nur die zwei Werte odd und even existieren, wird jedem Schleifenwert erst odd und dann dem nächsten even zugeordnet. Der übernächste bekommt wieder odd und so weiter. Hätte Cycle drei Werte gehabt, so wären
389
17 Die Fluid-Template-Engine die ersten zwei Werte doppelt zugeordnet worden und der dritte nur einmal im ersten Durchlauf, da ja nur fünf Elemente aus der For-Schleife existieren. Tabelle 17.4 Argumente für den ViewHelper cycle Name
Typ
benötigt
Default-Wert
Bemerkung
as
string
ja
–
Der Name für die iterierende Variable, auf die innerha b des ViewHelpers zugegriffen werden kann
values
array
ja
–
Das Array oder SplObjectStorage, über das iteriert wird
17.4.6
debug
Dieser ViewHelper ist ein Wrapper für die TYPO3-eigene Debug-Funktion. Dabei können Sie als Argument einen Titel zur besseren Übersichtlichkeit ausgeben lassen. Listing 17.14 ViewHelper debug // Verwendung {object}
Tabelle 17.5 Argumente für den ViewHelper debug Name
Typ
benötigt
Default-Wert
Bemerkung
title
string
nein
–
–
17.4.7
else
Der Else-ViewHelper macht nur in Zusammenhang mit dem If-ViewHelper Sinn und wird dementsprechend dort behandelt.
17.4.8
for
Der For-ViewHandler ist genau genommen (noch) ein Foreach-ViewHandler, da dieser letztlich die foreach()-Funktion von PHP nachbildet. Über das Argument as wird ein neuer Name für das aktuelle Schleifenobjekt festgelegt, den man ganz normal ansprechen kann. Über das Argument key kann man dabei auf den Schlüssel zugreifen.
390
17.4 ViewHelper-Übersicht Listing 17.15 ViewHelper For // Verwendung {wert} // Ausgabe 1ab4 // Verwendung
//Ausgabe
name1 name2 name3 name4
Tabelle 17.6 Argumente für den ViewHelper for Name
Typ
benötigt
Default-Wert
Bemerkung
each
array
ja
–
Das Array, über das iteriert wird
as
string
ja
–
Der Name der Iterationsvariablen
key
string
nein
–
Der Name der Variablen, die den Schlüssel speichert
17.4.9
form
Über den Form-ViewHelper können umfangreiche Formulare aufgebaut werden. Prinzipiell wird zuerst das Form-Tag selbst definiert und darin die verschiedenen Eingabefelder. Listing 17.16 ViewHelper form // Verwendung … // Ausgabe
391
17 Die Fluid-Template-Engine Wie gut zu erkennen ist, wird die Formular-Action auf die URL der aktuellen Seite gesetzt – einschließlich der Angabe für den (Default-)Controller. Als Formular-Methode wird per Default POST verwendet. Zusätzlich befinden sich aber noch drei Hidden-Felder, die sowohl die Extension, den Controller wie auch die Action spezifizieren. Diese Angaben sind unter Umständen notwendig, wenn man nach dem Abschicken noch Zugriff auf den Referrer benötigt. Tabelle 17.7 Argumente für den ViewHelper form
392
Name
Typ
benötigt
Default-Wert
Bemerkung
accesskey
string
nein
–
Keyboard-Shortcut
action
string
nein
Die aktuelle URL
Die Form-Action
additionalAttributes
array
nein
–
Hiermit können zusätzliche Attribute für das -Tag angegeben werden
arguments
string
nein
–
Zusätzliche Argumente
class
string
nein
–
CSS-Klasse(n)
controller
string
nein
Der aktuelle Controller
Der Controller, der nach dem Abschicken aufgerufen werden soll
dir
string
nein
ltr
Textrichtung: ltr oder rtl
enctype
string
nein
–
MIME-Type für die Übertragung
extensionName
string
nein
Die aktuelle Extension
Der Extension-Name ohne tx und unterstrichen
id
string
nein
–
ID des Formulars
lang
string
nein
–
Language-Attribut (RFC 1766)
method
string
nein
post
POST oder GET
name
string
nein
–
Der Name der Form
onreset
string
nein
–
JS-Handler für onReset
onsubmit
string
nein
–
JS-Handler für onSubmit
pageUid
integer
nein
Die aktuelle Page-UID
Die ID der Seite, zu der gesprungen werden soll
pluginName
string
nein
Das aktuelle Plug-in
Der Plug-in-Name
object
mixed
nein
–
Ein Form-Objekt
options
array
nein
–
Typolink-Optionen
pageType
integer
nein
0
Der Seitentyp (typenum)
style
string
nein
–
Inline CSS Styles
17.4 ViewHelper-Übersicht Name
Typ
benötigt
Default-Wert
Bemerkung
tabindex
integer
nein
–
TabIndex-Angabe
title
string
nein
–
Title-Attribut (Tooltipp-Text)
17.4.9.1
form.checkbox
Diesen ViewHelper können Sie zur Erzeugung einer Checkbox verwenden. Listing 17.17 ViewHelper form.checkbox // Verwendung // Ausgabe // Verwendung – Vorausgefüllt, wenn object.name == 5 ist // Verwendung – Binden an die Objekt-Eigenschaft "interessen"
Tabelle 17.8 Argumente für den ViewHelper form.checkbox Name
Typ
benötigt
Default-Wert
Bemerkung
accesskey
string
additionalAttributes
array
nein
–
Keyboard-Shortcut
nein
–
Hiermit können zusätzliche Attribute für das -Tag angegeben werden
checked
string
nein
–
Wenn auf den Wert checked gesetzt, dann ist die Checkbox vorausgewählt.
class
string
nein
–
CSS-Klasse(n)
dir
string
nein
ltr
Textrichtung: ltr oder rtl
disabled
string
nein
–
Deaktiviert die Checkbox
id
string
nein
–
ID des Formulars
lang
string
nein
–
Language-Attribut (RFC 1766)
name
string
nein
–
Der Name der Selectbox
property
string
nein
–
Name der Objekteigenschaft, wenn im Form-Tag das objectAttribut verwendet wurde. Dann werden hier das name- und value-Attr but ignoriert.
style
string
nein
–
Inline CSS Styles
393
17 Die Fluid-Template-Engine Name
Typ
benötigt
Default-Wert
Bemerkung
tabindex
integer
nein
–
TabIndex-Angabe
title
string
nein
–
Title-Attribut (Tooltipp-Text)
17.4.9.2
form.error
Alle Fehler, die in Zusammenhang mit dem Form-ViewHelper auftreten, können über diesen ViewHelper angezeigt werden: Listing 17.18 ViewHelper form.error // Verwendung {error.message}
<strong>{error.propertyName}: {error.code}: {errorDetail.message}
// Ausgabe Validation errors for argument "newPost"
<strong>newPost: 1245107351: Validation errors for property "title"
Tabelle 17.9 Argumente für den ViewHelper form.error Name
Typ
benötigt
Default-Wert
Bemerkung
as
string
nein
error
Der Name des Fehlerobjekts (so wie dieses dann in Fluid angesprochen werden kann)
for
string
ja
–
Der Name der Objekteigenschaft (wird später auch Objekte aufnehmen können)
17.4.9.3
form.hidden
Über diese ViewHelper können sogenannte Hidden-Fields in Formulare eingebracht werden.
394
17.4 ViewHelper-Übersicht Listing 17.19 ViewHelper form.hidden // Verwendung // Ausgabe
Gut zu sehen ist, dass das Name-Attribut automatisch in den Namensraum der Extension (tx_efempty_pi1) verschoben wird. Tabelle 17.10 Argumente für den ViewHelper form.hidden Name
Typ
benötigt
Default-Wert
Bemerkung
accesskey
string
nein
–
Keyboard-Shortcut
additionalAttributes
array
nein
–
Hiermit können zusätzliche Attribute für das -Tag angegeben werden.
class
string
nein
–
CSS-Klasse(n)
dir
string
nein
ltr
Textrichtung: ltr oder rtl
id
string
nein
–
ID des Formulars
lang
string
nein
–
Language-Attribut (RFC 1766)
name
string
nein
–
Der Name des Feldes
property
string
nein
–
Name der Objekteigenschaft, wenn im Form-Tag das object-Attribut verwendet wurde. Dann werden hier das name- und value-Attribut ignoriert.
style
string
nein
–
Inline CSS Styles
tabindex
integer
nein
–
TabIndex-Angabe
title
string
nein
–
Title-Attr but (Tooltipp-Text)
value
string
nein
–
Der Wert des Input-Tags
17.4.9.4
form.password
Input-Boxen, deren Eingabe verschleiert ist (sodass man diese nicht sehen kann und stattdessen * angezeigt wird), können mit diesem ViewHelper erzeugt werden. Listing 17.20 ViewHelper form.password // Verwendung // Ausgabe
395
17 Die Fluid-Template-Engine Tabelle 17.11 Argumente für den ViewHelper form.password Name
Typ
benötigt
Default-Wert
Bemerkung
accesskey
string
nein
–
Keyboard-Shortcut
additionalAttributes
array
nein
–
Hiermit können zusätzliche Attribute für das -Tag angegeben werden.
class
string
nein
–
CSS-Klasse(n)
dir
string
nein
ltr
Textrichtung: ltr oder rtl
disabled
string
nein
–
Deaktiviert die Checkbox
id
string
nein
–
ID des Formulars
lang
string
nein
–
Language-Attr but (RFC 1766)
maxlength
string
nein
–
Die maximale Länge des Passwortes
name
string
nein
–
Der Name des Feldes
property
string
nein
–
Name der Objekteigenschaft, wenn im Form-Tag das objectAttribut verwendet wurde. Dann werden hier das name- und value-Attribut ignoriert.
readonly
string
nein
–
Ist dieser Wert gesetzt, kann das Passwort nicht mehr geändert werden.
style
string
nein
–
Inline CSS Styles
tabindex
integer
nein
–
TabIndex-Angabe
title
string
nein
–
Title-Attribut (Tooltipp-Text)
value
string
nein
–
Der Wert des Input-Tags
17.4.9.5
form.radio
Über diesen ViewHelper können Sie Radio-Buttons realisieren. Listing 17.21 ViewHelper form.radio // Verwendung // Ausgabe // Verwendung – Vorausgefüllt, wenn object.name == 5 ist // Verwendung – Binden an die Objekt-Eigenschaft "newsletter" ja nein
396
17.4 ViewHelper-Übersicht Tabelle 17.12 Argumente für den ViewHelper form.radio Name
Typ
benötigt
Default-Wert
Bemerkung
accesskey
string
nein
–
Keyboard-Shortcut
additionalAttributes
array
nein
–
Hiermit können zusätzliche Attribute für das -Tag angegeben werden.
checked
string
nein
–
Wenn auf den Wert checked gesetzt, dann ist die Checkbox vorausgewählt.
class
string
nein
–
CSS-Klasse(n)
dir
string
nein
ltr
Textrichtung: ltr oder rtl
disabled
string
nein
–
Deaktiviert die Checkbox
id
string
nein
–
ID des Formulars
lang
string
nein
–
Language-Attribut (RFC 1766)
name
string
nein
–
Der Name der Selectbox
property
string
nein
–
Name der Objekteigenschaft, wenn im Form-Tag das objectAttribut verwendet wurde. Dann werden hier das name- und value-Attr but ignoriert.
style
string
nein
–
Inline CSS Styles
tabindex
integer
nein
–
TabIndex-Angabe
title
string
nein
–
Title-Attr but (Tooltipp-Text)
17.4.9.6
form.select
Select-Boxen können mithilfe dieses ViewHelpers bequem erzeugt werden. Sie können dabei entweder selbst definierte Werte verwenden oder sogar Objekteigenschaften als Werte verwenden. Selbst definierte Werte Listing 17.22 ViewHelper form.select – selbst definierte Werte // Verwendung // Ausgabe <select name="tx_efempty_pi1[Farben]"> Rote Farbe Blaue Farbe Gelbe Farbe
397
17 Die Fluid-Template-Engine Über das Attribut selectedValue="blau" beispielsweise könnte man nun die blaue Farbe vorauswählen. Objekteigenschaften als Werte Listing 17.23 ViewHelper form.select – Objekteigenschaften als Werte // Verwendung
In diesem Fall wird ein Objekt mit dem Namen userArray übergeben, das sämtliche User enthält. Diese haben eine Eigenschaft vorname, die als Label ausgegeben wird. Der dazugehörige Wert wiederum ist die UID des Users. Beide Werte (sowohl das Label wie auch der Wert) werden natürlich nicht direkt ermittelt, sondern über die zugehörigen Getter-Methoden. In obigen Beispiel wird also für den Wert die Funktion $user->getId() bemüht und für das Label die Funktion $user->getVorname(). Tabelle 17.13 Argumente für den ViewHelper form.select
398
Name
Typ
benötigt
Default-Wert
Bemerkung
accesskey
string
nein
–
Keyboard-Shortcut
additionalAttributes
array
nein
–
Hiermit können zusätzliche Attribute für das -Tag angegeben werden.
class
string
nein
–
CSS-Klasse(n)
dir
string
nein
ltr
Textrichtung: ltr oder rtl
id
string
nein
–
ID des Formulars
lang
string
nein
–
Language-Attribut (RFC 1766)
multiple
string
nein
–
Erlauben, ob mehrere Felder ausgewählt werden können
name
string
nein
–
Der Name des Feldes
options
array
nein
–
Entweder ein Objekt oder ein assoziatives Array der Werte, getrennt mit einem Doppelpunkt. Der erste Wert wird als Schlüssel verwendet, der zweite als Label.
optionLabelField
string
nein
–
Wenn bei options ein Objekt angegeben wurde, werden hier über eine Getter-Funktion die Label ermittelt.
17.4 ViewHelper-Übersicht Name
Typ
benötigt
Default-Wert
Bemerkung
optionValueField
string
nein
–
Wenn bei options ein Objekt angegeben wurde, werden hier über eine Getter-Funktion die Werte ermittelt.
property
string
nein
–
Name der Objekteigenschaft, wenn im Form-Tag das objectAttribut verwendet wurde. Dann werden hier das name- und value-Attr but ignoriert.
size
integer
nein
–
Größe (Höhe) der Select-Box
style
string
nein
–
Inline CSS Styles
tabindex
integer
nein
–
TabIndex-Angabe
title
string
nein
–
Title-Attribut (Tooltipp-Text)
value
string
nein
–
Der Wert des Input-Tags
17.4.9.7
form.submit
Dieser ViewHelper wird zur Erzeugung eines Submit-Buttons verwendet. Listing 17.24 ViewHelper form.submit // Verwendung Abschicken //Ausgabe
Tabelle 17.14 Argumente für den ViewHelper form.submit Name
Typ
benötigt
Default-Wert
Bemerkung
accesskey
string
nein
–
Keyboard-Shortcut
additionalAttributes
array
nein
–
Hiermit können zusätzliche Attribute für das -Tag angegeben werden.
class
string
nein
–
CSS-Klasse(n)
dir
string
nein
ltr
Textrichtung: ltr oder rtl
id
string
nein
–
ID des Formulars
lang
string
nein
–
Language-Attribut (RFC 1766)
name
string
nein
–
Der Name des Feldes
style
string
nein
–
Inline CSS Styles
tabindex
integer
nein
–
TabIndex-Angabe
399
17 Die Fluid-Template-Engine Name
Typ
benötigt
Default-Wert
Bemerkung
title
string
nein
–
Title-Attribut (Tooltipp-Text)
value
string
nein
–
Der Wert des Input-Tags
17.4.9.8
form.textarea
Über diesen ViewHelper ist es möglich, ein Textarea-Feld in einem Formular zu erzeugen. Listing 17.25 ViewHelper form.textarea // Verwendung // Ausgabe Das ist ein Default-Text der innerhalb der Textarea angezeigt wird!
Tabelle 17.15 Argumente für den ViewHelper form.textarea
400
Name
Typ
benötigt
Default-Wert
Bemerkung
accesskey
string
nein
–
Keyboard-Shortcut
additionalAttributes
array
nein
–
Hiermit können zusätzliche Attribute für das -Tag angegeben werden.
class
string
nein
–
CSS-Klasse(n)
cols
integer
nein
–
Anzahl der Spalten
dir
string
nein
ltr
Textrichtung: ltr oder rtl
id
string
nein
–
ID des Formulars
lang
string
nein
–
Language-Attribut (RFC 1766)
name
string
nein
–
Der Name des Feldes
property
string
nein
–
Name der Objekteigenschaft, wenn im Form-Tag das objectAttribut verwendet wurde. Dann werden hier das name- und value-Attribut ignoriert.
rows
integer
nein
–
Anzahl der Zeilen
style
string
nein
–
Inline CSS Styles
tabindex
integer
nein
–
TabIndex-Angabe
title
string
nein
–
Title-Attribut (Tooltipp-Text)
value
string
nein
–
Der Wert des Input-Tags
17.4 ViewHelper-Übersicht 17.4.9.9
form.textbox
Mit diesem View-Helper erzeugen Sie eine klassische Input-Textbox in Ihrem Formular. Listing 17.26 ViewHelper form.textbox // Verwendung // Ausgabe
Tabelle 17.16 Argumente für den ViewHelper form.textbox Name
Typ
benötigt
Default-Wert
Bemerkung
accesskey
string
nein
–
Keyboard-Shortcut
additionalAttribues
array
nein
–
Hiermit können zusätzliche Attribute für das -Tag angegeben werden.
class
string
nein
–
CSS-Klasse(n)
dir
string
nein
ltr
Textrichtung: ltr oder rtl
id
string
nein
–
ID des Formulars
lang
string
nein
–
Language-Attribut (RFC 1766)
name
string
nein
–
Der Name des Feldes
property
string
nein
–
Name der Objekteigenschaft, wenn im Form-Tag das objectAttribut verwendet wurde. Dann werden hier das name- und value-Attr but ignoriert.
style
string
nein
–
Inline CSS Styles
tabindex
integer
nein
–
TabIndex-Angabe
title
string
nein
–
Title-Attr but (Tooltipp-Text)
value
string
nein
–
Der Wert des Input-Tags
17.4.9.10 form.upload Mithilfe dieses ViewHelpers können Sie Upload-Formulare realisieren, mit denen es möglich ist, Dateien auf den Server zu übertragen. Wichtig ist dabei, dass das Formular selbst die Option enctype="multipart/formdata" gesetzt hat!
401
17 Die Fluid-Template-Engine Listing 17.27 ViewHelper form.upload // Verwendung // Ausgabe
Tabelle 17.17 Argumente für den ViewHelper form.upload Name
Typ
benötigt
Default-Wert
Bemerkung
accesskey
string
nein
–
Keyboard-Shortcut
additionalAttributes
array
nein
–
Hiermit können zusätzliche Attribute für das -Tag angegeben werden.
class
string
nein
–
CSS-Klasse(n)
dir
string
nein
ltr
Textrichtung: ltr oder rtl
id
string
nein
–
ID des Formulars
lang
string
nein
–
Language-Attribut (RFC 1766)
name
string
nein
–
Der Name des Feldes
property
string
nein
–
Name der Objekteigenschaft, wenn im Form-Tag das objectAttribut verwendet wurde. Dann werden hier das name- und value-Attribut ignoriert.
style
string
nein
–
Inline CSS Styles
tabindex
integer
nein
–
TabIndex-Angabe
title
string
nein
–
Title-Attribut (Tooltipp-Text)
value
string
nein
–
Der Wert des Input-Tags
17.4.10 format Die ViewHandler in dieser Gruppe sind primär dafür zuständig, einen Eingabewert in ein anderes Format umzuwandeln. 17.4.10.1 format.crop Dieser ViewHandller dient dazu, um einen Text nach einer bestimmten Anzahl von Zeichen abzuschneiden. Listing 17.28 ViewHandler format.crop // Verwendung Das ist ein sehr langer Text!
402
17.4 ViewHelper-Übersicht
// Ausgabe Das ist ein... // Verwendung Das ist ein sehr langer Text! // Ausgabe Das ist ein [mehr]
Über die Eigenschaft maxCharacters wird die maximale Anzahl an Buchstaben bestimmt, die ausgegeben werden dürfen. Der ViewHelper bricht die Darstellung unterhalb dieser Grenze ab und fügt drei Punkte hinzu, es sei denn, es ist mittels des Arguments append ein anderer String definiert. Tabelle 17.18 Argumente für den ViewHandler format.crop Name
Typ
benötigt
Default-Wert
Bemerkung
append
string
nein
–
String, der an der Stelle zugefügt wird, an der abgeschnitten wird
maxCharacters
integer
ja
–
Stelle, an der abgeschnitten wird
respectWordBoundaries
boolean
nein
1
Schneidet nur an Wortgrenzen ab
17.4.10.2 format.currency Wandelt die Eingabe in einen Währungs-String um. Listing 17.29 ViewHelper format.currency // Verwendung 123456 // Ausgabe 1.234.567,00 €
Tabelle 17.19 Argumente für den ViewHandler format.currency Name
Typ
benötigt
Default-Wert
Bemerkung
currencySign
string
nein
–
Das Währungssymbol
decimalSeparator
string
nein
–
Trennzeichen für die Dezimal-Darstellung
thousandsSeparator
string
nein
–
Trennzeichen für die Tausender-Darstellung
403
17 Die Fluid-Template-Engine 17.4.10.3 format.date# Hiermit stehen Ihnen alle Möglichkeiten der Datumsformatierung zur Verfügung. Dabei wird als Eingabe ein DateTime-Objekt erwartet. Ebenso möglich ist eine Berechnung – ausgehend vom aktuellen Datum. Listing 17.30 ViewHelper format.date // Verwendung now // Ausgabe 23.09.2009 - 22:28:27 // Verwendung +1 week 2 days 4 hours 2 seconds // Ausgabe 03.10.2009 - 02:27:09
Mögliche Eingabe- und Formatierungsparameter sind auf der folgenden Seite beschrieben: http://www.php.net/manual/en/function.strtotime.php
Tabelle 17.20 Argumente für den ViewHandler form.date Name
Typ
benötigt
Default-Wert
Bemerkung
format
string
nein
Y-m-d
Hiermit wird die Formatierung festgelegt.
17.4.10.4 format.html Dieser ViewHandler rendert einen String gemäß der in TYPO3 festgelegten Funktion parseFunc. Es ist über das Argument parseFuncTSPath möglich, eine eigene parseFuncFunktion zu hinterlegen. Listing 17.31 ViewHandler format.html // Verwendung String1 String2. Das ist ein Link. // Ausgabe
String1 String2. Das ist ein Link.
Tabelle 17.21 Argumente für den ViewHandler format.html
404
Name
Typ
benötigt
Default-Wert
Bemerkung
parseFuncTSPath
string
nein
lib.parseFunc_RTE
Pfad zu einer eigenen parseFunc-Funktion
17.4 ViewHelper-Übersicht 17.4.10.5 format.nl2br Dies ist letztlich nur ein Wrapper für die PHP-Funktion nl2br(). Listing 17.32 ViewHandler format.nl2br // Verwendung String1 String2 String3 // Ausgabe String1
String2
String3
17.4.10.6 format.number Hierüber kann eine Eingabe als Zahl formatiert werden – inkl. Dezimalstellen und Tausender-Trennzeichen. Listing 17.33 ViewHandler format.number // Verwendung 12345.678 // Ausgabe 12.345,7
Tabelle 17.22 Argumente für den ViewHelper format.number Name
Typ
benötigt
Default-Wert
Bemerkung
decimals
int
nein
2
Stellen nach dem Komma
decimalSeparator
string
nein
,
Trennzeichen für die Dezimal-Darstellung
thousandsSeparator
string
nein
.
Trennzeichen für die Tausender-Darstellung
17.4.10.7 format.padding Dieser ViewHandler dient als Wrapper für die PHP-Funktion str_pad(). Es wird der Eingabestring genommen und mit dem als padString spezifizierten Zeichen (es können dort auch mehrere definiert werden) so lange hinten aufgefüllt, bis die unter padLength angegebene Länge erreicht ist. Listing 17.34 ViewHandler format.padding // Verwendung TYPO3 // Ausgabe TYPO3...............
405
17 Die Fluid-Template-Engine Tabelle 17.23 Argumente für den ViewHandler format.padding Name
Typ
benötigt
Default-Wert
Bemerkung
padLength
integer
nein
–
Länge des auszugebenden Strings
padString
string
nein
–
Der String, mit dem aufgefüllt wird
17.4.10.8 format.printf Hierüber wird ein ViewHelper definiert, der die Eingabe mittels printf() formatiert. Als Eingabe können Sie entweder ein Array oder einen einzelnen Wert übergeben. Alle möglichen Formatierungsmöglichkeiten finden Sie hier: http://www.php.net/manual/en/function.sprintf.php
Listing 17.35 ViewHelper format.printf // Verwendung %s und %s sind super! // Ausgabe Fluid und TYPO3 sind super!
Tabelle 17.24 Argumente für den ViewHandler format.printf Name
Typ
benötigt
Default-Wert
Bemerkung
arguments
array
ja
–
Die Argumente für printf
17.4.11 groupedFor Während man mit dem For-ViewHelper durch das Objekt oder Array in der Reihenfolge iteriert, dass man das erste Element zuerst und das letzte Elemente zuletzt bekommt, kann man mit dem groupedFor-ViewHelper nach einem der Schlüssel vorsortieren. Listing 17.36 ViewHelper groupedFor // Verwendung {fruit.name} - {fruit.color}
// Ausgabe apple - green
406
17.4 ViewHelper-Übersicht cherry - red
strawberry - red
banana - yellow
Hier wird also das über der GroupedFor-ViewHelper eingebrachte Array nach der Farbe (groupBy="color") vorsortiert und erst dann an den For-ViewHelper übergeben. Somit erhalten wir eine nach der Farbe sortierte Ausgabe. Tabelle 17.25 Argumente für den ViewHelper groupedFor Name
Typ
benötigt
Default-Wert
Bemerkung
as
string
ja
–
Der Name der IterationsVariablen
each
array
ja
–
Das Array oder das SplObjectStorage, über das iteriert wird
groupBy
string
ja
–
Nach dieser hier angegebenen Eigenschaft wird gruppiert.
groupKey
string
nein
groupKey
Der Name der Variablen, in der die aktuelle Gruppierung gespeichert wird
17.4.12 if Zusammen mit dem Then- und Else-ViewHelper können Sie damit eine komplette IfThen-Else-Abfrage realisieren, wie Sie sie aus den klassischen Programmiersprachen kennen. Dazu wird im IF-ViewHelper eine Bedingung geprüft und der Then-Zweig angesprungen, wenn diese positiv war. Sollte die Bedingung negativ ausgefallen sein, wird direkt im Else-Zweig weitergemacht. Listing 17.37 ViewHelper if, then und else // Verwendung
Es sind Posts vorhanden!!
Keine Posts vorhanden!!
Die Ausgabe des obigen Codebeispiels ist nun abhängig davon, ob der im Argument condition angegebene Blog Posts besitzt. Ist dies der Fall, wird die Zeichenkette Es sind Posts vorhanden!! ausgegeben. Ansonsten erfolgt die Ausgabe der Zeichenkette im ElseZweig.
407
17 Die Fluid-Template-Engine Tabelle 17.26 Argumente für den ViewHelper if Name
Typ
benötigt
Default-Wert
Bemerkung
condition
boolean
ja
–
Dies ist eine ViewHelperCondition wie in Kapitel 17.3 beschrieben.
17.4.13 image Über den ViewHelper image können Sie Bilder in das Template laden und einige Attribute an diese übergeben, wie beispielsweise die minimale oder maximale Breite oder Höhe sowie die Angabe, ob das Bild eine Image-Map beinhalten soll. Listing 17.38 ViewHelper image // Verwendung
Das Bild wird nun an der über src angegebenen Stelle gesucht und mittels der anderen Parameter über die TYPO3-Verarbeitung geschickt. Dabei wird das Bild dann sowohl skaliert (wenn dies notwendig sein sollte) als auch mit einer Image-Map versehen (wenn dies spezifiziert wurde). Anschließend wird das Bild ausgegeben. Tabelle 17.27 Argumente für den ViewHelper image
408
Name
Typ
benötigt
Default-Wert
Bemerkung
accessKey
string
nein
–
Keyboard-Shortcut
alt
string
ja
–
Alt-Angabe
class
string
nein
–
CSS-Klasse(n)
dir
string
nein
ltr
Textrichtung: ltr oder rtl
height
string
nein
–
Höhe des Bildes – entweder als fixer Wert oder als Kalkulation mittels „m“ oder „c“
id
string
nein
–
ID des Bildes
ismap
strin
nein
–
Spezifiziert das Bild als serverseitige Image-Map (kaum benutzt)
lang
string
nein
–
Language-Attribut (RFC 1766)
longdesc
string
nein
–
Legt eine URL fest, unter der man eine ausführliche Beschreibung für das Bild hinterlegen kann
maxHeight
integer
nein
–
Maximale Höhe
maxWidth
integer
nein
–
Maximale Breite
minHeight
integer
nein
–
Minimale Höhe
17.4 ViewHelper-Übersicht Name
Typ
benötigt
Default-Wert
Bemerkung
minWidth
integer
nein
src
string
ja
–
Quelle des Bildes
style
string
nein
–
zusätzliche Stilangaben
tabIndex
string
nein
–
TabIndex-Angabe
title
string
nein
–
Title-Attribut (Tooltipp)
usemap
string
nein
–
Spezifiziert das Bild als clientseitige Image-Map
width
string
nein
–
Breite des Bildes – entweder als fixer Wert oder als Kalkulation mittels „m“ oder „c“
Minimale Breite
17.4.14 layout Komplexe Layouts lassen sich in Fluid über eine Kombination des Layout-ViewHelpers und des Render-ViewHelpers erreichen. Näheres zu dieser Thematik finden Sie in Kapitel 17.7. Listing 17.39 ViewHelper layout // Verwendung
Damit wird ein Template geladen, das sich im Verzeichnis Resources/Private/ Layouts/ befindet und den unter name angegebenen Namen mit der Extension .html
trägt. Wird kein Argument für name angegeben, so wird standardmäßig der Name default verwendet. Tabelle 17.28 Argumente für den ViewHelper layout Name
Typ
benötigt
Default-Wert
Bemerkung
name
string
nein
default
Die zu ladende Layout-Template-Datei
17.4.15 link Über diese ViewHelper-Familie können bequem Links mit zusätzlichen Funktionalitäten angelegt werden. 17.4.15.1 link.action Dieser ViewHelper wird zur Erzeugung von Extbase-Action-Links verwendet.
409
17 Die Fluid-Template-Engine Listing 17.40 ViewHelper link.action // Verwendung Link auf die Show-Action des Start-Controllers // Ausgabe Link auf die Show-Action des Start-Controllers
Tabelle 17.29 Argumente für den ViewHelper link.action
410
Name
Typ
benötigt
Default-Wert
Bemerkung
accessKey
string
nein
–
Keyboard-Shortcut
action
string
ja
–
Die Action, die angesprochen werden soll
additionalAttributes
array
nein
–
Zusätzliche Parameter, die dem HTML zugefügt werden
additionalParams
array
nein
–
Wie additionalAttributes, nur dass die Parameter kein Präfix erhalten, sondern unverändert hinzugefügt werden
arguments
array
nein
–
Argumente, die an die Action übergeben werden
class
string
nein
–
CSS-Klasse(n)
controller
string
nein
Der aktuelle Controller
Name des Controllers, der angesprungen werden soll
dir
string
nein
Ltr
Textrichtung: ltr oder rtl
extensionName
string
nein
–
Name der Extension
id
string
nein
–
ID des Links
lang
string
nein
–
Language-Attribut (RFC 1766)
linkAccessRestrictedPages
boolean
nein
–
Der Link wird se bst dann angezeigt, wenn die Zielseite aus Gründen der Zugangsberechtigung nicht angesprungen werden kann.
noCache
boolean
nein
–
Deaktiviert den Cache der Zielseite
17.4 ViewHelper-Übersicht Name
Typ
benötigt
Default-Wert
Bemerkung
noCacheHash
boolean
nein
–
Verhindert die Erzeugung des cHashParameters im Link, der von der typolinkFunktion erzeugt wird
pageType
integer
nein
–
Der gewünschte typenum der Seite
pageUid
integer
nein
Die aktuelle pageUid
Die UID der Seite, die angesprungen werden soll
pluginName
string
nein
–
Name des Plug-ins
rel
string
nein
–
Spezifiziert die Verbindung zwischen dem aktuellen und dem verlinkten Dokument
section
string
nein
–
Fügt eine Ankerangabe an den Link hinzu (#section)
style
string
nein
–
Zusätzliche Stilangaben
tabIndex
integer
nein
–
TabIndex-Angabe
target
string
nein
–
Sprungziel
title
string
nein
–
Title-Attribut (Tooltipp)
17.4.15.2 link.email Hierüber können Sie E-Mail-Links erzeugen. Insbesondere werden die TYPO3-eigenen Verfahren zur Spam-Vermeidung verwendet, wenn diese entsprechend konfiguriert wurden. Listing 17.41 ViewHelper link.email // Verwendung Email an Patrick Lobacher schreiben // Ausgabe Email an Patrick Lobacher schreiben
Tabelle 17.30 Argumente für den ViewHelper link.email Name
Typ
benötigt
Default-Wert
Bemerkung
additionalParams
array
nein
–
Zusätzliche Parameter, die dem HTML zugefügt werden
email
string
ja
–
Em-Mail-Adresse
411
17 Die Fluid-Template-Engine 17.4.15.3 link.external Dieser ViewHelper wird zur Erzeugung von externen Links verwendet. Listing 17.42 ViewHelper link.external // Verwendung Homepage typofaktum // Ausgabe Homepage typofaktum
Tabelle 17.31 Argumente für den ViewHelper link.external
412
Name
Typ
benötigt
Default-Wert
Bemerkung
accessKey
string
nein
–
Keyboard-Shortcut
additionalAttributes
array
nein
–
Zusätzliche Parameter, die dem HTML zugefügt werden
additionalParams
array
nein
–
Wie additionalAttr butes, nur dass die Parameter kein Präfix erhalten, sondern unverändert hinzugefügt werden
class
string
nein
–
CSS-Klasse(n)
dir
string
nein
ltr
Textrichtung: ltr oder rtl
id
string
nein
–
ID des Links
lang
string
nein
–
Language-Attr but (RFC 1766)
linkAccessRestrictedPages
boolean
nein
–
Der Link wird selbst dann angezeigt, wenn die Zielseite aus Gründen der Zugangsberechtigung nicht angesprungen werden kann.
rel
string
nein
–
Spezifiziert die Verbindung zwischen dem aktuellen und dem verlinkten Dokument
style
string
nein
–
zusätzliche Stilangaben
tabIndex
integer
nein
–
TabIndex-Angabe
target
string
nein
–
Sprungziel
title
string
nein
–
Title-Attribut (Tooltipp)
uri
string
ja
–
Die URL, zu der verlinkt werden soll
17.4 ViewHelper-Übersicht 17.4.15.4 link.page Dieser ViewHelper wird Erzeugung von internen Links verwendet. Listing 17.43 ViewHelper link.page // Verwendung Link auf die Seite mit der UID=1 // Ausgabe Link auf die Seite mit der UID=1
Tabelle 17.32 Argumente für den ViewHelper link.external Name
Typ
benötigt
Default-Wert
Bemerkung
accessKey
string
nein
–
Keyboard-Shortcut
additionalAttributes
array
nein
–
Zusätzliche Parameter, die dem HTML zugefügt werden
class
string
nein
–
CSS-Klasse(n)
dir
string
nein
ltr
Textrichtung: ltr oder rtl
id
string
nein
–
ID des Links
lang
string
nein
–
Language-Attribut (RFC 1766)
noCache
boolean
nein
–
Deaktiviert den Cache der Zielseite
noCacheHash
boolean
nein
–
Verhindert die Erzeugung des cHash-Parameters im Link, der von der typolink-Funktion erzeugt wird.
pageType
integer
nein
–
Der gewünschte typenum der Seite
pageUid
integer
nein
Die aktuelle pageUid
Die UID der Seite, die angesprungen werden soll
rel
string
nein
–
Spezifiziert die Verbindung zwischen dem aktuellen und dem verlinkten Dokument
section
string
nein
–
Fügt eine Ankerangabe an den Link hinzu (#section)
style
string
nein
–
zusätzliche Stilangaben
tabIndex
integer
nein
–
TabIndex-Angabe
target
string
nein
–
Sprungziel
title
string
nein
–
Title-Attr but (Tooltipp)
uri
string
ja
–
Die URL, zu der verlinkt werden soll
413
17 Die Fluid-Template-Engine
17.4.16 render Dieser ViewHelper dient dazu, Partials oder Sections zu rendern. Wird der ViewHelper in einem Layout-Template-File verwendet, so wird der Content im Haupt-Template-File gerendert. Wird der ViewHelper allerdings schon in einem Haupt-Template-File verwendet, so wird der jeweilige Sections-Abschnitt im selben Template gerendert. Nähere Informationen hierzu finden Sie in Kapitel 17.7. Wird allerdings der Parameter partial gesetzt, so wird der Wert mit .html ergänzt und ein damit gleichnamiges Template im Verzeichnis Resources/Private/Partials geladen und gerendert. Listing 17.44 ViewHelper render // Anwendung // Anwendung
Tabelle 17.33 Argumente für den ViewHelper render Name
Typ
benötigt
Default-Wert
Bemerkung
arguments
array
nein
–
Ein Array mit Argumenten, die man an den Renderer weitergeben möchte
partial
string
nein
–
Angabe des Partials, das gerendert werden soll
section
string
nein
–
Angabe der Section, die gerendert werden soll
17.4.17 renderFlashMessages Mit der Methode $this->flashMessages->add() können sogenannte Flash-Messages zugefügt werden. Diese beinhalten meist Statusinformationen, wie „Das Blog wurde zugefügt“, „Der Post wurde erfolgreich gelöscht“ oder „Ihre letzte Transaktion hat 7 Elemente gelöscht“ und Ähnliches. Mit diesem ViewHelper können die vorher zugefügten FlashMessages zugefügt werden. Listing 17.45 ViewHelper renderFlashMessages // Verwendung
Die Ausgabe erfolgt per Default als ungeordnete Liste, wobei jede vorher zugefügte FlashMessage ein Listenelement darstellt. Will man eine andere Darstellung erreichen, so muss man dafür einen eigenen ViewHelper schreiben.
414
17.4 ViewHelper-Übersicht Tabelle 17.34 Argumente für den ViewHelper renderFlashMessages Name
Typ
benötigt
Default-Wert
Bemerkung
class
string
nein
–
Fügt dem Listenelement eine CSS-Klasse hinzu
17.4.18 section Über diesen ViewHelper können Sie in einem Template einen Bereich definieren, der durch ein Layout gerendert wird. Weitere Informationen hierzu finden Sie in Kapitel 17.7. Listing 17.46 ViewHelper section // Verwendung … … Inhalt …
Durch den Render-ViewHelper wird die mit diesem ViewHelper definierte Sektion dann gerendert. Tabelle 17.35 Argumente für den ViewHelper render Name
Typ
benötigt
Default-Wert
Bemerkung
name
string
ja
–
Name der Sektion
17.4.19 then Der Then-ViewHelper macht nur in Zusammenhang mit dem If-ViewHelper Sinn und wird dementsprechend dort behandelt.
17.4.20 translate Über diesen ViewHelper können mehrsprachige Labels verwendet werden. Dafür wird die aktuelle Sprache aus der aktuellen TypoScript-Konfiguration ermittelt und dann die zugehörige locallang.xml Datei (oder locallang.php) im Verzeichnis Resources/Private/Language/ ermittelt. Dort wird über den Parameter key der entsprechende Schlüssel ausgelesen und dessen Wert zurückgegeben. Listing 17.47 Der ViewHelper translate // Aufbau locallang.xml <meta type="array">
415
17 Die Fluid-Template-Engine module <description>Sprachlabels für die Efempty Extension This is the english output Das ist die deutsche Ausgabe // Verwendung // Ausgabe (bei Konfiguration der deutschen Sprache) Das ist die deutsche Ausgabe
Tabelle 17.36 Argumente für den ViewHandler translate Name
Typ
benötigt
Default-Wert
Bemerkung
htmlEscape
boolean
nein
–
Ist der Wert TRUE, so wird die Ausgabe HTML escaped.
key
string
ja
–
Der Schlüssel, über den der Wert in der locallang-Datei ermittelt wird
17.4.21 uri Die ViewHelper-Familie uri ist identisch zu der Link-Familie – mit der Ausnahme, dass lediglich der Link selbst zurückgegeben wird (sprich ohne -Tag) – so gibt es also uri.action, uri.email, uri.external und uri.page.
17.5
Erstellen eines eigenen ViewHelpers Nachdem wir nun die mitgelieferten ViewHelper genauer inspiziert haben, wollen wir uns jetzt an die Arbeit machen, selbst einen ViewHelper zu schreiben. Genau dies macht Fluid so mächtig – wir können den Kern von Fluid nämlich auf diese Weise einfach und bequem selbst erweitern. Grundsätzlich müssen für einen eigenen ViewHelper folgende Schritte ausgeführt werden:
Anlegen eines Verzeichnisses Classes/ViewHelpers in Ihrer Extension Ausdenken eines Namens für den ViewHelper Anlegen eine Klassendatei NameViewHelper.php im oben angelegten Verzeichnis
416
17.5 Erstellen eines eigenen ViewHelpers
In der Klassendatei platzieren Sie eine Klasse mit dem Namen: Tx_ExtensionName_ ViewHelpers_NameViewHelper,
die AbstractViewHelper abgeleitet wird.
von
der
Klasse
Tx_Fluid_Core_
Hinzufügen einer Funktion render() Das war es im Grunde genommen schon – so einfach ist es prinzipiell, einen ViewHelper zuzufügen. Wir wollen dies im Folgenden an ein paar unterschiedlichen Beispielen zeigen.
17.5.1
Der Dummytext-ViewHelper
In einem Projekt kommt es oft genug vor, dass zwar das Design schon halbwegs abgesegnet ist und bereits implementiert werden kann – dann allerdings fehlen zumeist die Texte, um beispielsweise die Boxen in den Randspalten zu füllen. Um nun nicht warten zu müssen, bis der Kunde die Inhalte liefert, könnte man doch schon mal Dummy-Texte dort platzieren. Und genau dies soll der Dummytext-ViewHelper erledigen. Zunächst benötigen wir also eine Datei DummytextViewHelper.php im Verzeichnis Classes/ViewHelpers/, das wir im Verzeichnis der vorhin schon benutzten Extension efempty aus dem TER anlegen. Listing 17.48 Die Datei DummytextViewHelper.php
In diesem ViewHelper wird nun Folgendes durchgeführt:
Offensichtlich gibt es einen Parameter length, der – wenn er denn nicht übermittelt wurde – per Default die Länge 100 enthält.
Nun wird der angegebene Dummytext-String so oft wiederholt, bis die angegebene Anzahl an Zeichen erreicht wurde. Anschließend wird der String wieder zurückgegeben.
417
17 Die Fluid-Template-Engine
Nun ist es aber noch etwas ungeschickt, dass wir den Dummytext fest in den Code geschrieben haben. Wenn wir beispielsweise nun einen anderen Text haben wollten, so funktioniert dies nur für alle Texte gleichermaßen, indem wir den Code ändern.
Wir könnten aber den Dummy-Text jeweils beim Verwenden des ViewHelpers notieren, dann würde dieser Text nur für diesen speziellen ViewHelper gelten und damit individuell anpassbar sein.
Wir verändern also den Aufruf unseres ViewHelpers im Template: Listing 17.49 Anpassen des ViewHelpers um einen individuellen Dummy-Text im Template {namespace efempty = Tx_Efempty_ViewHelpers} <efempty:dummytext length="60">Das ist ein Dummytext!
Wir haben nun also den Dummy-Text zwischen die Tags geschrieben. Um nun auf diesen zuzugreifen, müssen wir diesen entsprechend ansprechen. Die dafür notwendige Funktion lautet $this->renderChildren(). Damit wird der komplette Inhalt des ViewHelpers zunächst einmal gerendert. Die Ausgabe dann wird dem umgreifenden ViewHelper zur Verfügung gestellt. Dafür müssen wir die render()-Funktion unseres ViewHelpers anpassen. Listing 17.50 Anpassung an die render()-Funktion … public function render($length = 100) { //$dummytext = 'Lorem ipsum dolor sit amet. '; $dummytext = $this->renderChildren(); $len = strlen($dummytext); …
Nun könnten wir aber auch anstelle eines Textes einen anderen ViewHelper als Quelle für unseren Dummy-Text verwenden – beispielsweise einen Translate-ViewHelper. Schon bekommen wir Dummy-Texte, die von der eingestellten Sprache abhängig sind: Listing 17.51 Verwenden des Translate-ViewHelpers als Quelle für den Dummy-Text // Verwendung {namespace efempty = Tx_Efempty_ViewHelpers} <efempty:dummytext length="60">Dummytext: // Ausgabe Dummytext: Das ist die deutsche AusgabeDummytext: Das ist di
17.5.2
Zugriff auf die übergebenen Argumente
Innerhalb des ViewHelpers haben Sie (wenn auch nur lesenden) Zugriff auf die übergebenden Argumente mittels $this->arguments:
418
17.5 Erstellen eines eigenen ViewHelpers Listing 17.52 Zugriff auf die an einen ViewHelper übergebenden Argumente // Verwendung debug($this->arguments) // Ausgabe Tx_Fluid_Core_ViewHelper_Arguments Object ( [arguments:protected] => Array ( [length] => 60 ) )
17.5.3
Zufügen von Argumenten
Das Zufügen von Argumenten kann prinzipiell auf zwei Wegen geschehen:
Wie in Kapitel 17.5.1 gezeigt, kann man die Argumente einfach als MethodenArgumente an die Methode render() übergeben und über die Annotation validieren lassen (also den Typ überprüfen).
Ein
weiterer Weg ist, explizit die folgende Funktion aufzurufen: $this->registerArgument($name, $dataType, $description, $isRequired, $defaultValue=NULL)
$name
Der Name des Arguments
$dataType
Der Datentyp des Arguments
$description
Eine kurze Beschreibung
$isRequired
Angabe, ob dieses Argument unbedingt notwendig ist (Wert = 1) oder auch weggelassen werden kann (Wert = 0)
$defaultValue
Die Angabe eines Default-Wertes
17.5.4
Tag-basierende ViewHelper
Viele ViewHelper geben in irgendeiner Weise am Ende ein HTML-Tag aus. Dieses ist meist mit zahlreichen Attributen versehen. Diese können natürlich auch selbst „händisch“ per String-Konkatenation (a là if ($this->arguments['class']) { $output .= ' '; }) hinzugefügt werden, allerdings hilft uns Fluid mit speziell hierfür vorgesehenen Methoden und Eigenschaften:
protected $tagName = 'a'
Mit dieser Eigenschaft wird der Name des späteren Tags festgelegt – in diesem Beispiel also wird ein -Tag zusammengestellt.
419
17 Die Fluid-Template-Engine
$this->registerUniversalTagAttributes()
Dies registriert die folgenden Attribute zur Verwendung mit diesem Tag: class, dir, id, lang, style, title, accesskey, tabindex
$this->registerTagAttribute($name, $type, $description, $required)
Mit dieser Methode kann ein eigenes Attribut registriert werden, das dann – sofern es verwendet wird – automatisch mit gerendert wird.
$name
Der Name des Attributs
$type
Der Datentyp des Attributs
$description
Eine kurze Beschreibung
$required
Die Angabe, ob dieses Attribut angegeben werden muss
$this->tag->addAttribute($name, $type, $description, $required)
Mit dieser Methode können Sie Attribute angeben, die dem Tag direkt zugefügt werden sollen
$this->tag->setContent($taginhalt)
Hiermit wird der Inhalt innerhalb der Tags gesetzt. Dieser kann beispielsweise über $this->renderChildren() ermittelt werden.
$this->tag->render()
Rendert das Tag schließlich 17.5.5
Der Variablen-Container
Wenn man einen ViewHelper hat, der sämtliche benötigte Daten aus der Eingabe nehmen kann, dann sind Sie hier bereits fertig mit Ihrem ViewHelper. Haben Sie jedoch beispielsweise eine Schleife, die in jedem Schleifendurchlauf einen eigenen Wert verarbeitet, dann müssen Sie leicht anders vorgehen. Diese Problematik wird mit einem Variablen-Container gelöst. Dieser nimmt eine Variable auf, daraufhin wird der Inhalt mit eben diesem Wert gerendert, anschließend wird die Variable wieder entfernt, und der nächste Schleifendurchlauf beginnt. Nachfolgend der Code eines Loop-ViewHelpers, der letztlich nichts anderes macht, als eine foreach()-Schleife nachzuahmen. Dieser ViewHelper iteriert einfach durch ein vorgegebenes Array. Listing 17.53 Ein eigener foreach-ViewHelper mit dem Name loop
Listing 17.54 Die Verwendung des Loop-ViewHelpers im Template // Verwendung {namespace efempty = Tx_Efempty_ViewHelpers} <efempty:loop each="{0:'test', 1:2, 2:3, 3:4, 4:5}" as="value"> Der Wert heisst: {value} // Ausgabe Der Wert heisst: Der Wert heisst: Der Wert heisst: Der Wert heisst: Der Wert heisst:
test 2 3 4 5
Die Vorgehensweise ist dabei wie folgt:
Über
$this->templateVariableContainer->add($varname, $value) wird ein
Wert registriert
Mittels $out
.= $this->renderChildren(); wird das Template mit der eben zugefügten Variablen gerendert (und der gerenderte Inhalt an die Ausgabevariable – hier $out – zugefügt).
Am
Variable mittels >templateVariableContainer->remove($varname); wieder entfernt.
17.6
Ende
(des
Durchlaufs)
wird
dann
die
$this-
Verwendung von Fluid in klassischen Extensions So bequem die Verwendung von Fluid in Extensions ist, die auf Extbase basieren, so praktisch wäre es doch manchmal auch, Fluid genauso in klassischen Extensions verwenden zu können. Einerseits will man vielleicht noch nicht die komplette Extension umwandeln, oder es ist andererseits schlicht noch nicht möglich, die Extension komplett mit Extbase zu realisieren – vielleicht weil diese mit anderen Extensions interagiert oder weil Features fehlen, die zur Realisierung unbedingt benötigt werden.
421
17 Die Fluid-Template-Engine Daher können Sie Fluid natürlich auch in klassischen Extensions ohne großen Aufwand einsetzen. Zum Test haben wir mit dem Kickstarter eine Demo-Extension mit dem Namen fluidohneextbase (Fluid ohne Extbase) erstellt, die lediglich ein Plug-in enthält – sonst nichts. In die Plug-in-Klassendatei class.tx_fluidohneextbase_pi1.php im Verzeichnis typo3conf/ext/fluidohneextbase/pi1/ schreiben wir nun in die Funktion main() folgenden PHP-Code (der neue Code ist hervorgehoben): Listing 17.55 PHP-Code zum Ansprechen der Fluid-Funktionalität
Wichtig ist lediglich, dass sowohl die Extension fluid wie auch die Extension Extbase installiert ist – Letztere wird lediglich dafür gebraucht, um den Rendering-Context festzulegen. Die selbst geschriebene Extension greift aber ansonsten nicht auf Extbase zu – lediglich Fluid.
422
17.7 Layouts und Partials Somit sind Sie in der Lage, Ihre eigenen, klassischen Extensions ebenfalls mit der mächtigen und flexiblen Template-Engine Fluid anzureichern.
17.7
Layouts und Partials Gerade wenn man eine umfangreiche Webapplikation entwirft, stellt man fest, dass man im Grunde genommen drei wiederkehrende Bestandteile in der Ausgabe hat.
Das Layout, welches das CI enthält (also Logos, Menüleiste, Suche …) Ein Template, das die gerade benötigte Action (beispielsweise eine Liste, ein Formular oder eine Einzelansicht) darstellt
Immer wiederkehrende Teile (Partials), die beispielsweise Fehlermeldungen anzeigen können. Sobald ein bestimmter Abschnitt im Template öfter als einmal unverändert auftaucht, kann es schon Sinn machen, diesen in ein Partial auszulagern
Abbildung 17.3 Grafische Darstellung von Layout, Template und Partial
Um nun diese Struktur zu realisieren, müssen Sie zunächst unterhalb von Resources/Private/ folgende Verzeichnisse anlegen: Layouts Partials
423
17 Die Fluid-Template-Engine
Abbildung 17.4 Verzeichnisstruktur im Private-Ordner zur Realisierung von Layouts und Partials
Nun starten wir mit dem Haupt-Template index.html: Listing 17.56 Das Template index.html It works :-) Weiterer Text…
Beim Aufbau der Layout-Template-Struktur muss man nun etwas um die Ecke denken: 1. Zuerst wird über die Action das Template-File im zum Model passenden Unterverzeichnis von Templates definiert. 2. Dieses Template-File kann nun einen Layout-ViewHelper beinhalten (oben in der ersten Zeile), der wiederum bestimmt das Layout-Template-File. An diesen unter dem Attribut name angegebenen Namen wird nun .html zugefügt und das File aus dem Verzeichnis Resources/Private/Layouts geladen. 3. Im Layout-Template-File nun können Sie das Layout definieren. An der Stelle, an der Sie das Template platzieren wollen, verwenden Sie den ViewHelper . Als Attribut section nehmen Sie genau denjenigen Namen, den Sie im Haupt-Template über den Section-ViewHelper verwendet haben. Damit wird dann der Abschnitt (Section) des Templates gerendert. 4. Partials können Sie nun beliebig platzieren, indem Sie den Render-ViewHelper verwenden.
424
17.7 Layouts und Partials Listing 17.57 Das Layout-File defaultLayout.html Welcome to the efempty extension!
© typofaktum - Patrick Lobacher
Über diesen Mechanismus ist es möglich, auch komplexe Layouts zu realisieren. Allerdings ist es momentan noch nicht möglich, Fluid als Output-Template-Engine für TYPO3 selbst zu verwenden. Hier muss (vorläufig) weiterhin mit Marker/Subparts bzw. TemplaVoilà gearbeitet werden. Lediglich die Ausgabe der Extension selbst ist mittels Fluid steuerbar.
425
Register $
_GET 165 _GETset 165 _GP 166 _POST 166
addModulePath() 66 addSlashesOnArray 186 addTCAcollumns() 54 Aggregate 285 AJAX 114, 205, 257 AJAX-Dispatcher 258 AJAX-Request 207 all 232 anchorPrefix 233 applicationData 233 Applikationsschicht 281 Arbeitsfläche 201 array_merge 187 array_merge_recursive_overrule 187 array2json 188 array2xml 188 arrayToLogString 189 ATagParams 233 Attribute 268 Ausgabe 103
A
B
Abmessungen 201 absRefPrefix 232 abstract 274 abstrakte Klasse 273 Action anlegen 335 additionalCSS 228 additionalHeaderData 224, 228, 232 additionalJavaScript 224 addModule() 66
Backend User Object 91 Backend-Flexform 300 Backend-Formulare 34, 82 Backend-Modul 40 Backend-Modul (Extbase) 365 baseUrl 234 baseUrlWrap 215, 234 Basisdatei 206 Bearbeitungssymbole 84
$BE_USER 91 $EM_CONF[$_EXTKEY] 46 $extpath 67 $GLOBALS 82 $GLOBALS['TSFE']->fe_user->user 245 $GLOBALS['TYPO3_DB'] 141 $MCONF 50 $TCA 53 $temp_TBE_MODULES 67 $this->content 79
[ [Passthrough] 36
_
427
Register BEER3 380 Berechtigungsprüfung 75 Berlin Manifesto 266 Berliner Transition Days 379 beUserLogin 234 bigDoc 76 Bilder 101, 104, 199 Bildupload 60 Blog 26 Blog-Example 287
C cacheExpires 209 calcAge 195 calcParenthesis 171 callUserFunction 166 CGL 9 Changelog 22 Checkbox single 35 Checkbox, 4 Boxes in a Row und 10 Boxes in two Rows 35 Checkboxen 57 checkEmail 195 cImage 211 class.tx_extkey_pi#.php 52 cleanFormName 211 cleanIntArray 147 cleanIntList 147 clearPageCacheContent 209 clearPageCacheContent_pidList 209 cli 259 Clickmenu items 41 clientInfo 167, 234 cliKey 259 cmpFQDN 171 cmpIP 172 cObj 151 cObjGet 211 cObjGetSingle 212 Codeformatierung 11 codeString 195 compat_version 167 compileSelectedGetVarsFromArray 168
428
Conditions 17, 91 conf.php 50 content 235 Content-Element 39 Controller 281 Convention over Configuration 294 convUmlauts 172 Copyright 12 css_styled_content 96 CSS-Datei 86 csvValues 172 ctrl-Bereich 54 currentPageUrl 212
D Database Relation 36 Date und Date Time 35 Dateistruktur 12 Dateisystem 155 Daten persistieren 324 Datenbank 28 Datenbank-Abstraktions-Layer 141 Datenbankfelder 29 Datenbank-Handler 141 Datenbankstruktur 25 Datenbanktabellen 34 DBAL 141 DBgetDelete 151 DBgetInsert 151 DBgetUpdate 152 debug 260 Debug 17 debug_lastBuiltQuery 147 debug_ordvalue 261 debug_trail 261 Debugging 260 debugRows 261 defaultBodyTag 235 defVals 82 deHSCentities 173 Destruktor 271 devLog 262 Dienste 42
Register dirname 155 Dispatcher 306 Dokumentation 133 Dokumententypen 257 Domain Driven Design 280, 291 Aggregate 285 Entity 285 Factory 286 Repository 286 Service 285 Ubiquitous Language 282 Value Object 285 domainStartPage 235 Domänenschicht 281
E efempty Extension 380 eID 114, 205 enableFields 153 encryptEmail 196 Entitäten einführen 322 Entity 285 escapeStrForLike 146 exec_DELETEquery 143 exec_INSERTquery 143 exec_SELECT_mm_query 142 exec_SELECT_queryArray 141 exec_SELECTgetRows 142 exec_SELECTquery 141 exec_UPDATEquery 143 expandList 173 explodeUrl2Array 190 ext_conf_template.txt 80, 244 ext_emconf.php 27, 45, 296 ext_icon.gif 302 ext_localconf.php 53, 205, 301 ext_tables.php 53, 66, 297 ext_tables.sql 54 ext_tables_static+adt.sql 55 Extbase 266 Extbase-Kickstarter 366 extdeveval 14, 133 Extend existing Tables 36
extends 271 Extension-ID 205 Extension-Key 8, 315 Extension-Manager 244 ExtJS 119 extTarget 236
F Factory 286 Features 24 Fehlerausgabe 347 Feldtyp 81 fePreview 236 Field name 29 fileResource 213 Files 36 finale Klasse 273 fixed_lgd 173 fixed_lgd_pre 174 fixWindowsFilePath 155 FlashMessages 377 Flex 36 Flexform 125, 242, 249 FLOW3 265 Fluid 266, 379 Argumente 385 Arrays 382 Basissyntax 382 Layout 423 Namespace 384 Objekte 383 Partial 423 Verwendung in klassischen Extensions 421 ViewHelper-Syntax 384 formatForTextarea 174 Formatierung 11 formatSize 156 Formulardaten 243 Formulardaten eingeben 337 Formulare 34, 251 Formularfelder 253 Frontend-Bibliotheken 4 Frontend-Plug-ins 37
429
Register Frontend-Rendering-Prozess 4, 205 Frontend-User 245 fullQuoteArray 146 fullQuoteStr 145
G General Info 27 generateRandomBytes 174 get_cache_timeout 210 get_dirs 156 get_tag_attributes 175 getAllFilesAndFoldersInPath 157 getBrowsableTree() 72 getFileAbsFileName 158 getFilesInDir 158 getHostname 168 getImgResource 213 getIndpEnv 168 getLLL 230 getMailTo 215 getSlidePids 213 getThisUrl 168 getTypoLink 216 getTypoLink_URL 216 getURL 159 GIFBUILDER 104 gifBuilderTextBox 214 Globale Extensions 7 GPL 12 GraphicsMagick 200 Graustufen 202
H Hauptmodul 65 header type 39 Hook 123 HTMLcaseshift 196 htmlspecialchars_decode 175 HTML-Template 109 HTML-Templates 103 http_makelinks 217
430
I Icon 83 id 236 imageLinkWrap 217 ImageMagick 200 imagesOnPage 237 Implementierung 269 implodeArrayForUrl 175 implodeAttributes 176 inArray 190 Infrastrukturschicht 281 Ingmar Schlecht 366 initialisieren 75 inList 176 Input-Felder 58 Installation von Extbase 287 Installation von Fluid 287 instanceof-Operator 272 Instanziieren 268 int_from_ver 177 Integer, 10 -1 000 35 Integrate in existing Modules 41 Interface 275 intInRange 177 intTarget 237 intval_positive 178 isAbsPath 159 isAllowedAbsPath 159 isFirstPartOfStr 178
J JavaScript 115, 206 Jochen Rau 266 JSeventFuncCalls 225 JSON 122
K Kapselung 274 Kategorie 80 keywords 196 Kickstarter 26 Klassen 267 Klassenzugehörigkeit 272
Register Kommentare 16 Konstanten 43 Konstruktor 269 Konzept 23
L lang 237 lastImageInfo 238 linebreaks 197 Link 35 linkThisScript 169 linkThisUrl 169 Liste 85 Listenansicht 102 Listenausgabe 99 listQuery 144 listView 98 locallang.xml 51, 56 locallang_db xml 56, 250 locallang_mod xml 51 locationHeaderUrl 169 loginUser 238 Lokale Extensions 7
modifyHTMLColor 179 modifyHTMLColorAll 179 Modul 40 Modulinhalt 79 MVC (Model-View-Controller) 281 MVC-Request Objekt 376
N Namenskonventionen 293 Namespace 10, 278 Navigationsbaum 65, 69 new-Operator 269 no_cache 238 noDoc 76 normalizeIPv6 180 Not editable, only displayed 36
O Objekte 267 objektorientierte Programmierung 267 OpenOffice 135 Optionale Argumente 347
P M mailto_makelinks 218 mailto-Link 106 makeInstance 170 makeInstanceService 170 Marker 109 md5int 178 mediumDoc 76 Mehrsprachigkeit 250, 361 Methoden 268 Methodendeklaration 268 Methodenrumpf 269 milliseconds 179 minifyJavaScript 225 mkdir 160 mkdir_deep 160 M-M-Relationen 62 Model 281 Modellierung 282
page 239 Page-Browser 87 phpDoc 12, 21 PHP-Shell 259 PHP-Syntax 15 PHP-Tags 11 PHPTAL 379 pi_exec_query 148 pi_getClassName 229 pi_getFFvalue 256 pi_getLL 230 pi_getPageLink 218 pi_getPidList 149 pi_getRecord 150 pi_linkToPage 218 pi_linkTP 219 pi_linkTP_keepPIvars 219 pi_linkTP_keepPIvars_url 219 pi_list_browseresults 221
431
Register pi_list_header() 101 pi_list_linkSingle 222 pi_list_makelist 222 pi_list_modeSelector 223 pi_list_searchBox 223 pi_openAtagHrefInJSwindow 220 pi_prependFieldsWithTable 150 pi_setClassStyle 229 Planung 23 Plug-in 37 Präsentationsschicht 281 prefixLocalAnchorsWithScript 220 print_array 190 printError 239 private 274 processParams 197 protected 274 public 274
Q Query-Manager 341 quoteJSvalue 226 quoteStr 145
R Radiobuttons 36 rawUrlEncodeJS 226 readLLfile 231 Registrierung 8 Relation 348 Relation m n 356 removeArrayEntryByValue 191 removePrefixPathFromList 160 removeXSS 180 Repository 23, 286 anlegen 333 Objekte entfernen 338 Update von Objekten 339 resolveBackPath 161 revExplode 180 rm_endcomma 181 rmdir 161
432
rmFromList 170 rootLine 240 RTE 105
S Scope Resolution Operator 272 searchQuery 144 Sebastian Kurfürst 379 Seitenbaum 72 Selectorbox 35 self 278 Services 42, 259, 285 Servicetyp 43 Session-Key 246 set_cache_timeout_default 210 set_no_cache 210 setCSS 229 setJS 227 Setup 43 shortMD5 181 showRecordFieldList 56 Signatur 268 singleView 98 siteScript 240 slashArray 191 smallDoc 76 Smarty 379 split_fileref 162 split_tag_attributes 181 splitCalc 182 splitGroupOrderLimit 145 Sprachdatei 102, 250 sql_fetch_assoc 143 sql_fetch_row 144 SQL-Abfrage 78, 131 static 278 Static TypoScript code 43 Statische Eigenschaften 277 Statische Methoden 277 stdWrap 214 StdWrap 110 StoragePid 374 String input 34
Register String input, advanced 34 strtolower 183 strtoupper 183 Sub- or Mainmodule 40 Subpart 109 substUrlsInPlainText 183 Subversion 13 SVN 13 sysLog 171 Systemextensions 7 SystemLog 92
T t3lib_div 155 t3lib_extMgm 66 t3lib_scbase.php 75 t3lib_treeview 71 Tabellen 29 Table Configuration Array 53 Tabs 251 tca.php 56 template 76 Templating-Klasse 76 tempnam 162 TER 137 testInt 184 Text 204 Text area 34 Text area with RTE 34 Text area, no wrapping 35 Textfelder mit RTE 61 this 270 tmpl->config, tmpl->setup 241 trimExplode 184 TrueType 204 TSconfig 43 tslib_eidtools 121 tslib_pibase 96, 148 type 241 Type Hint 277 TYPO3 5 x 265 TYPO3 Coding Guidelines 9 TYPO3_CONF_VARS 241
TYPO3-Kern 3 TypoScript 43, 244, 257 TypoScript Konfiguration 363
U Ubiquitous Language 282 UML 282 uniqueHash 198 uniqueList 185 uniqueString 242 unlink_tempfile 162 Upload 137 upload_copy_move 162 upload_to_tempfile 163 uploads/extkey 60 UpperCamelCase 268, 294 URLqMark 198 User-TS 91
V Validator 343 eigene Validatoren 344 vordefinierte Validatoren 343 validEmail 185 Validierung 343 Validierung mit eval 58 validIP 185 validIPv4 186 validIPv6 186 Value Object 285 Vererbung 271 verifyFilenameAgainstDenyPattern 163 Versionsnummer 44, 137 Verzeichnis Classes 303 Verzeichnis Configuration 304 Verzeichnis Module 305 Verzeichnis Resources 305 Verzeichnisstruktur 302 View 281 View hinzufügen 320 View result 44 view_array 192 ViewHelper
433
Register alias 387 base 388 cObject 388 count 389 cycle 389 debug 390 else 390 Erstellung eines eigenen 416 for 390 form 391 form.checkbox 393 form.error 394 form.hidden 394 form.password 395 form.radio 396 form.select 397 form.submit 399 form.textarea 400 form.textbox 401 form.upload 401 format 402 format.crop 402 format.currency 403 format.date 404 format html 404 format nl2br 405 format number 405 format.padding 405 format.printf 406 groupedFor 406 if 407 image 408
434
layout 409 link 409 link.action 409 link.email 411 link.external 412 link.page 413 render 414 renderFlashMessages 414 section 415 then 415 translate 415 uri 416
W Weblog 26 wrapJS 227 writeFile 164 writeFileToTypo3tempDir 164
X XCLASS 15 xml2array 192 xml2tree 193 xmlGetHeaderAttribs 194 XML-Response 206 XML-Struktur 126
Z Zeichensatz 11 Zeilenumbruch 11 Zuschneiden 201
Neues aus der TYPO3-Küche.
Ebner/Lobacher TYPO3 und TypoScript – Kochbuch Lösungen für die TYPO3-Programmierung mit TypoScript und PHP 2., überarbeitete Auflage 864 Seiten ISBN 978-3-446-41733-5
TYPO3 lässt von Haus aus kaum Wunsche offen. Wer aber die Möglich keiten dieses mächtigen CMS voll ausschöpfen will, muss mit dem TYPO3-System bestens vertraut sein. Hier hilft dieses Buch mit seinen zahlreichen Rezepten. Im bewährten Stile der Hanser-Kochbucher liefern die Autoren Lösungen und Lösungsvorschläge zu typischen Problemen der TYPO3- bzw. TypoScript-Programmierung. Die uber 300 Rezepte sind dabei thematisch sortiert, ihre Bandbreite reicht von der Bedienung uber die Konfiguration bis hin zu der Entwicklung eigener Erweiterungen, der Systemsicherheit und dem System-Tuning. Das Buch empfiehlt sich allen erfahrenen TYPO3-Anwendern und -Entwicklern, die nach Lösungen suchen, um das TYPO3-Basis-CMS per TypoScript und mit Hilfe von PHP an individuelle Bedurfnisse anzupassen.
Mehr Informationen zu diesem Buch und zu unserem Programm unter www.hanser.de/computer
Machen Sie mehr aus TYPO3!
Koch TYPO3 und TypoScript 400 Seiten. ISBN 3-446-40751-0
TYPO3 ist eines der populärsten Content Management Systeme. Durch seine rasche Verbreitung ist weiterführende Literatur gefragt, die zeigt, wie sich TYPO3 anpassen und erweitern lässt. Genau in diese Kategorie fällt dieses Buch. Daniel Koch zeigt Ihnen darin, wie Sie die Programmierung von Webseiten, die Erstellung von Templates und die Entwicklung von Extensions unter TYPO3 mit Hilfe von TypoScript optimieren können. Nach einer Einführung in Sprachsyntax und Funktionsweise von TypoScript stellt er weiterführende Themen vor, so u.a. Grafikbearbeitung, Menüs, Frames und Formulare sowie TypoScript und SQL.
Mehr Informationen zu diesem Buch und zu unserem Programm unter www.hanser.de/computer
Alby macht mobil.
Alby Das mobile Web 240 Seiten. ISBN 978-3-446-41507-2
Mit »Das mobile Web« knüpft Tom Alby konzeptionell an seinen Bestseller über das Web 2.0 an. Er beschreibt, wie sich typische Anwendungen der Web 2.0-Generation wie Flickr, Youtube, Newsgator, LastFM oder GMail ihren Weg auf mobile Geräte wie Handy, Smartphone, PDA oder iPod/iPhone bahnen. Neben einem ausführlichen, auch für Laien verständlichen Überblick über die Technik bestimmen vor allem die nichttechnischen Aspekte das Buch. Alby zeigt auf, welche Anwendungen im mobilen Web denkbar sind, welche bereits existieren und welchen Herausforderungen sich sowohl Hersteller als auch Anwender solcher mobilen Applikationen stellen müssen. Das Buch wendet sich an Web-User und Web-Professionals gleichermaßen, die erfahren möchten, wie sie das mobile Web optimal für sich nutzen können.
Mehr Informationen zu diesem Buch und zu unserem Programm unter www.hanser.de/computer
Was Sie über AJAX wissen müssen!
Darie/Brinzarea/ Chereches¸-Tos¸a/Bucica Ajax und PHP 288 Seiten. ISBN 3-446-40920-3
“AJAX und PHP” liefert Webprogrammierern alles, was sie brauchen, um mit AJAX in Verbindung mit PHP – der meistverbreiteten Skriptsprache weltweit - interaktive Webanwendungen zu erstellen. In der Einführung erfährt der Leser kurz und knapp die wichtigsten Grundlagen zu AJAX. Im Hauptteil dreht sich dann alles um den gelungenen Einsatz von AJAX. In sieben Kapiteln werden Anwendungsbei– spiele vorgestellt, wie sie in der Praxis geläufig sind – Form Validation, Chat, Suggest & Autocomplete, Real-time Charting, Grid Computing, RSS Reader sowie Drag & Drop. Dabei steht die schrittweise, ausführlich erläuterte programmiertechnische Umsetzung im Mittelpunkt.
Mehr Informationen zu diesem Buch und zu unserem Programm unter www.hanser.de/computer
eins, zwei, DREI.
Tom Alby Web 2.0 – Konzepte, Anwendungen, Technologien 3., überarbeitete Auflage 280 Seiten. 75 Abb. ISBN 978-3-446-41449-5
• Liefert einen Überblick über die Konzepte, die hinter dem Web 2.0 stecken • Stellt die wichtigsten Anwendungen des Web 2.0 dar • Analysiert Stärken und Schwächen der Ansätze und Geschäftsmodelle • Vermittelt das richtige Verständnis für die Bedeutung des Web 2.0 Das Buch von Tom Alby ist daher auch kein weiteres Buch zu Web 2.0Techniken. Vielmehr behandelt es die Konzepte, ohne die man die Vorteile des Web 2.0, die sich vor allem Unternehmen bieten, verschenkt. Tom Alby untersucht die unterschiedlichen Ansätze und Geschäftsmodelle von Web 2.0-Anwendungen – Wikis, Blogs und Podcasts, Social Software, Folksonomy und User Generated Software – und zeigt Gemeinsamkeiten wie auch Unterschiede auf.
Mehr Informationen zu diesem Buch und zu unserem Programm unter www.hanser.de/computer
Mehr Transparenz = mehr Erfolg
Aden Google Analytics Implementieren. Interpretieren. Profitieren. 357 Seiten ISBN 978-3-446-41905-6
Sicher haben Sie von Google Analytics schon gehört oder nutzen es bereits. Aber kennen Sie auch alle Feinheiten, Tipps und Tricks? Haben Sie das Tool wirklich perfekt implementiert und Ihren individuellen Bedürfnissen angepasst? Nutzen Sie es vollständig aus und leiten konkrete Aktionen aus den vorhandenen Zahlen ab? Timo Aden, ehemaliger Google-Mitarbeiter und Web-Analyse-Experte, stellt Ihnen in diesem Praxisbuch die vielfältigen Funktionen, die dieses Tool bietet, umfassend vor. Von nützlichen Hinweisen und technischen Kniffen bei der Implementierung und dem Tracking sämtlicher Online-Marketing-Aktivitäten, über die effektive Anwendung der Benutzeroberfläche und Berichte bis hin zur Ableitung von konkreten Aktionen - dieser Praxisleitfaden deckt sämtliche Bereiche von Google Analytics ab.
Mehr Informationen zu diesem Buch und zu unserem Programm unter www.hanser.de/computer
Der ultimative Leitfaden für die Praxis.
Alby/Karzauninkat Suchmaschinenoptimierung 296 Seiten. 2. Auflage ISBN 978-3-446-41027-5
• Webseiten für Google & Co. effizient optimieren • Die Autoren sind seit Jahren im internationalen Suchmaschinenbusiness tätig • Optimierung als Teil der Unternehmenskommunikation, nicht als isolierte technische Aufgabe • Solide, dauerhafte Optimierungskonzepte statt dubioser, kurzfristiger Tricks – Beispiele aus realen Projekten und Seminaren Dieses Buch liefert alle nötigen Informationen, damit die eigene Site in Suchmaschinen besser gefunden wird. Dazu gehört u.a. das Wissen, wie die Suchalgorithmen der Suchmaschinen bei der Entwicklung der Website optimal ausgenutzt werden, welche Form des Suchmaschinen-Marketings am besten geeignet ist, welche technischen Hürden es zu meistern gilt und mit welcher Webprogrammierung die besten Erfolge zu erzielen sind. Mehr Informationen zu diesem Buch und zu unserem Programm unter www.hanser.de/computer
Wissen wie Hacker ticken!
Zalewski Stille im Netz 320 Seiten. ISBN 978-3-446-40800-5
Hacker gehen den Weg des geringsten Widerstandes und suchen dazu nach nicht alltägliche Angriffsszenarien. Diese finden sie genau dort, wo das Wissen um mögliche Gefahren fehlt. Deshalb liefert das Buch keine fertigen Lösungen für konkrete Gefahren und wiegt den Leser nicht in absoluter Sicherheit – denn die ist illusorisch. Es erklärt vielmehr, wie Hacker denken, wo und wie sie nach Lücken in Systemen suchen, welche Gefahrentypen es gibt und weshalb sie gefährlich werden können. Ziel ist es, den Leser dafür zu sensibilisieren, Bedrohungen zu erkennen und adäquat darauf zu reagieren. Denn nur wer sich in die Logik des Hackers hineinversetzt, so Zalewskis Überzeugung, kann Angriffe wirklich effektiv abwehren. Mehr Informationen zu diesem Buch und zu unserem Programm unter www.hanser.de/computer
Für Alles-Wissen-Woller
Breymann Der C++ -Programmierer
C++ lernen – Professionell anwenden – Lösungen nutzen 963 Seiten. Mit DVD ISBN 978-3-446-41644-4
Egal ob Sie C++ lernen wollen oder Ihre Kenntnisse in der Softwareentwicklung mit C++ vertiefen, in diesem Buch finden Sie, was Sie brauchen. C++-Neulinge erhalten eine motivierende Einführung in die Sprache C++. Die vielen Beispiele sind leicht nachzuvollziehen. Klassen und Objekte, Templates, STL und Exceptions sind bald keine Fremdwörter mehr für Sie. Als Profi finden Sie in diesem Buch fortgeschrittene Themen wie ThreadProgrammierung, Netzwerk-Programmierung mit Sockets und grafische Benutzungsoberflächen. Durch den Einsatz der Boost- und Qt-Libraries wird größtmögliche Portabilität erreicht. Weil Softwareentwicklung nicht nur Programmierung ist, finden Sie hier auch Themen für die professionelle Arbeit im Team.
Mehr Informationen zu diesem Buch und zu unserem Programm unter www.hanser.de/computer
Konzentrieren Sie sich auf das Wesentliche!
Hunt/Thomas Der Pragmatische Programmierer 331 Seiten. ISBN 978-3-446-22309-7
Der Pragmatische Programmierer veranschaulicht zahlreiche Best Practices der Softwareentwicklung mit Hilfe von Anekdoten, Beispielen und interessanten Analogien. Wer dieses Buch liest, lernt, · die Anwender zu begeistern, · die echten Anforderungen zu finden, · gegen Redundanz anzugehen, · dynamischen und anpassbaren Quelltext zu schreiben, · effektiv zu testen, · Teams von Pragmatischen Programmierern zu bilden und · durch Automatisierung sorgfältiger zu entwickeln. Mehr Informationen zu diesem Buch und zu unserem Programm unter www.hanser.de/computer
Der ProjektmanagementKlassiker
Tom DeMarco Der Termin 272 Seiten. ISBN 978-3-446-41439-6
Mr. Tompkins, ein von einem Telekommunikationsriesen soeben entlassener Manager, hat die Aufgabe, sechs Softwareprodukte zu entwickeln. Dazu teilt Tompkins die ihm zur Verfügung stehende gigantische Entwicklungsmannschaft in achtzehn Teams auf - drei für jedes Produkt. Die Teams sind unterschiedlich groß und setzen verschiedene Methoden ein. Sie befinden sich im Wettlauf miteinander und haben einen gnadenlos engen Terminplan. Mit seinen Teams und der Hilfe zahlreicher Berater, die ihn unterstützen, stellt Mr. Tompkins die Managementmethoden auf den Prüfstand, die er im Laufe seines langen Managerlebens kennen gelernt hat. Jedes Kapitel endet mit einem Tagebucheintrag, der seine verblüffenden Erkenntnisse zusammenfasst. Mehr Informationen zu diesem Buch und zu unserem Programm unter www.hanser.de/computer
TYPO3 GEKONNT ERWEITERN // ■ Behandelt alle wesentlichen Aspekte der Extensionentwicklung ■ Berücksichtigt topaktuell Extbase und Fluid ■ Nur soviel allgemeine TYPO3-Grundlagen wie nötig ■ Ideale Mischung aus Referenz und Lernbuch ■ Code und Lösungen unter http://downloads.hanser.de und www.typo3-backstage.de
TYPO3-EXTENSIONS // TYPO3 spielt im Markt der Content Management Systeme eine zentrale Rolle. Mit ein Grund für diesen Erfolg sind die vielfältigen Möglichkeiten zur Erweiterung des Systems durch eigene Extensions.
TIPP // Suchen Sie Lösungen für Probleme im Umgang mit TYPO3? Dann könnte Ihnen das „TYPO3-Kochbuch“ von Alexander Ebner und Patrick Lobacher gefallen, das ebenfalls bei Hanser erschienen ist. //
alexander EBNER arbeitet als Webentwickler beim Münchner Reiseveranstalter FTI und setzt dort regelmäßig TYPO3 ein. patrick LOBACHER ist Geschäftsführer der Agentur typofaktum unternehmenskommunikation und berät seit 1996 Unternehmen beim Einsatz von Webtechnologien. Auch bernhard ULBRICH ist als Entwickler für FTI tätig, schwerpunktmäßig im Bereich TYPO3-Extensions. tobias HAUSER & christian WENZ sind Herausgeber der Content ManagementBibliothek bei Hanser und beschäftigen sich seit Mitte der Neunziger Jahre mit Webtechnologien. Dabei haben sie zahlreiche CMS- und Portal-Projekte realisiert. Ihre Erfahrungen geben sie als Trainer, Berater und Autoren an ihre Kunden und Leser weiter.
www.hanser.de/computer ISBN 978-3-446-41557-7
Web Developer, Webprogrammierer, Content Provider und Hoster, die TYPO3 einsetzen
9
783446 415577
Systemvoraussetzungen für eBook-inside: Internet-Verbindung und eBookreader Adobe Digital Editions.
Genau diesem Thema widmet sich dieses Buch. Es wendet sich an TYPO3-Anwender und -Entwickler, die mithilfe eigener Erweiterungen das TYPO3-Grundsystem leistungsfähiger machen möchten. Schritt für Schritt wird der Leser durch die Welt der Extensionprogrammierung für das TYPO3-Backend und -Frontend geleitet; dabei werden alle Aspekte sowohl der klassischen Extensionentwicklung behandelt als auch neue Ansätze wie Extbase und Fluid berücksichtigt. Unterstützt wird die Darstellung durch zahlreiche anschauliche Beispiele. Der Referenzteil nennt und erläutert sämtliche Referenzen, API‘s, Strukturen und Funktionen.