Anzeige
Anzeige
Artikel
Artikel merken

Die Zukunft der Extension-Entwicklung: Neues MVC-Framework „Extbase“ ebnet den Weg von 4.x zu FLOW3

Mit der kommenden TYPO3-Version 5 und deren neu entwickelter Basis FLOW3 wird sich vieles an der bisher gewohnten Art ändern, für TYPO3 zu entwickeln. Die neue Version wird allerdings erst in einigen Monaten für den Einsatz in Produktiv-Umgebungen zur Verfügung stehen. Mit Extbase, einem neuen Framework für Extensions, das ab Version 4.3 fester Bestandteil von TYPO3 ist, können Entwickler schon heute ihre Extensions im Stil der Version 5 programmieren. Wir zeigen, was Extbase kann und wie das Framework funktioniert.

12 Min. Lesezeit
Anzeige
Anzeige

Im Oktober 2008 fanden in Berlin die „Transition Days“ statt. Die Mitglieder des TYPO3 Core-Teams erarbeiteten dort eine gemeinsame Vision und Strategie für den Übergang von der heutigen Version 4.x zur kommenden Version 5. Ein Ergebnis dieses überaus fruchtbaren Treffens war die Entscheidung, einen modernen Nachfolger für die Basisklasse „tslib_piBase“ zu entwickeln, auf der heute die Mehrzahl der über 3.600 TYPO3-Extensions basiert. Eine wichtige Zielsetzung für die Entwicklung des neuen Extension-Frameworks: Es soll die Lücke zwischen dem aktuellen 4er-Zweig und der kommenden 5er-Version überbrücken und sich so nahe wie möglich an den Ideen, der Architektur und den Schnittstellen von FLOW3 orientieren.

Anzeige
Anzeige

Auf den folgenden Seiten blicken wir aus drei verschiedenen Richtungen darauf, wie man in Zukunft Extensions mit Extbase entwickelt. Zunächst aus der Perspektive des „Auftraggebers“, dann anhand eines Beispiels aus dem Inneren einer Extension, abschließend blicken wir hinter die Kulissen des Frameworks.

Konzentration bitte!

Erfolgreiche Software-Projekte sind oft geprägt von einem gegenseitigen Lernprozess: Die Entwickler lernen, sich in der Domäne des Auftraggebers gedanklich und sprachlich zu bewegen. Der Auftraggeber lernt, anhand des entstehenden Codes nachzuvollziehen, ob die Struktur und Geschäftslogik seiner Domäne adäquat umgesetzt wurde. Das erfordert eine von allen Beteiligten gleich verstandene Sprache („Ubiquitous Language“).

Anzeige
Anzeige

Die Domäne des Auftraggebers wird während dieses gegenseitigen Lernprozesses in abstrahierte Softwareobjekte – das Domänen-Modell („Domain Model“) – übersetzt [1]. Objekte, die explizit nicht zum Domänen-Modell gehören sind solche, die für das Speichern und Wiederauffinden, die Validierung, Filterung und Darstellung von Daten zuständig sind. Diese werden weitgehend aus der Extension herausgenommen und in Extbase ausgelagert.

Anzeige
Anzeige

Eric Evans hat für diesen Entwicklungsprozess den Ausdruck „Domain-Driven Design“ geprägt [2]. Der Vorteil dabei ist eine „natürlich“ anmutende Konzentration auf das Wesentliche: den Nutzen für den Auftraggeber. Extbase ist um das Konzept des Domain-Driven Design „herum gebaut“ und unterstützt diese Vorgehensweise optimal, ohne den Entwickler darauf zu beschränken.

