C3: Tutorial Extension Entwicklung 1.Teil: Grundlagen

Aus Contao Community Documentation


Hinweis.png Hinweis: I'm on a mission: In diesem und in den folgenden Tutorials werde ich die Videos von Tristan Lins zur Contao3 Extension Entwicklung transkribieren. Da dies immer reichlich Zeit in Anspruch nimmt, bleibt dieser Hinweis immer so lange stehen, bis ich ein Video fertig transkribiert habe. Bitte daher erstmal nicht erweitern. Anschließend könnt ihr das natürlich gerne tun. Stand:20.4.13



Dieses Tutorial basiert auf der Screencast-Reihe von Tristan Lins *Youtube-Link einfügen...wir dummerweise vom Spamfilter geblockt*. Es empfiehlt sich unbedingt parallel auch das Video anzuschauen.

"Information"


Einleitung

Seit 2010 arbeite ich nun schon mit Contao. Vorher habe ich die CMS Joomla, Typo3 und Drupal ausprobiert und muss sagen: Contao rocks! Leider hat das CMS aus meiner Sicht jedoch einen entscheidenden Nachteil gegenüber anderen Systemen: Es gibt kaum Tutorials (Tagebuch einer Extension Entwicklung), die "semiprofessionellen" Programmierern einen schrittweisen und zusammenhängenden Einstieg in die Extension-Entwicklung mit Contao 3 ermöglichen.

Dank der Screencast-Reihe von Tristan Lins auf Youtube habe ich den Eintsieg gefunden. Ich persönlich mag es aber auch, Tutorials in geschriebener Form vor mir zu haben. Daher habe ich damit begonnen, die Videos in dieses Wiki zu übertragen. Viel Spaß damit!

An wen richtet sich dieses Tutorial?

Dieses Tutorial ist für all diejenigen gedacht, die ein Step-by-Step Tutorial zum Einstieg in die Extension-Entwicklung mit Contao 3 suchen.

Lernziel

In diesem Tutorial lernt ihr die Grundlagen der Extension-Entwicklung mit Contao 3 anhand eines praktischen Beispiels. Es wird ein Modul programmiert, welches verschiedene Screencast-URLs inkl. Titel auflistet.

<----Bild der fertigen Extension BE + FE----->

Was man wissen sollte

Grundlagen in PHP, objektorientierter Programmierung und SQL sind nötig. Natürlich sollte man sich auch mit den Grundlagen von Contao 3 auskennen.

Vorbereitung

Eine Version von Contao 3.0.4 oder höher sollte installiert sein. Optional: Da die Extension in das bestehende „Music Academy“-Theme integriert wird, empfiehlt es sich, selbiges zu installieren. Ferner sollte folgende Ordnerstruktur in contao/system/modules angelegt werden: Verzeichnisstruktur der Erweiterung Zum Verständnis: Im Verzeichnis modules liegen die Module, die bereits von Contao mitgeliefert werden, wei FAQ, Calendar etc. Auch unser Erweiterungsmodul 'screen- cast' gehört in dieses Verzeichnis.

Einen Menüeintrag im Inhaltsbereich der Backend-Module erzeugen.

  • Erstellt im Verzeichnis config die Datei config.php.
    In der config.php werden z.B. Frontend- und Backend-Module registriert.
  • Schreibt in die config.php folgenden Code:
<?php
 
/**
 * Back end modules
 */
$GLOBALS['BE_MOD']['content']['screencast'] = array(
	'tables' => array('tl_screencast'),
	'icon'   => 'system/modules/screencast/assets/images/screencast.png'
);

Dabei steht ['BE_MOD']['content'] für die Elemente der Backend-Module im Inhaltsbereich (Array). Durch die Erweiterung des Arrays um ['screencast'] wird unser neues Modul referenziert. Als Wert wird dem Array ein assoziatives Array mit zwei Einträgen (Verweis auf die Tabelle in der Datenbank, sowie auf die Bilddatei) übergeben.

  • Fügt in den Ordner screencast/assets/images ein Icon für euer Modul ein.
  • Da das assets-Verzeichnis geschützt ist, müsst ihr noch eine .htaccess Datei in screencast/assets/ speichern. Darin muss stehen:
Order Allow, Deny
Allow from all

Nun soll in der Auflistung der Elemente im Backend-Modul auch eine entsprechende Übersetzung ausgegeben werden.

  1. Erstellt hierzu ein Verzeichnis de in eurem Verzeichnis screencast/languages/
  2. Erstellt in diesem Verzeichnis eine Datei modules.php
  3. In diese Datei gebt ihr folgenden Code ein:
<?php
 
