dedlfix: Array mit Nested Set Werten zu Html-Liste/Menu verarbeiten

Beitrag lesen

Tach!

/* Beziehung zwischen Menüs und Seiten */
CREATE TABLE cms\_menu\_pages (  id int(11) NOT NULL AUTO_INCREMENT,
leftkey int(11) NOT NULL,
rightkey int(11) NOT NULL,
menu\_id int(11) NOT NULL,
page\_id int(11) NOT NULL,

Das ist ja die Nested-Sets-Tabelle. Und sie ist gleichzeitig die Verbindungstabelle einer m:n-Beziehung zwischen Menüs und Seiten. Für das Verständnis ist es wichtig, die Beziehungen zwischen den beiden abseits des Datenbankschemas und mehr aus fachlicher Sicht zu kennen. Ist es so, dass alle Menüpunkte in menues gelistet sind und in menu_pages die hierarchische Struktur abgebildet ist? Andererseits kann ich mir vorstellen, dass die m:n-Beziehung aussagt, welche Menüpunkte auf welcher Seite zu sehen sein soll. Wie aber spielt das mit der Hierarchie zusammen. Ein Menüpunkt kann vermutlich auf mehreren Seiten auftauchen und dann ist er mehrmals in den Nested Sets enthalten, oder nicht? Oder ist das alles ganz anders? Hier sehe ich Aufklärungsbedarf.

SELECT
    cms\_menues.name AS menuName,
    cms\_menu\_pages.leftkey,
    cms\_menu\_pages.rightkey,
    cms\_pages.id,
    cms\_pages.name
FROM cms\_menu\_pages
JOIN cms\_pages
ON cms\_menu\_pages.page\_id = cms\_pages.id
JOIN cms\_menues
ON cms\_menu\_pages.menu\_id = cms\_menues.id

Es joint hier zur m:n-Tabelle die m- und n-Tabelle, um deren Daten zu bekommen.

Zur WHERE-Klausel komme ich gleich noch. Aber du hast da eine Gruppierung,

GROUP BY cms\_menu\_pages.page\_id

mit der du viel mehr Spalten direkt und nicht aggregiert abfragst, als hier gruppiert wurden. Das lässt nur MySQL zu, anderswo wird das als Fehler geahndet. MySQL nimmt dann als Ergebnis pro Gruppe irgendeinen Wert dieser ungruppierten Spalten. Zu jeder Page-Id kommt also irgendeine beliebige Menu-ID ins Ergebnis. Das scheint mir komisch zu sein, aber vielleicht löst sich ja mit Kenntnis der Bedeutung auf. Zurück zum WHERE.

WHERE cms\_pages.id

Wir wollen nur Seiten,

IN(
    SELECT
        cms\_content.page\_id
    FROM cms\_content
    JOIN cms\_rights
    ON cms\_content.id = cms\_rights.content\_id
    WHERE
    cms\_rights.group\_id
    IN(
        SELECT cms\_user\_groups.group\_id
        FROM cms\_user\_groups
        WHERE cms\_user\_groups.user\_id = ?
    )

für deren Content der Nutzer über die Gruppenzugehörigkeit die Berechtigung hat (Ich habs mal umsortiert.)

AND
    cms\_content.page\_id
    IN(
        SELECT cms\_pages.id
        FROM cms\_menu\_pages
        JOIN cms\_pages
        ON cms\_menu\_pages.page\_id = cms\_pages.id
        WHERE cms\_menu\_pages.menu\_id = ?

(Einmal pages unnötigerweise gejoint. Die pages.id ist bereits als menu_pages.page_id verfügbar.)

und die zur übergebenen Menü-ID passen. Aber die Bedeutung dieser Bedingung erschließt sich mir nicht. Warum wird hier die Menu-ID als Parameter übergeben?

)
)

Und liege ich richtig, wenn ich vermute, dass ich die Beispiele von deinem Link einfach nur in das erste, äusserste SELECT schieben muss? Dann wäre es wohl doch einfacher als gedacht.

Das kann ich jetzt noch nicht sagen. Nur soviel: Nested-Sets-Abfragen verwenden oftmals Self-Joins und Gruppierung, so auch die Level-Query. Das mit der jetzigen gejointen und bereits gruppierten Query zu verheiraten wird eine ganz schöne Herausforderung werden.

Was meinst du, ist es sinnvoller mit der Datenbank-Abfrage oder mit dem Array zu spielen?

Bei der Komplexität der Query wird es wohl auf eine Array-Lösung hinauslaufen. Andererseits kann man die Komplexität mit noch mehr Komplexität augenscheinlich verringern. Die ungetestete Idee wäre, die Query in eine View zu bringen, dann wird die Anwendung des Self-Joins und der Gruppierung einfacher, als wenn man das Riesending doppelt notieren muss.

dedlfix.