Oldperl hat geschrieben:Hab ich nun was falsch gemacht oder muss man bei eurem geposteten Code noch was besonders beachten?
nun, dieser code wurde nicht direkt für contenido geschrieben, sondern war als anregung gedacht. ich habe mal die funktion
strMoveUpCategory entsprechend umgeschrieben (datei
contenido/includes/functions.str.php):
Code: Alles auswählen
/**
* @copyright Copyright © 2009, w3concepts AG
* @author Andreas Kummer, w3concepts AG
* @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License
*/
function strMoveUpCategory ($idcat) {
global $db;
global $cfg;
$idcat = (int) $idcat;
$db->query('' .
'update ' .
' ' . $cfg['tab']['cat'] . ' as catone, ' . // previous cat
' ' . $cfg['tab']['cat'] . ' as cattwo, ' . // current cat
' ' . $cfg['tab']['cat'] . ' as catthree, ' . // following cat
' ' . $cfg['tab']['cat'] . ' as catfour ' . // preprevious cat
'set ' .
' catone.preid = catone.postid, ' .
' catone.postid = cattwo.postid, ' .
' cattwo.preid = catone.preid, ' .
' cattwo.postid = cattwo.preid, ' .
' catthree.preid = catone.idcat, ' .
' catfour.postid = cattwo.idcat ' .
'where ' .
' cattwo.preid = catone.idcat ' .
' and catthree.preid = cattwo.idcat ' .
' and catfour.idcat = catone.preid ' .
' and cattwo.idcat = ' . $idcat);
if ($db->affected_rows() > 0) {
return;
}
/*
* Update not done, because the catgory to be moved is either
* the last or the first one in the row.
*/
$db->query('' .
'update ' .
' ' . $cfg['tab']['cat'] . ' as catone, ' . // previous cat
' ' . $cfg['tab']['cat'] . ' as cattwo, ' . // current cat
' ' . $cfg['tab']['cat'] . ' as catfour ' . // preprevious cat
'set ' .
' catone.preid = catone.postid, ' .
' catone.postid = cattwo.postid, ' .
' cattwo.preid = catone.preid, ' .
' cattwo.postid = cattwo.preid, ' .
' catfour.postid = cattwo.idcat ' .
'where ' .
' cattwo.preid = catone.idcat ' .
' and catfour.idcat = catone.preid ' .
' and cattwo.idcat = ' . $idcat);
if ($db->affected_rows() > 0) {
return;
}
/*
* Update not done, because the category to be moved is the first
* one in the row.
*/
$db->query('' .
'update ' .
' ' . $cfg['tab']['cat'] . ' as catone, ' . // previous cat
' ' . $cfg['tab']['cat'] . ' as cattwo, ' . // current cat
' ' . $cfg['tab']['cat'] . ' as catthree ' . // following cat
'set ' .
' catone.preid = catone.postid, ' .
' catone.postid = cattwo.postid, ' .
' cattwo.preid = catone.preid, ' .
' cattwo.postid = cattwo.preid, ' .
' catthree.preid = catone.idcat ' .
'where ' .
' cattwo.preid = catone.idcat ' .
' and catthree.preid = cattwo.idcat ' .
' and cattwo.idcat = ' . $idcat);
}
das kannst du ja mal bei dir in einer testumgebung einbauen. das ist jetzt allerdings zunächst nur die verschiebung eine ebene nach oben. und nicht gleich in eine produktive umgebung einbauen, sondern zuerst eingehend testen.
analog funktioniert auch die verschiebung nach unten. die prüfungen, ob wir uns bereits zuoberst befinden oder zuunterst (innerhalb der gleichen ebene), bedarf keiner weiteren prüfung, da die queries kein update vornehmen, sollte das der fall sein. die con_cat_tree muss dabei nicht - wie das bisher der fall war - neu erstellt werden, da sich bei einer solchen operation das level ja nicht verändern kann.
bei der verschiebung eines astes in einem anderen ast (
strMoveSubtree) kann das verfahren ebenfalls angewendet werden. der code ist freichlich nicht identisch; ich meine damit jetzt bloss das prinzip des simultanen updates mehrerer einträge (oder tabellen). und das beschreibene problem tritt eben genau dort auf.
will heissen: dieser code löst das aktuelle problem nicht, da dieses ist der strMoveSubtree oder einer nachgeschalteten aktion auftritt. aber dieser code zeigt auf, wie man mit einer verringerung der komplexität das problem lösen kann.
dann zur frage, ob eine nachträglich überführung in die dritte (resp. 5.) normalform möglich ist oder nicht: sobald man anpassungen am datenmodell vornimmt, werden verschiedene teile betroffen sein. ich würde deshalb auch nicht dafür plädieren, gleich alles über den haufen zu schmeissen. was jedoch ohne weiteres zu machen ist, ist folgendes:
- bei abfragen der navigation auf die preid verzichten (diese information ist redundant)
- sobald keine stellen mehr vorhanden sind, welche die preid verwenden, kann diese einfach entfernt und die verschiebeoperationen entsprechend vereinfacht werden.
- das level in der con_cat_tree ist ebenfalls redundant und könnte gleich behandelt werden. dazu muss in analogie bei der abfrage das level aus der unterordnung abgeleitet werden. sobald das vorgenommen ist, kann die tabelle sowie die für die erstellung der tabelle vorgesehen funktionen gelöscht werden.
- zur weiteren verbesserung kann die tabelle con_cat um die merkmale lft und rgt ergänzt werden (für die bildung verschachtelter mengen) und die erforderlichen aktualisierungsabfragen in den entsprechenden funktionen ergänzt werden. auch hier gilt: sobald die abfragen, die vorgenommen werden, alle nur noch die lft und rgt für die bildung des kategoriebaumes verwenden, kann dann auch die postid entfernt werden.
kurz gesagt: es ist durchaus möglich, eine sanfte überführung in ein normalisiertes datenmodell vorzunehmen. es muss nicht alles in einem schritt erfolgen. was jedoch zwingend erforderlich ist: die entwickler (wenn es denn solche gibt), insbesondere die entwickler von modulen müssen auf die empfohlene variante aufmerksam gemacht werden. sonst bleibt das rückwärtskompatiblitätsproblem ewig bestehen. der beste weg dazu, ist eine - allerdings gute und leistungsfähige - API für den kategorienzugriff. wenn diese besteht und leistungsfähig ist, können die einzelnen schritte vorgenommen werden.
ich möchte mich nicht immer des klagens bezichtigen lassen. es sind auch nicht einfach klagen ohne jeden grund. es ist keine entwicklung mehr zu erkennen. und schlimmer noch, es gibt eben auch keine konsolidierung und kein bemühen, die komplexität zu reduzieren. es ist eher das gegenteil der fall. mit jeder anpassung wird der code noch etwas komplexer (und das ist beileibe keine positive qualität). ich sage an dieser stelle wieder, was ich schon des öfteren gesagt habe: offenbar wird nichts in den code integriert, dass nicht aus der richtigen quelle stammt. was auch immer der grund dafür ist, schädlich ist es alleweil. kann es sein, dass es damit zu tun hat, dass in jeder einzelnen datei ein copyright-hinweis von 4fb zu finden ist? denn dieser dürfte mindestens nicht alleine 4fb obliegen, wenn entwickler beteiligt sind, die nicht bei 4fb angestellt sind. und zwar unabhängig davon, wie die lizenz ansonsten aussieht. das urheberrecht ist unveräusserlich und liegt wie der name sagt beim urheber, sofern dieser nicht bei 4fb angestellt ist. und ohne explizite übertragung der nutzungsrechte ergibt sich für 4fb eben kein copyright. deshalb habe ich mir erlaubt, in die funktion den in diesem fall zutreffenden urheberhinweis zu integrieren (gnu/gpl gilt uneingeschränkt).