$GLOBALS['TL_LANG']['MOD']['screencast'][0] = 'Screencasts';
$GLOBALS['TL_LANG']['MOD']['screencast'][1] = 'Screencasts verwalten';
  1. Öffnet eure Contao-Backend und navigiert dort zu System->Einstellungen.
  2. Setzt dort einen Haken unter den Sicherheitseinstellungen->Internen Cache umgehen. Und
    Sicherheitseinstellungen->Fehlermeldungen anzeigen.
  3. Eure Seitenleiste sollte nach einer Aktualisierung der Seite nun so aussehen:

Die Backend-Module sind nun um den Eintrag "Screencasts" erweitert

Heureka! Der Eintrag erscheint in der Liste. Leider wirft Contao jedoch nach Klick auf Screencast noch eine Fehlermeldung. Was fehlt? Contao kann noch kein DCA-Objekt erstellen.

Was macht ein DCA?

"Data Container Arrays (DCAs) dienen zur Speicherung von Tabellen-Metadaten. Jedes DCA beschreibt die Konfiguration einer bestimmten Tabelle, ihre Beziehungen zu anderen Tabellen sowie die einzelnen Felder. Die Contao Core-Engine erkennt anhand dieser Metadaten, wie Datensätze aufgelistet, bearbeitet und gespeichert werden."

