Advanced SQL - Praxistutorial 1 - Tauschangebot machen Teil 3
1. Die Abschnitte
- Vorwort
- Die Datenbank-Klasse
- Verbindungsaufbau
- Login
- Die grundsätzliche Vorgehensweise
- Die Übersichtsliste
- Mitglied auf dem Marktplatz anzeigen
- Mitglied anbieten Teil 1
- Mitglied anbieten Teil 2
- Direktangebot machen Teil 1
- Direktangebot machen Teil 2
- Tauschangebot machen Teil 1
- Tauschangebot machen Teil 2
- Tauschangebot machen Teil 3
2. Die Methode transactExchangeOffer
... sieht erst mal ziemlich pupsig aus, hat es aber in sich. Außerdem gibt es eine Premiere, denn wir werden in diesem Tutorial zum ersten Mal mit einer halbwegs vernünftigen Fehlerbehandlung arbeiten. Werfen wir zunächst einen Blick auf den grundsätzlichen Aufbau.
public function transactExchangeOffer($queries, $settings) {
try {
$this -> beginTransaction();
...
$this -> commit();
}
catch(PDOExecption $e) {
$this -> rollback();
}
}
Erläuterung
Im try
-Block wird zuerst eine Transaktion gestartet. Dann kommen die eigentlichen Queries (im Moment das ...
). Die werden dann
per commit
dauerhaft in die Datenbank geschrieben. Aber was ist, wenn irgendwas in die Hose geht? Nun, dann wird im catch
-Block
einfach ein Rollback gestartet und nichts passiert.
3. Die Queries
Wo bis dato nur die drei Pünktchen standen, gehört der folgende Code hin.
if ($this -> insert($queries['angebot'], $settings['angebot'])) {
$insert_id = $this -> lastInsertId();
for ($i = 0; $i < count($settings['mitglied']); $i++) {
$settings['mitglied'][$i][':angebot'] =
sprintf($settings['mitglied'][$i][':angebot'], $insert_id);
$this->insert($queries['tausch'], $settings['mitglied'][$i]);
}
}
Erläuterung
Zunächst tragen wir die Daten für die Tabelle angebot
ein ($this -> insert($queries['angebot'], $settings['angebot'])
).
Warum in einer Bedingung? Ganz einfach, wenn alles geklappt hat, so gibt execute
ein true
zurück. Dann holen wir uns mit
der PDO-Methode $this -> lastInsertId()
die ID des Datensatzes.
Dann wird das Array $settings['mitglied']
durchlaufen. Und jetzt kommt die Sache mit dem %d
. Der ist wie schon gesagt ein Platzhalter
und wird dann mit der PHP-eigenen Methode sprintf durch den Wert der Variable
$insert_id
ersetzt. Zu guter Letzt werden dann die Werte in die Tabelle tausch
geschrieben.
4. Aber
Wenn ihr jetzt in dem Formular ein paar Mitglieder auswählt und auf den Submit-Button klickt, fliegt euch auf einmal eine dicke Fehlermeldung um die Ohren.
Fatal error: Uncaught exception 'PDOException'
with message 'SQLSTATE[23000]: Integrity constraint violation:
1452 ... a foreign key constraint fails
Dumm gelaufen
Was zum Teufel ist denn jetzt los? Wo passt was nicht und warum? Leider ist obige Fehlermeldung nicht sehr aussagekräftig. Jetzt könnte ich euch bis zum Sankt-Nimmerleins-Tag suchen lassen. Oder ich verrate es euch.
5. Das Problem
Schaut euch mal genau den SQL-Dump an, wo es um die Tabelle angebot
geht. Dämmert schon was? Nun dort gibt es folgenden Eintrag.
FOREIGN KEY (`fuer`) REFERENCES `mitglied` (`id`)
ON DELETE CASCADE ON UPDATE CASCADE
In der Spalte fuer
muss also ein Eintrag stehen, der in der Tabelle mitglied
vorkommt. Wir allerdings wollen Dank unseres üblen
Datenmodells eine 0
hineinschreiben. Und das kann nicht klappen, weil es in der mitglied
keinen entsprechenden Wert bei der ID gibt.
Und nun?
Da es sich hier um ein Tutorial handelt, könntet ihr den Fremdschlüssel aus dem Dump entfernen und ihn neu einspielen. Aber was ist, wenn der Fehler euch erst auffällt, nachdem schon zig tausend Eintrage in die Datenbank geschrieben wurden und dort auch bleiben sollen?
6. Die Lösung
Dafür reicht eine einfache SQL-Anweisung aus, die prinzipiell so aussieht.
ALTER TABLE angebot DROP FOREIGN KEY [symbol];
[symbol]???
Das ist jetzt ein wenig kompliziert. Also MySQL verwaltet Fremdschlüssel über das schon genannte Symbol. Dabei handelt sich um eine Art von interner
Namensvergabe. Die Vergabe läuft nach dem Schema tabellenname_ibfk_fortlaufenden_nummer
ab. Zumindest bei mir.
Aber wie
... kommt man an den Namen ran? Da gibt es zum Beispiel die Möglichkeit über ein SHOW CREATE TABLE angebot;
. Dann bekommt man in der Spalte
Create_Table
das Symbol aufgelistet. Wenn man es findet. Oder man exportiert in phpMyAdmin/HeidiSQL die Tabellenstruktur und schaut sich das
Ergebnis an. Oder man greift auf die Tabelle key_column_usage
der Datenbank information_schema
zu. Vorausgesetzt, man hat die
entsprechenden Rechte.
SELECT
CONSTRAINT_NAME
FROM
information_schema.key_column_usage
WHERE CONSTRAINT_NAME LIKE 'angebot%'
AND TABLE_NAME = 'angebot'
AND COLUMN_NAME = 'fuer'
Egal wie ihr vorgeht, der Name von [symbol]
lautet angebot_ibfk_3
. Den kann man nun ganz einfach plätten und es klappt auch wieder.
Probiert es aus.
ALTER TABLE angebot DROP FOREIGN KEY angebot_ibfk_3;
7. Fazit
Ich hoffe, ihr habt ein paar Dinge über PDO, Views, Prepared Statements, Transaktionen und Fremdschlüssel gelernt. Im kommenden Tutorial werden wir dann das Niveau ein wenig steigern und uns weiter vorarbeiten.