Ein Beispiel für ein einfaches Domänen-Modell bietet die Extension „BlogExample“, die als Anwendungsbeispiel für Extbase im TYPO3 Extension Repository zum freien Download steht [3]. Das Domänen-Modell dieser Beispiel-Extension sieht wie folgt aus: Ein Blog (von dem es mehrere geben kann) hat einen Namen und eine Beschreibung. Es „enthält“ beliebig viele Posts. Ein Post hat wiederum einen Autor, einen Titel, einen Inhalt, ein Veröffentlichungsdatum usw. Einem Post können Stichworte (Tags) zugeordnet werden. Außerdem haben die Besucher des Blogs die Möglichkeit, Kommentare zu verfassen. Ein Blog besteht also aus einer Ansammlung („Aggregate“) von Objekten (Blog, Post, Comment, Tag), die in einer Art Baumstruktur enthalten sind. Die Baumstruktur hat genau ein Objekt als Wurzel („Aggregate Root“).

Anzeige
Anzeige

Das Domänen-Modell der Beispiel-Extension „BlogExample“.

Das Domänen-Modell der Beispiel-Extension „BlogExample“.

Über das Wurzel-Objekt „Blog“ wird auf alle enthaltenen Sammlungen (Posts, Comments und Tags) zugegriffen (Traversierbarkeit, Navigierbarkeit). Ein direktes Auslesen aus der Datenbank, zum Beispiel eines Tags, ist nicht notwendig (und auch nicht erlaubt). Die Wurzel-Objekte selbst werden über eigene Objekte verwaltet, die so genannten „Repositories“, die weiter unten noch näher erläutert werden. Werfen wir aber zunächst einen Blick auf die Blog-Klasse:

PHP

 1	class Tx_BlogExample_Domain_Model_Blog extends
 	 Tx_Extbase_DomainObject_AbstractEntity {
 2
 3		protected $name = '';
 4		protected $description = '';
 5		protected $logo;
 6		protected $posts = array();
 7
 8		public function setName($name) {
 9			$this->name = $name;
10		}
11
12		public function getName() {
13			return $this->name;
14		}
15
16		public function setDescription($description) {
17			$this->description = $description;
18		}
19
20		public function getDescription() {
21			return $this->description;
22		}
23
24		public function addPost(Tx_BlogExample_Domain_Model_Post $post) {
25			$this->posts[$post->getUid()] = $post;
26		}
27
28		public function removePost(Tx_BlogExample_Domain_Model_Post
		     $postToRemove) {
29			foreach ($this->posts as $uid => $post) {
30				if ($post === $postToRemove) {
31					unset($this->posts[$uid]);
32				}
33			}
34		}
35		[...]
36		public function findPostsByTag($tag) {
37			$foundPosts = array();
38			foreach ($this->posts as $post) {
39				foreach ($post->getTags() as $postTag) {
40					if (strtolower($postTag) === strtolower($tag)) {
41						$foundPosts[] = $post;
42						break;
43					}
44				}
45			}
46			return $foundPosts;
47		}
48		[...]
49 	}

Listing 1

Die Blog-Klasse wird von einem generischen Domänen-Objekt abgeleitet, dem AbstractEntity-Objekt (Zeile 1). Dadurch werden unter anderem Methoden für die Verwaltung und Überwachung des internen Zustands des Objekts zur Verfügung gestellt.

Die neue Verzeichnisstruktur einer Extension.

Die neue Verzeichnisstruktur einer Extension.

Alle Eigenschaften des Objekts werden als „protected“ gekennzeichnet (Zeilen 3-6). Auf diese kann dann nur indirekt über so genannte „getter“- und „setter“-Methoden zugegriffen werden (Zeilen 8-22). Post-Objekte werden dabei intern unter ihrer UID in einem Array abgelegt (Zeilen 24-26). Etwas komplexer ist die Methode zum Löschen eines Posts, da die Objekt-Identität geprüft wird (Zeilen 28-34). Die Methode „findPostsByTag()“ zeigt die oben beschriebene Navigierbarkeit vom Wurzel-Objekt „Blog“ zum „Tag“-Objekt auf der dritten Hierarchieebene (Zeilen 36-47). Interessant ist hier, dass das Argument „$tag“ als String übergeben wird und mit dem Tag-Objekt in „$postTag“ verglichen wird. Dies gelingt, da das „Tag“-Objekt über seine Methode „toString()“ zunächst in einen String umgewandelt wird.

