TYPO3-Tutorial: Extension mit N zu M Datenbankrelationen erstellen

27. Mai 2008 | 13 Kommentare

TYPO3 Tutorials by undkonsorten BerlinDer Kickstarter für TYPO3-Extensions gibt einem Entwickler viele Möglichkeiten Datenbanken anzulegen, sogar MM-Tabellen. Aber leider lassen sich viele Funktionen, die modernes Datenbankdesign bietet, mit dem Kickstarter nicht umsetzen. Dieser Artikel gibt einen Einblick, wie in TYPO3 die wichtigsten Relationen zwischen Tabellen

  • M zu M
  • N zu M
  • N zu M mit Attributen

angelegt werden können.

NEU: Zu diesem Eintrag gibt es jetzt auch eine Demo-Extension im TYPO3-Extension-Repository: uk Datenbank Tutorial (t3uk_db_tutorial)

Auf 1:N Relationen wird hier nicht eingegangen, da diese vom Kickstarter voll unterstützt und einfach zusammen geklickt werden können.

Worum geht es hier genau?

Fangen wir mit einem einfachen Beispiel an. Für eine Freelancer-Datenbank die mit TYPO3 umgesetzt werden soll brauchen wir zwei Datensatztypen:

  • Mitarbeiter oder Freelancer sowie
  • Firmen bei für die diese Mitarbeiter gerade arbeiten.

Logischerweise sollen diese Daten miteinander verknüpft werden können. Mitarbeiter arbeiten für verschiedenen Firmen und für Firmen arbeiten verschiedenen Mitarbeiter. Nun soll die Eingabe der Verbindungen Mitarbeiter-Firma so flexibel sein, dass wir sie von beiden Seiten aus bearbeiten können.

Wird also zum Beispiel einem Mitarbeiter-Datensatz A eine Firma B zugeordnet, so sieht man auch im Firmen-Datensatz B, dass der Mitarbeiter bei der Firma arbeitet. Man kann so die Verbindung zwischen dem Mitarbeiter und der Firma sowohl beim Bearbeiten des Firmen-, als auch des Mitarbeiter-Datensatzes wieder lösen. Ferner kann natürlich der Firma B ein Mitarbeiter C zugeordnet werden und im Mitarbeiter-Datensatz C erscheint dann automatisch die Firma B.

In einem weiteren Schritt werden wir auch noch erklären, wie man der Verbindung noch weitere Eigenschaften wie Werksvertrag, studentische Hilfskraft oder freier Mitarbeiter hinzufügt.

Doch bereits das erste Szenario ist mit dem TYPO3-Kickstarter nicht mehr möglich: Wird mit dem eine Tabelle Firma angelegt mit dem Feld Mitarbeiter (Relation zu Mitarbeiter) und ein Mitarbeiter mit dem Feld Firma, so macht der Kickstarter daraus zwei M:M Tabellen. Es ist aber klar, dass sowohl Mitarbeiter als auch Firma über ein und dieselbe Relationstabelle verknüpft werden müssen, um die gewünschte, oben beschriebene Funktionalität zu erhalten. Dies wird ermöglicht mit ‚foreign_table‘ =>“ und ‚foreign_field‘ => “ welche in der tca.php der Extension definiert werden können.

Ein Beispiel der gewünschten Datenbankrelation:

Datenbankrelation Beispiel

Ein Projekt-Mitarbeiter kann für mehrere verschiedene Firmen arbeiten und eine Firma hat mehrere verschieden Mitarbeiter. Zunächst werden beide Tabellen im Kickstarter angelegt:

TYPO3 Datenbankrelation - Kickstarter

In der Tabelle Mitarbeiter wird nun eine Relation zur Tabelle Firma definiert:

TYPO3 Datenbankrelation - Kickstarter #2

In der Tabelle Firma wird eine Relation zur Tabelle Mitarbeiter definiert:

TYPO3 Datenbankrelation - Kickstarter #3

Beide Relationen müssen als True M-M relations markiert werden, da sonst keine extra Relationstabelle angelegt wird. Das beidseitige Anlegen von Mitarbeiter und Firma ermöglicht später das beidseitige Editieren (siehe oben).

Schaut man sich nun die ext_tables.sql der Exension an, erkennt man, dass zwei MM Relationstabellen angelegt werden. Eine für die Richtung Mitarbeiter->Firma und eine für Firma->Mitarbeiter:
ext_tables.sql