(Quelle: https://contao.org/de/manual/3.0/data-container-arrays.html, Stand: 6.4.13)

Wie ist ein DCA aufgebaut?

"Ein Data Container Array ist in 6 Sektionen unterteilt. Die erste Sektion speichert globale Informationen wie z.B. Relationen zu anderen Tabellen. Die zweite und dritte Sektion legt fest, wie Datensätze aufgelistet werden und welche Aktionen ein Benutzer ausführen kann. Die vierte Sektion definiert verschiedene Gruppen von Eingabefelder (Paletten) und die letzten beiden Sektionen beschreiben die Eingabefelder im Detail."

(Quelle: https://contao.org/de/manual/3.0/data-container-arrays.html, Stand: 6.4.13)

Neu in Contao 3: In der DCA-Datei werden auch die SQL-Befehle eingetragen. Eine separate Datei ist nicht mehr notwendig. Alles klar? Nicht? Ok...dann Schritt für Schritt.

Das Formular zur Eintragung der Daten erstellen, sowie die Datenbank-Tabelle anlegen.

Erstellt im Verzeichnis screencast/dca/ eine Datei mit Namen tl_screencast.php.

Die Tabellenkonfiguartion

Anmerkung: Ab jetzt ist "Mut zur Lücke" gefordert. Einige Sachverhalte sind mir in dem Screencast nicht ganz klar geworden. Leider ist auch die Dokumentation auf Contao.org in diesem Bereich noch recht rudimentär. Ich schreib daher auf, was ich verstanden habe.

Auf der Contao-Seite kann man sich über die möglichen Einträge in den DCA informieren. Leider ist hier derzeit noch nicht aufgeführt, welchem Array-Abschnitt welche Einträge zugeordnet sind. Tristan empfiehlt, sich die Verwendungsmöglichkeiten in bestehenden Modulen abzugucken. Für die nachfolgenden Erklärungen empfiehlt es sich jedoch trotzdem, den DCA-Teil der Online-Doku aufzufrufen, um scih über die Bedeutung der Arrayeinträge zu informieren.

Wer nicht alles selber schreiben möchte oder etwas nicht lesen kann, kopiert sich nun erstmal den gesamten Inhalt der Datei sytem/modules/core/dca/tl_theme.php in die tl_screencast.php und modifiziert diese nur entsprechend der folgenden Beispiele.

  • Schreibt in die Datei tl_screencast.php folgende Zeilen Code:
<?php
 
 
/**
 * Table tl_screencast
 */
$GLOBALS['TL_DCA']['tl_screencast'] = array
(
 
	// Config
	'config'   => array
	(
		'dataContainer'    => 'Table',
		'enableVersioning' => true,
		'sql'              => array
		(
			'keys' => array
			(
				'id' => 'primary'
			)
		),
	),

Was passiert hier? In diesem Abschnitt legen wir die Grundeinstellungen für unser Modul fest, so z.B. woher die Daten kommen. Ergänzt die Datei mit folgendem Code (Video: 17:47):

// List
	'list'     => array
	(
		'sorting'           => array
		(
			'mode'        => 2,
			'fields'      => array('title'),
			'flag'        => 1,
			'panelLayout' => 'filter;sort,search,limit'
		),

Was passiert hier? Im diesem Abschnitt wird festgelegt, wie die Datensätze aufgelistet werden und welche Sortieroptionen dem Nutzer zur Verfügung stehen sollen. So steht 'panelLayou't z.B. dafür, welche Optionen in der Kopzeile erscheinen sollen. Semiokolon oder Komma stehen dafür, ob das Layout (ein- oder mehrzeilig). Fragt mich aber nicht, warum 'filter' in Tristans Beispiel nicht auftaucht.

Die Elemente des Panel Layouts

Schaut bzgl. der anderen Optionen der Online-Doku unter "Datensätze auflisten" nach.

  1. Ergänzt die Datei mit folgendem Code (Video: 20:45):
'label'             => array
		(
			'fields' => array('title'),
			'format' => '%s',
		),

Was passiert hier? Hier werden die Bezeichnungen gesetzt, die später in der Listenansicht erscheinen sollen. In unserem Fall also immer der Titel der Screencasts. <----Bild der Screencast Liste----->

  • Ergänzt die Datei mit folgendem Code (Video: 21:25):
'global_operations' => array
		(
			'all' => array
			(
				'label'      => &$GLOBALS['TL_LANG']['MSC']['all'],
				'href'       => 'act=select',
				'class'      => 'header_edit_all',
				'attributes' => 'onclick="Backend.getScrollOffset()" accesskey="e"'
			)
		),

Was passiert hier? Bei den 'global operations' handelt es sich um die Bearbeitungsfelderunterhalb der Filterfelder.

<----Bild der global Operations----->

  • Ergänzt die Datei mit folgendem Code (Video: 21:44):
'operations'        => array
		(
			'edit'   => array
			(
				'label' => &$GLOBALS['TL_LANG']['tl_screencast']['edit'],
				'href'  => 'act=edit',
				'icon'  => 'edit.gif'
			),
			'delete' => array
			(
				'label'      => &$GLOBALS['TL_LANG']['tl_screencast']['delete'],
				'href'       => 'act=delete',
				'icon'       => 'delete.gif',
				'attributes' => 'onclick="if(!confirm(\'' . $GLOBALS['TL_LANG']['MSC']['deleteConfirm'] . '\'))return false;Backend.getScrollOffset()"'
			),
			'show'   => array
			(
				'label'      => &$GLOBALS['TL_LANG']['tl_screencast']['show'],
				'href'       => 'act=show',
				'icon'       => 'show.gif',
				'attributes' => 'style="margin-right:3px"'
			),
		)
	),

Was passiert hier? Bei den 'operations' handelt es sich um die Bearbeitungsfelder zu jedem Listeneintrag. <----Bild der Operations----->

<----Bild der global Operations----->

Nun kommen wir zum eigentlichen Herzstück einer jeden Erweiterung: Das Formular zum Anlegen der Screencasts. Im DCA wird dieses definiert unter dem Bereich 'palettes'.

  • Ergänzt die Datei mit folgendem Code (Video: 22:55):
// Palettes
	'palettes' => array
	(
		'default'       => '{title_legend},type,title',{screencast_legend},url'
),

Was passiert hier? Die Grobstruktur des Formulars wird angelegt, also das, was später dem BE-User zur Dateneingabe präsentiert wird. Dabei stehen in den geschweifen Klammern immer die Abschnittsnamen. Es folgen die Felder. Ein Semikolon leitet einen neuen Abschnitt ein. <----Bild des BE Templates----->

  1. Ergänzt die Datei mit folgendem Code (Video: 24:30)
// Fields
	'fields'   => array
	(
		'id'     => array
		(
			'sql' => "int(10) unsigned NOT NULL auto_increment"
		),
		'tstamp' => array
		(
			'sql' => "int(10) unsigned NOT NULL default '0'"
		),
		'title'  => array
		(
			'label'     => &$GLOBALS['TL_LANG']['tl_screencast']['title'],
			'inputType' => 'text',
			'exclude'   => true,
			'sorting'   => true,
			'flag'      => 1,
                        'search'    => true,
			'eval'      => array(
				'mandatory'   => true,
                                'unique'         => true,
                                'maxlength'   => 255,
				'tl_class'        => 'w50',
 
			),
			'sql'       => "varchar(255) NOT NULL default ''"
		),
                'url'    => array
		(
			'label'         => &$GLOBALS['TL_LANG']['tl_screencast']['url'],
			'inputType' => 'text',
			'exclude'     => true,
			'sql'            => "text NULL"
		)
       )
);

Was passiert hier? Im Abschnitt 'fields' werden alle Felder definiert, die in der Datenbank-Tabelle angelegt werden sollen. Dies sind meist mehr Felder, als im Formular des Backend-Moduls ausgegeben werden (z.B. wird man die id wohl fast immer automatisch setzen). Die Felder 'id' und 'tstamp' sind übrigens immer Pflicht. 'sql' ist (Überraschung) immer das SQL-Statement.

Kümmern wir uns der um die einzelnen Felder: 'title' und 'url' sind die beiden Eingabefelder im BE-Modul. Diese haben wir auch in den 'palettes' definiert. Beide felder werden noch mit einigen weiteren Eigenschaften konfikuriert:

  • label: Ist eine Referenz auf die Sprachvariable, die noch erstellt wird.
  • inputType: (s. Contao-Docs) in userem Fall ein Textfeld
  • exclude: Erlaubt dem Admin, dieses Feld später für Redakteure zu sperren.
  • sorting: Bestimmt, dass dieses Feld oben in der Sortierpalette angewählt werden kann
  • flag: Regelt die Sortierreihenfolge
  • search: Bestimmt, dass nach dieses Feld oben in der Sortierpalette gesucht werden kann
  • eval: Konfiguriert ein Eingabefeld im Detail (s. Contao-Docs). In unserem Fall ob es ein Pflichtfeld ist, ob es einzigartig ist, die Textfeldlänge sowie die Darstellung, wie dieses Feld im BE-Modul angezeigt wird. Schaut euch zu tl_class auch das Video an oder den Abschnitt "Felder ausrichten" in den Docs.
  • Diejenigen, die den Code aus der tl_theme.php kopiert haben:

Löscht bitte den nachfolgenden Code aus eurer Datei. Die Klassendefinition wird für diese Beispiel nicht benötigt.

  • Der große Moment ist nah: Navigiert im Contao-BE zu System->Erweiterungskatalog und klickt auf Datenbank aktualisieren.

Wenn ihr alles richtig gemacht habt, solltet ihr nun eine Meldung von Contao darüber erhalten, dass eine neue Tabelle angelegt wird. Klickt auf Aktualisieren.

  • etzt könntet ihr eigentlich schon einen Screencast anlegen....aber es fehlen noch die Sprachvariablen.
  • Erstellt daher eine Datei tl_screencast.php im Verzeichnis screencast/languages/de.
  • Gebt folgenden Code in diese Datei ein (Video: 32:30):
<?php
 
$GLOBALS['TL_LANG']['tl_screencast']['title_legend'] = 'Titel';
 
$GLOBALS['TL_LANG']['tl_screencast']['type'][0] = 'Typ';
$GLOBALS['TL_LANG']['tl_screencast']['type'][1] = 'Wählen Sie hier aus, ob es sich um ein externes oder lokales Video handelt.';
 
$GLOBALS['TL_LANG']['tl_screencast']['title'][0] = 'Titel';
$GLOBALS['TL_LANG']['tl_screencast']['title'][1] = 'Geben Sie hier den Screencast Titel ein.';
 
$GLOBALS['TL_LANG']['tl_screencast']['screencast_legend'] = 'Screencast';
 
$GLOBALS['TL_LANG']['tl_screencast']['url'][0] = 'Video URL';
$GLOBALS['TL_LANG']['tl_screencast']['url'][1] = 'Geben Sie hier die Video URL ein.';
 
$GLOBALS['TL_LANG']['tl_screencast']['new'][0] = 'Neuer Screencast';
$GLOBALS['TL_LANG']['tl_screencast']['new'][1] = 'Einen neuen Screencast anlegen';
 
$GLOBALS['TL_LANG']['tl_screencast']['edit'][0] = 'Screencast bearbeiten';
$GLOBALS['TL_LANG']['tl_screencast']['edit'][1] = 'Screencast ID %s bearbeiten';
 
$GLOBALS['TL_LANG']['tl_screencast']['delete'][0] = 'Screencast löschen';
$GLOBALS['TL_LANG']['tl_screencast']['delete'][1] = 'Screencast ID %s löschen';
 
$GLOBALS['TL_LANG']['tl_screencast']['show'][0] = 'Screencastdetails';
$GLOBALS['TL_LANG']['tl_screencast']['show'][1] = 'Details des Screencast ID %s anzeigen';

Was passiert hier? Es werden alle Übersetzungen angelegt, die für das Backend notwendig sind. Die notwendigen Keys der Arrays findet ihr z.T. in der DCA-Datei unter 'paletts' bzw. im Bereich 'global operations' und 'operations'. Die Beschreibungen der Felder liegen immer auf dem zweiten Arrayeintrag. Beispiel: ['title'] bezieht sich auf das den paletts-Eintrag title. [0] ist dabei der Titel des BE-Feldes.[1] ist die Beschreibung unterhalb des Feldes. Diese wird automatisch hinzugefügt.

Anlegen der Klasse für die Ausgabe-Logik

(Video:39:00)

Das FE-Template erstellen

(Video 43:00)

Die Übersetzung für das FE-Template erstellen (Video 44:00)

(Video 43:00)

Erstellung der autoloader-Dateien

Geschafft!

Ausblick

Weiterführende Links

Ansichten
Meine Werkzeuge

Contao Community Documentation

was passiert eigentlich, wenn man per zip alle gezippten cache-css cached, bevor der cache vom apache gezippt wird?

Christian de la Haye
Navigation
Verstehen
Verwenden
Entwickeln
Verschiedenes
Werkzeuge