Anzeige
Anzeige

Und Action!

Das Domänen-Modell liegt jetzt in Form von einzelnen Klassen-Dateien im richtigen Ordner auf dem Server. Doch wie bringt man diese in Aktion? Die richtigen Objekte, angefüllt mit den richtigen Daten, es müssen zur rechten Zeit angefordert werden, um sie dann im gewünschten Format auszugeben.

Die Kontrolle über diesen Vorgang hat eine spezielle Klasse von Objekten, die „Controller“. Ein Controller ruft entsprechend seinem erteilten Auftrag („Request“) (2) die Domänen-Objekte aus den Lagerräumen („Repositories“) ab – (3) und (4) – und leitet sie an das für die Ausgabe zuständige Objekt der Klasse „View“ weiter (5). Dieses spezialisierte Objekt kümmert sich nun selbständig um die Transformation der Daten in die gewünschte Form (meist in HTML-Code auf Basis einer Vorlage). Den fertigen Inhalt geben sie als Antwort („Response“) über den Controller an TYPO3 zurück (6).

Diese sinnvolle Trennung der Zuständigkeiten und die darauf aufbauende Abfolge des Informationsflusses nennt man nach den drei beteiligten Klassen auch das „Model-View-Controller“-Muster (oder kurz: MVC-Pattern).

Anzeige
Anzeige

Der Durchlauf durch eine Extension (vereinfacht).

Der Durchlauf durch eine Extension (vereinfacht).

Zur Verdeutlichung noch mal der Ablauf der einzelnen Schritte:

  1. TYPO3 arbeitet den Seiteninhalt ab und „entdeckt“ das Plugin auf der Seite. Es ruft aber nicht die Extension direkt auf, sondern übergibt die Kontrolle zunächst dem Disponenten („Dispatcher“) von Extbase. Der Dispatcher entscheidet auf Grundlage der von TYPO3 übergebenen Konfiguration und der $_GET/$_POST-Parameter, welche Kombination aus Controller und Action die Kontrolle übernehmen soll.
  2. Der Dispatcher übergibt dem zuständigen Controller nun alle Informationen, die für die weitere Steuerung des Ablaufs notwendig sind. Intern führt der Controller die passende Aktion („Action“) in Form einer Methode aus.
  3. Innerhalb der Action-Methode wird zunächst das zuständige Repository angefragt. Dies geschieht mit Hilfe einer „find“-Methode (siehe Tabelle weiter unten).
  4. Das Repository liefert ein fertig gebautes Domänen-Objekt zurück. In unserem Beispiel ist dies eine Instanz der Klasse „Blog“. Dieses Blog-Objekt enthält bereits alle zugehörigen Post-, Comment- und Tag-Objekte (zur Beruhigung für Experten: Lazy Loading wird zukünftig unterstützt).
  5. Die Action-Methode ordnet dem zuständigen View-Objekt das Blog-Objekt zu (assign()) und fordert es auf, den Inhalt im gewünschten Ausgabeformat zu erzeugen (render()).
  6. Der View gibt den erzeugten Inhalt innerhalb des Response zurück an den Dispatcher. Dieser reicht diesen abschließend weiter an den übergeordneten TYPO3-Rendering-Prozess.

Bemerkenswert an diesem Weg durch die Extension ist, dass an keiner Stelle eine Methode aufgerufen wird, die ein Objekt aus einer Datenbank lädt oder speichert. Man muss also nicht explizit die Funktion „$blog->save()“ aufrufen, falls man das Blog während der Laufzeit geändert hat. Wichtig ist nur, dass das Objekt durch ein Repository verwaltet wird. Extbase erkennt dann automatisch geänderte Eigenschaften des Objekts und persistiert diese, nachdem die Extension durchlaufen wurde.

