be_manager_relation: Löschverhalten bei "inline n-1" inkonsistent?
(Alle Addons und der Core auf dem aktuellen Stand, YForm 3.4.1, Core 5.11, PHP 7.3)
Mit Blick auf #915 wollte ich mir das Verhalten von be_manager_relation in der Variante "inline (multiple n-1)" ansehen. Dabei fiel mir auf:
-
Lösche im Formular von Tabelle A (Haupttabelle) eines von mehreren Inline-Formularen (Tabelle B). Nachdem der Datensatz A gespeichert ist, ist der gelöschte Untersatz B auch aus Tabelle B verschwunden. Erwartetes Verhalten! Passt.
-
Lösche in der Datentabelle von Tabelle A den ganzen DAtensatz auf einen Schlag. In der Tabelle B sind die Untersätze noch immer vorhanden. Unerwartetes Verhalten! So sollte es m.E. nicht sein.
Nun frage ich mich: ist das wirklich so gewollt oder ein Bug? Und wenn Bug: im ersten oder zweiten Fall?
Mein Testszenario: zwei Tabellen A und B. Tabellen und Felder im Table_Manager angelegt.
- A:
- Feld "titel", text
- Feld "detail": be_manager_Relation auf Tabelle b, Relationenfeld "xyz"
- B:
- Feld "titel", text
- Feld *xyz", integer
Ich würde erwarten, dass im zweiten Fall auch gelöscht wird.
In der ersten (korrekten) Variante übernimmt rex_yform_value_be_manager_relation das Löschen:
https://github.com/yakamara/redaxo_yform/blob/d4b1b250e479875e9ecc52681889cc4b7690e90f/plugins/manager/lib/yform/value/be_manager_relation.php#L387-L389
Beim Löschen eines Datensatzes gibt es zwar auch eine Aufräumaktion in rex_yform_manager_dataset:
https://github.com/yakamara/redaxo_yform/blob/d4b1b250e479875e9ecc52681889cc4b7690e90f/plugins/manager/lib/yform/manager/dataset.php#L515
die aber nur n:m-Relationen bereinigt:
https://github.com/yakamara/redaxo_yform/blob/d4b1b250e479875e9ecc52681889cc4b7690e90f/plugins/manager/lib/yform/manager/table.php#L333-L349
An der Stelle könnte man eingreifen, hinter das IF ein weiteres IF setzen und darin zusätzlich die Relationen vom Typ 5 (inline n-1) aufräumen:
if (5 == $field->getElement('type') && ($table_b = $field->getElement('table')) ) {
$table_a = $deleteSql->escapeIdentifier($this->getTableName());
$table_b = $deleteSql->escapeIdentifier($table_b);
$relation_b = $deleteSql->escapeIdentifier($field->getElement('field'));
$qry = "DELETE FROM $table_b WHERE NOT EXISTS (SELECT * FROM $table_a WHERE $table_a.id = $table_b.$relation_b)";
$deleteSql->setQuery( $qry );
}
Klar. Gerne als PR. Wäre eine große Hilfe. Eigentlich gehört da noch ein richtiges Löschen rein, sodass auch feldspezifische Inhalte entfernt werden können (z.B. Files bei Upload), aber wäre ein neues Issue.
Ich schiebe es auf 4.1. wenn du das vorher getestet hinbekommst, top. :)
Lassen wir es mal bei "4.1"; es scheint mir etwas komplizierter zu sein. Es läuft ja jetzt auch Vieles nicht mehr über direktes SQL
Ich hab mir den obigen Patch wieder in meine 4.0.2-Instanz eingebaut und schau mal, wie die Verträglichkeit mit 4.0.2 ist. Da sich in dem Teil keine Änderungen beim Sprung auf 4.0 ergeben haben, erwarte ich keine Probleme.
Aber über den Lösungsansatz an sich bin ich mir unsicher. Darf man die Subformulare wirklich einfach so per SQL löschen? Oder muss es anders eingebettet werden? Also im Rahmen von "Satz löschen" auch planvoll die Subformulare bzw. deren Datensätze löschen und das nicht einer "Aufräumaktion "removeRelationTableRelicts" überlassen?
Müsste es nicht Löschüberprüfungen geben? Sowohl mein Herauslöschen eines einzelnen Subformulars als auch bei allen. immerhin könnten auch auf die Subtabelle weitere Relationen eingerichtet sein oder sie sind in einem Choice adressiert?
Da hast du vollkommen Recht. Einfach per SQL ist falsch und nur eine Krücke. und eigentlich muss die ganze Reihe durchlaufen werden und bei einem Fehler, wieder alles rückgängig gemacht werden.
Ich hänge mich hier mal rein, da ich eben festgestellt habe das 1-n Relationen nicht gelöscht werden, wenn der "Hauptdatensatz" gelöscht wurde.
Lösen konnten wir es nur durch einen Trigger
DELIMITER $$
CREATE TRIGGER delete_rex_news
AFTER DELETE ON rex_news
FOR EACH ROW
BEGIN
DELETE FROM rex_news_blocks WHERE news = OLD.id;
END $$
DELIMITER ;
Dies ist aber so auch nur möglich da rex_news_blocks nicht noch weitere Tochter Tabellen hat.