CREATE TABLE tx_ukdbtutorial_mitarbeiter_firma_mm (
uid_local int(11) DEFAULT ‚0‘ NOT NULL,
uid_foreign int(11) DEFAULT ‚0‘ NOT NULL,
tablenames varchar(30) DEFAULT “ NOT NULL,
sorting int(11) DEFAULT ‚0‘ NOT NULL,
KEY uid_local (uid_local),
KEY uid_foreign (uid_foreign)
);

CREATE TABLE tx_ukdbtutorial_firma_mitarbeiter_mm (
uid_local int(11) DEFAULT ‚0‘ NOT NULL,
uid_foreign int(11) DEFAULT ‚0‘ NOT NULL,
tablenames varchar(30) DEFAULT “ NOT NULL,
sorting int(11) DEFAULT ‚0‘ NOT NULL,
KEY uid_local (uid_local),
KEY uid_foreign (uid_foreign)
);

Es werden aber nicht beide benötigt, daher kann getrost eine Tabelle aus der Datei gelöscht werden, z.B. tx_ukdbtutorial_firma_mitarbeiter_mm. Außerdem muss bei der Relationstabelle ein Feld hinzugefügt werden: sorting_foreign int(11) DEFAULT ‚0‘ NOT NULL.

Dies ermöglicht das unterschiedliche Sortieren der Datensätze auf beiden Seiten und muss erstellt werden, da TYPO3 danach verlangt.
Das Resultat sieht dann also so aus:

CREATE TABLE tx_ukdbtutorial_mitarbeiter_firma_mm (
uid_local int(11) DEFAULT ‚0‘ NOT NULL,
uid_foreign int(11) DEFAULT ‚0‘ NOT NULL,
tablenames varchar(30) DEFAULT “ NOT NULL,
sorting int(11) DEFAULT ‚0‘ NOT NULL,
sorting_foreign int(11) DEFAULT ‚0‘ NOT NULL,
KEY uid_local (uid_local),
KEY uid_foreign (uid_foreign)
);

Jetzt muss noch dafür gesorgt werden, dass sowohl Firma als auch Mitarbeiter auf dieselbe Relationstabelle zugreifen:

$TCA[„tx_ukdbtutorial_firma“] = array (
„mitarbeiter“ => Array (
„exclude“ => 1,
„label“ => „LLL:EXT:uk_db_tutorial/locallang_db.xml:tx_ukdbtutorial_firma.mitarbeiter“,
„config“ => Array (
„type“ => „group“,
„internal_type“ => „db“,
„allowed“ => „tx_ukdbtutorial_mitarbeiter“,
„size“ => 10,
„minitems“ => 0,
„maxitems“ => 10,
„MM“ => „tx_ukdbtutorial_firma_mitarbeiter_mm“,
)

wird geändert in:

$TCA[„tx_ukdbtutorial_firma“] = array (
„mitarbeiter“ => Array (
„exclude“ => 1,
„label“ => „LLL:EXT:uk_db_tutorial/locallang_db.xml:tx_ukdbtutorial_firma.mitarbeiter“,
„config“ => Array (
„type“ => „group“,
„internal_type“ => „db“,
„allowed“ => „tx_ukdbtutorial_mitarbeiter“,
„size“ => 10,
„minitems“ => 0,
„maxitems“ => 10,
„MM“ => „tx_ukdbtutorial_mitarbeiter_firma_mm“,
„MM_opposite_field“ => „mitarbeiter“,
)

„MM“ => „tx_ukdbtutorial_mitarbeiter_firma_mm“ ist die zu benutzende Relationstabelle, sie muss sowohl bei Mitarbeiter als auch bei Firma dieselbe sein.
„MM_opposite_field“ => „mitarbeiter“ sorgt dafür das die uids in der Relationstabelle nicht vertauscht werden .
Diese Relation ist jetzt eigentlich eine N:M Relation da, z.B. mehrere Mitarbeiter einer Firma zugeordnet werden können, die Anzahl der Zuordnungen auf beiden Seiten aber nicht gleich sein muss. Möchte man dies haben sollten die Max number of relations im Kickstarter passend gesetzt werden.

N:M Relation mit Attributen

Ein Mitarbeiter kann in mehreren Firmen arbeiten, in diesen kann er bestimmte Positionen, z.B. Werksvertrag, studentische Hilfskraft, fester freier Mitarbeiter besitzen. Dies sind die Attribute.

Ein Beispiel: N zu M Relation mit Attributen

TYPO3 Datenbankrelation - N zu M

Es ist kann aber vorkommen, das ein Mitarbeiter in der Firma A einen Werksvertrag hat und in der Firma B studentische Hilfskraft ist. Es ist also nicht möglich die Position des Mitarbeiters in einem Feld in der Tabelle Mitarbeiter zu speichern, da die Position von der jeweiligen Firma abhängt. Das Attribut Position muss also in der Relationstabelle gespeichert werden. Dies lässt sich am besten mit Inline Rational Relation Editing (IRRE) realisieren:

Zunächst legt man zwei neue Tabellen an: Mitarbeiter2 und Firma2. Dies kann exakt, wie oben beschrieben, mit Hilfe des Kickstarters erfolgen.

Jetzt müssen wieder die tca.php und die ext_tables.sql editiert werden:
ext_tables.sql:

CREATE TABLE tx_ukdbtutorial_mitarbeiter2_firma_mm (
uid int(11) NOT NULL auto_increment,
pid int(11) DEFAULT ‚0‘ NOT NULL,
tstamp int(11) DEFAULT ‚0‘ NOT NULL,
tablenames varchar(30) DEFAULT “ NOT NULL,
sorting int(11) DEFAULT ‚0‘ NOT NULL,
position tinytext NOT NULL,
mitarbeiterid int(11) DEFAULT ‚0‘ NOT NULL,
firmaid int(11) DEFAULT ‚0‘ NOT NULL,
crdate int(11) DEFAULT ‚0‘ NOT NULL,
cruser_id int(11) DEFAULT ‚0‘ NOT NULL,
deleted tinyint(4) DEFAULT ‚0‘ NOT NULL,
PRIMARY KEY (uid),
KEY parent (pid)
);
);

Die zweite Relationstabelle tx_ukdbtutorial_firma2_mitarbeiter_mm kann wieder gelöscht werden. Wir benötigen jetzt das neue Feld position und 2 Felder zu Steuerung mitarbeiterid und firmaid. uid_local und uid_foreign werden als Felder nicht mehr benötigt, dafür aber eine uid und eine pid. Die uid ist wie immer der Primary Key und wird daher auf auto_increment gesetzt.
cruser, tstamp, deleted und crdate werden von TYPO3 benötigt.
Man sieht jetzt schon das die Relationstabelle nicht mehr klassisch aufgebaut ist , sondern wie eine ganz normale „Datensatz“-Tabelle., dazu später mehr.

In der tca.php muss nun etwas mehr geändert werden:

$TCA[„tx_ukdbtutorial_mitarbeiter2“] = array (
„interface“ => array (
„showRecordFieldList“ => „hidden,name,firma“
),
„firma“ => Array (
„exclude“ => 1,
„label“ => „LLL:EXT:uk_db_tutorial/locallang_db.xml:tx_ukdbtutorial_mitarbeiter2.firma“,
„config“ => Array (
‚type‘ => ‚inline‘,
‚foreign_table‘ => ‚tx_ukdbtutorial_mitarbeiter2_firma_mm‘,
‚foreign_field‘ => ‚mitarbeiterid‘,
‚foreign_label‘ => ‚firmaid‘,
),
),
$TCA[„tx_ukdbtutorial_firma2“] = array (
„interface“ => array (
„showRecordFieldList“ => „hidden,name,mitarbeiter“
),
„mitarbeiter“ => Array (
„exclude“ => 1,
„label“ => „LLL:EXT:uk_db_tutorial/locallang_db.xml:tx_ukdbtutorial_firma2.mitarbeiter“,
„config“ => Array (
‚type‘ => ‚inline‘,
‚foreign_table‘ => ‚tx_ukdbtutorial_mitarbeiter2_firma_mm‘,
‚foreign_field‘ => ‚firmaid‘,
‚foreign_label‘ => ‚mitarbeiterid‘,
),
),

type‘ => ‚inline‘: Jetzt wird nicht länger die Groupbox von TYPO3 benutzt, sondern IRRE. Das heißt, dass Kinderelemente oder Relationen direkt in dem Mitarbeiter bzw. der Firma angelegt werden können.
foreign_table‘ =>: Definiert welche Relationstabelle benutzt wird, muss auch hier wieder gleich sein.
Achtung es darf kein „MM“ => benutzt werden, da dann keine Attribute mehr unterstützt werden.

Außerdem muss die Relationstabelle in der tca.php definiert werden:

$TCA[‚tx_ukdbtutorial_mitarbeiter2_firma_mm‘] = Array(
„ctrl“ => $TCA[„tx_ukdbtutorial_mitarbeiter2_firma_mm“][„ctrl“],
„interface“ => Array (
„showRecordFieldList“ => „mitarbeiterid,firmatid,position“
),
„feInterface“ => $TCA[„tx_ukdbtutorial_mitarbeiter2_firma_mm“][„feInterface“],
‚columns‘ => Array(
‚mitarbeiterid‘ => Array(
‚label‘ => ‚LLL:EXT:uk_db_tutorial/locallang_db.xml:tx_ukdbtutorial_mitarbeiter2‘,
‚config‘ => Array(
‚type‘ => ’select‘,
‚foreign_table‘ => ‚tx_ukdbtutorial_mitarbeiter2′,
’size‘ => 1,
‚minitems‘ => 0,
‚maxitems‘ => 1,
),
),
‚firmaid‘ => Array(
‚label‘ => ‚LLL:EXT:uk_db_tutorial/locallang_db.xml:tx_ukdbtutorial_firma2‘,
‚config‘ => Array(
„type“ => „group“,
„internal_type“ => „db“,
„allowed“ => „tx_ukdbtutorial_firma2“,
„size“ => 1,
„minitems“ => 1,
„maxitems“ => 1,)
),
‚position‘ => Array(
‚label‘ => ‚LLL:EXT:uk_db_tutorial/locallang_db.xml:tx_ukdbtutorial_mitarbeiter2_firma_mm.position‘,
‚config‘ => Array(
„type“ => „input“,
„size“ => „30“,
),
),
),
„types“ => Array (
„0“ => Array(„showitem“ => „hidden;;1,firmaid,mitarbeiterid,position“)
),
„palettes“ => Array (
„1“ => Array(„showitem“ => „“)
)
);

Die Konfiguration für das Backend wurde hier so gestaltet, dass bestehende Mitarbeiter über eine Selectorbox und bestehende Firmen über eine eine Groupbox ausgewählt werden können.
Die Eingabe der Position kann über ein normales Input Feld erfolgen.

In der ext_tables.php wird nun ebenfalls die Relationstabelle definiert:

$TCA[„tx_ukdbtutorial_mitarbeiter2_firma_mm“] = Array (
„ctrl“ => Array (
‚title‘ => ‚LLL:EXT:uk_db_tutorial/locallang_db.xml:tx_ukdbtutorial_mitarbeiter2_firma_mm‘,
‚label‘ => ‚uid‘,
‚tstamp‘ => ‚tstamp‘,
‚crdate‘ => ‚crdate‘,
„dynamicConfigFile“ => t3lib_extMgm::extPath($_EXTKEY).“tca.php“,
„iconfile“ => t3lib_extMgm::extRelPath($_EXTKEY).“icon_tx_ukdbtutorial_firma2.gif“,
),
„feInterface“ => Array (
„fe_admin_fieldList“ => „mitarbeiterid, firmaid, position“,
)
);

Jetzt müssen nur noch die Labels für die Relationstabelle in der locallang_db.xml gesetzt werden:

<label index=“tx_ukdbtutorial_mitarbeiter2_firma_mm“>Mitarbeiter-Firma</label>
<label index=“tx_ukdbtutorial_mitarbeiter2_firma_mm.position“>Position</label>

Nun kann man das Resultat im Backend bewundern, das Ganze sieht dann wie folgt aus:

TYPO3 Datenbankrelation - Backend N zu M

Wie man sieht , können, jetzt auch die Relation an sich bearbeitet werden. Sie erscheinen in dem Sysordner als regulärer Datensatz.

Bearbeitung der Firma:

TYPO3 Datenbankrelation - Backend N zu M - Firma

Bearbeitung des Mitarbeiters:

TYPO3 Datenbankrelation - Backend N zu M - Mitarbeiter

Zum Verständnis:
Neu anlegen meint in diesem Fall das Neuanlegen einer Relation, es können keine neuen Firmen innerhalb eines Mitarbeiters angelegt werden, sondern nur bestehende ausgewählt werden.

TYPO3 Datenbankrelation - Backend N zu M - Relation
Man kann IRRE aber auch so konfigurieren, das neue Kindelemente direkt angelegt werden können.

Weiterführende Links

symbol: t3uk datenbank tutorial, TYPO3 uk Datenbank Tutorial (t3uk_db_tutorial)

Näheres zu IRRE

Ein sehr ausführliches Tutorial zu IRRE:

Podcast zu IRRE

Es gibt noch sehr viele Möglichkeiten das Backend für die Datensätze zu gestalten:
TYPO3 Core Library

Ähnliche Artikel:

Meta-Daten



13 Kommentare

Auch mal Kommentieren:

Kommentar