Exkurs: Das Repository
Ein Repository ist ein Zwitter-Wesen. Es gehört zwar zur Domäne, steht aber mit einem „Bein“ in der Infrastruktur (Datenbankanbindung). Man kann sich die Funktionsweise eines Repositorys ähnlich der einer Universitätsbibliothek vorstellen: „An der Theke beauftragt man bei einen Mitarbeiter, ein Buch nach bestimmten Kriterien zu finden. Nach wenigen Minuten bis Tagen erhält man dann das entsprechende Buch. Dabei spielt es für den Anfordernden keine Rolle, an welchem Ort das Buch im Keller steht. Es spielt prinzipiell auch keine Rolle, ob das Buch schon hinter dem Tresen liegt, im Keller geholt werden muss, per Fernleihe von einer anderen Bibliothek angefordert wird oder erst noch gedruckt werden muss. Wichtig ist nur, dass das Buch irgendwann physisch vor einem liegt. Bleistiftliche Anmerkungen im Buch werden bei der Rückgabe (hoffentlich ohne Änderungen) einfach übernommen.“Übersetzt heißt dies für ein Repository: „Über ein Repository beauftragt man eine Methode, ein Objekt nach bestimmten Kriterien zu finden. Nach wenigen Millisekunden bis Sekunden erhält man dann das entsprechende Objekt. Dabei spielt es für den Anfordernden keine Rolle, an welchem Ort das Objekt gespeichert ist. Es spielt prinzipiell auch keine Rolle, ob das Objekt schon im Arbeitsspeicher liegt, von der Festplatte geholt werden muss, per Web Service von einem anderen Server angefordert wird oder das erste Mal instanziiert werden muss. Wichtig ist nur, dass das Objekt irgendwann instanziiert vor einem liegt. Geänderte Eigenschaften des Objekts werden beim Verlassen der Extension (hoffentlich ohne Änderungen) einfach übernommen.“

Um Objekte im Repository aufzufinden, stehen bereits einige generische „find“-Methoden zur Verfügung. Für komplexere Anfragen können (und müssen) eigene „find“-Methoden implementiert werden.

Anzeige
Anzeige
Aufruf Funktionalität
$repository->findAll() Das Repository liefert alle Objekte der verwalteten Klasse zurück, die nicht als gelöscht oder ausgeblendet gekennzeichnet sind.
$repository->findByFoo(‚bar‘) Das Repository liefert alle Objekte der verwalteten Klasse zurück, deren Eigenschaft „$foo“ mit dem gegebenen Wert übereinstimmt und die nicht als gelöscht oder ausgeblendet gekennzeichnet sind.
$repository->findOneByFoo(‚bar‘) Wie findByFoo(‚bar‘). Diesmal wird aber nur das erste gefundene Objekt zurückgegeben.

Die Controller spielen beim Ablauf innerhalb einer Extension die zentrale Rolle. Werfen wir daher einen Blick auf einige ausgewählte Actions des BlogController der Beispiel-Extension (Listing 2).

PHP

 1	class Tx_BlogExample_Controller_BlogController extends Tx_Extbase_MVC_Controller_ActionController {
 2		[...]
 3		/**
 4		* Index action for this controller. Displays a list of blogs.
 5		* @return string The rendered view
 6		*/
 7		public function indexAction() {
 8			$this->view->assign('blogs', $this->blogRepository->findAll());
 9		}
10		[...]
11		/**
12		* Displays a form for creating a new blog
13		* @return string An HTML form for creating a new blog
14		*/
15		public function newAction() {
16		}
17
18		/**
19		* Creates a new blog
20		* @param string $name The name of the new blog
21		* @param string $description The description of the new blog
22		* @return void
23		* @validate $name Text, Length(maximum = 150)
24		*/
25		public function createAction($name, $description) {
26			$blog = t3lib_div::makeInstance('Tx_BlogExample_Domain_Model_Blog');
27			$blog->setName($name);
28			$blog->setDescription($description);
29			$this->blogRepository->add($blog);
30			$this->redirect('index');
31		}
32		[...]
33		/**
34		* Updates an existing blog
35		* @param int $blogUid The uid of the the existing, unmodified blog
36		* @param string $name The updated name of the blog
37		* @param string $description The updated blog description
38		* @return void
39		*/
40		public function updateAction($blogUid, $name, $description) {
41			$blog = $this->blogRepository->findOneByUid($blogUid);
42			$blog->setName($name);
43			$blog->setDescription($description);
44			$this->redirect('index');
45		}
46		[...]
47 	}

Listing 2

Der BlogController ist von der Klasse „ActionController“ des Frameworks abgeleitet (Zeile 1). Damit wird unter anderem sichergestellt, dass alle Argumente, die an Actions übergeben werden, zuvor validiert wurden. Innerhalb der „indexAction()“ (Zeile 8) werden zunächst aus dem BlogRepository Instanzen aller vorhandenen Blog-Objekte bezogen (findAll()). Diese werden dann anschließend dem View unter dem Variablennamen „blogs“ zugewiesen (assign()). Da die Methode „render()“ des Views automatisch aufgerufen wird, erzeugt diese eine Zeile schon eine vollständige Listenausgabe aller Blogs.

Noch erstaunlicher wird dies bei der „newAction()“, deren Aufgabe es ist, ein Formular für die Eingabe eines neuen Blogs anzuzeigen (Zeilen 11 bis 16). Die Methode enthält keine einzige Zeile Code. Dass diese Methode trotzdem das Formular ausgibt, liegt an der „Intelligenz“ von Extbase, den richtigen View mit dem passenden HTML-Template aufgrund von Namenskonventionen automatisch zu instanziieren und aufzurufen.

Anzeige
Anzeige

Die Action „createAction()“ (Zeilen 18 bis 31) und die Action „updateAction()“ (Zeilen 33 bis 45) unterscheiden sich auf den ersten Blick nur geringfügig. In Zeile 25 werden bereits validierte Argumente übergeben, deren Inhalt in einem HTML-Formular eingegeben wurden. Es wurde zum Beispiel geprüft, ob im Textfeld „Beschreibung“ schädlicher Skript-Code enthalten war, bevor es dem Argument „$description“ zugewiesen wurde.

Die Regel für die Validierung entnimmt Extbase dem PHP-Kommentar über der eigentlichen Methode (Zeilen 20,21 und 23 sowie 35 bis 37). Durch die Angabe „@param int $blogUid […]“ wird Extbase zum Beispiel mitgeteilt, dass der Wert vom Typ „Integer“ sein muss. Komplexere Validierungsregeln können explizit angegeben werden („@validate […]“).

Als View kommt bei Extbase standardmäßig „Fluid“ zum Einsatz. Fluid ist die vollständig neuentwickelte Template-Engine für TYPO3 v5, die ebenfalls auf TYPO3 v4.x zurückportiert wurde. Mehr zu diesem überaus mächtigen Werkzeug finden Sie im Artikel von Sebastian Kurfürst in dieser Ausgabe des t3n-Magazins ab Seite 124.

Anzeige
Anzeige

Was die Welt im Innersten zusammenhält

Der folgende Abschnitt bietet für fortgeschrittene Entwickler einen kurzen Blick hinter die Kulissen des Frameworks. Einsteiger können diesen Absatz überspringen.

Extbase baut in weiten Teilen auf zurückportiertem FLOW3-Code auf. Wo dies nicht möglich war, mussten Funktionalitäten nachgebildet werden. Dies betrifft vor allem das Content-Repository von FLOW3, dessen Funktion in Extbase durch eine eigene, transparente Persistenz-Schicht übernommen wird. Dazu wird im Dispatcher eine Persistence-Session (nach dem „Unit of Work“-Pattern) eingerichtet, in der alle neu hinzugefügten, geänderten und entfernten Domänen-Objekte registriert werden. Nach dem Durchlauf durch die Extension werden die registrierten Objekte mit Hilfe eines Objekt-Relationalen Mappers (ORM) persistiert. Der ORM hat die Aufgabe, zwischen der hierarchischen Objekt-Struktur der Aggregate und dem relationalen Modell der Datenbank in beide Richtungen zu übersetzen. Dazu gehört insbesondere die Verwaltung der Relations-Tabellen für m:n-Beziehungen und die Kapselung der Metadaten aus dem $TCA in Data- und Column-Maps.

Eine Herausforderung war dabei die Registrierung der geänderten Properties der Domänen-Objekte sowie die Wiederherstellung (Rekonstitution) eines Objekts aus einer Datenbank-Tupel. Gelöst wurde dies durch die Ableitung der Domänen-Objekte von abstrakten Domänen-Objekten. Dies ermöglicht das Setzen und Auslesen von Properties, die als „protected“ gekennzeichnet sind. In FLOW3 steht dafür die Aspektorientierte Programmierung (AOP) als eleganteres Werkzeug zur Verfügung. In Extbase werden die Werte der Properties kurz nach der Rekonstitution in einem internen Array als „clean properties“ abgelegt und beim Committen der Persistence-Session mit den aktuellen Werten verglichen.

„Konvention geht vor Konfiguration“ ist ein weiteres wichtiges Grundprinzip von Extbase (und von FLOW3). Durch die Festlegung von Namenskonventionen und einer korrespondierenden Ordnerstruktur konnte der Konfigurationsaufwand eines Frontend-Plugins auf zwei Zeilen reduziert werden.

Neue Basen kehren gut

Manch einer mag sich fragen, welche Vorteile Extbase Entwicklern beim Programmieren von Extensions gegenüber dem „herkömmlichen“ Weg bietet und welche Aus- und Nebenwirkungen die Verwendung von Extbase hat.

Extbase gibt eine klare Trennung verschiedener Zuständigkeiten vor, die eine einfache Wartung des Codes und dessen modulare Erweiterung erst möglich machen. Durch den modularen Aufbau sinken die Entwicklungszeit für die Erst- und Anpassungsentwicklungen sowie die damit verbundenen Kosten. Extbase entlastet den Entwickler außerdem bei sicherheitskritischen und wiederkehrenden Aufgaben (Validierung der übergebenen Argumente, Einbindung der Seitenvorlagen, Persistenz der Daten, Auslesen der Einstellungen aus TypoScript und FlexForms). Dadurch befähigt und ermutigt Extbase den Entwickler, sich weitgehend auf die Lösung der Aufgabe des Auftraggebers zu konzentrieren.

Extensions, die auf Extbase aufbauen, können mit überschaubarem Aufwand zu TYPO3 v5 portiert werden, da die Struktur der Extension, die Namenskonventionen und die verwendete Schnittstellendefinition (API) sich weitgehend gleichen.

Eine moderne Extension-Architektur und aktuelle Software-Paradigmen steigern die Attraktivität für neue Entwickler (auch aus der Java-Welt). Extbase setzt allerdings anderes Fachwissen als bisher voraus. Es werden vermehrt solche Fähigkeiten verlangt, die nicht TYPO3-spezifisch sind, sondern zu einer breiteren Qualifikation beitragen (z. B. in den Bereichen Software-Architektur oder der Qualitätssicherung durch Software-Tests). Das erworbene Fachwissen kann ohne Weiteres auf FLOW3 oder andere Software-Projekte angewendet werden.

Extbase fördert insgesamt den „mentalen“ Übergang der TYPO3-Entwickler, indem der Lernpfad hin zur TYPO3-Version 5 früher als bisher beschritten werden kann. Dieser Artikel mag der Auftakt dazu sein.

Bitte einsteigen!

Wer sich mit dem neuen Framework vertraut machen möchte, sollte sich mit der Beispiel-Extension beschäftigen und parallel dazu die Extbase-Dokumentation [4] lesen. Darauf aufbauend empfiehlt sich ein weitergehendes Studium grundlegender Literatur zu den verwendeten Paradigmen. Sollten noch Fragen offen bleiben, kann man sich an die Mailingliste der TYPO3-Entwickler wenden [5].

In Kürze wird es außerdem einen neu entwickelten Kick-Starter geben, der das Domain-Driven Design voll unterstützt. Abschließend sei allen Menschen für ihr Engagement gedankt, die in den letzten Monaten an Extbase mitgearbeitet haben. In diesem Sinne: „Inspire people to share!“.

Mehr zu diesem Thema
Fast fertig!

Bitte klicke auf den Link in der Bestätigungsmail, um deine Anmeldung abzuschließen.

Du willst noch weitere Infos zum Newsletter? Jetzt mehr erfahren

Anzeige
Anzeige
Ein Kommentar
Bitte beachte unsere Community-Richtlinien

Wir freuen uns über kontroverse Diskussionen, die gerne auch mal hitzig geführt werden dürfen. Beleidigende, grob anstößige, rassistische und strafrechtlich relevante Äußerungen und Beiträge tolerieren wir nicht. Bitte achte darauf, dass du keine Texte veröffentlichst, für die du keine ausdrückliche Erlaubnis des Urhebers hast. Ebenfalls nicht erlaubt ist der Missbrauch der Webangebote unter t3n.de als Werbeplattform. Die Nennung von Produktnamen, Herstellern, Dienstleistern und Websites ist nur dann zulässig, wenn damit nicht vorrangig der Zweck der Werbung verfolgt wird. Wir behalten uns vor, Beiträge, die diese Regeln verletzen, zu löschen und Accounts zeitweilig oder auf Dauer zu sperren.

Trotz all dieser notwendigen Regeln: Diskutiere kontrovers, sage anderen deine Meinung, trage mit weiterführenden Informationen zum Wissensaustausch bei, aber bleibe dabei fair und respektiere die Meinung anderer. Wir wünschen Dir viel Spaß mit den Webangeboten von t3n und freuen uns auf spannende Beiträge.

Dein t3n-Team

Wolfgang Becker

Der Link zur Doku scheint nicht zu gehen:

[5] http://typo3.org/extensions/repository/view/doc_extbase/current/
Extbase-Dokumentation

Wo kann man sonst noch die DOku finden?

Antworten

Melde dich mit deinem t3n Account an oder fülle die unteren Felder aus.

Bitte schalte deinen Adblocker für t3n.de aus!
Hallo und herzlich willkommen bei t3n!

Bitte schalte deinen Adblocker für t3n.de aus, um diesen Artikel zu lesen.

Wir sind ein unabhängiger Publisher mit einem Team von mehr als 75 fantastischen Menschen, aber ohne riesigen Konzern im Rücken. Banner und ähnliche Werbemittel sind für unsere Finanzierung sehr wichtig.

Schon jetzt und im Namen der gesamten t3n-Crew: vielen Dank für deine Unterstützung! 🙌

Deine t3n-Crew

Anleitung zur Deaktivierung
Artikel merken

Bitte melde dich an, um diesen Artikel in deiner persönlichen Merkliste auf t3n zu speichern.

Jetzt registrieren und merken

Du hast schon einen t3n-Account? Hier anmelden

oder
Auf Mastodon teilen

Gib die URL deiner Mastodon-Instanz ein, um den Artikel zu teilen.

Anzeige
Anzeige