İç içe Setleri kullanarak dinamik menü oluşturmak

4 Cevap php

Ben PHP CMS dinamik bir menü oluşturmaya çalışıyorum; sayfalar / kategorileri iç içe setleri modeli kullanılarak düzenlenmektedir.

Tam ağaç:

root
 A
 B
  B1
   B1.1
   B1.2
  B2
   B2.1
   B2.1
 C
  C1
  C2
  C3
 D

I want to convert this result set to an unordererd list, which only displays a part of the tree. For example: If I click on B, I want to show only the following part of the list:

A
B
 B1
 B2
C
D

Ben B1 tıklarsanız Sonra, ben bu listeyi göstermek istiyorum:

A
B
 B1
  B1.1
  B1.2
 B2
C
D

vb

Ben (mysql) veritabanındaki tüm düğümleri almak için aşağıdaki SQL sorgu kullanın:

SELECT node.id, node.lft, node.rgt, node.name, 
GROUP_CONCAT(parent.name ORDER BY parent.lft  SEPARATOR "/" ) AS path, 
(COUNT(parent.lft) - 1) AS depth 
FROM pages AS node, pages AS parent 
WHERE node.lft BETWEEN parent.lft AND parent.rgt 
AND ( parent.hidden = "no" AND node.hidden = "no")  AND parent.lft > 1 
GROUP BY node.id ORDER BY node.lft

I managed to create the full list without recursion (using the depth column), but I can't filter the menu like I have shown above; I think I need to get the parent's lft and rgt value for each node and filter out the elements using PHP. But how can I get these values in the same query?

Bu nasıl ulaşılacağı konusunda herhangi bir öneriniz var mı?

Şimdiden teşekkürler!

4 Cevap

Sadece istenmeyen öğeleri gizlemek için proje kapsamında uygun olur? örneğin (css):

  • . Menüsü li> ul {display: none;}
  • . Menüsü li.clicked> ul {display: block;}

Sonra tıklandığı herhangi

  • elemanı "tıklanan" sınıfı eklemek için javascript kullanın. Bu CSS IE6 çalışmaz unutmayın.

  • Aşağıdaki sorgu SQL'ın sahip fıkra yararlanarak ve MySQL'in group_concat işlevi tarafından herhangi bir yol (veya yollar setleri) açmak için izin verecektir.

    Aşağıdaki Ben kullanılan tablo tanımı ve örnek veriler:

    drop table nested_set;
    
    CREATE TABLE nested_set (
     id INT,
     name VARCHAR(20) NOT NULL,
     lft INT NOT NULL,
     rgt INT NOT NULL
    );
    
    INSERT INTO nested_set (id, name, lft, rgt) VALUES (1,'HEAD',1,28);
    INSERT INTO nested_set (id, name, lft, rgt) VALUES (2,'A',2,3);
    INSERT INTO nested_set (id, name, lft, rgt) VALUES (3,'B',4,17);
    INSERT INTO nested_set (id, name, lft, rgt) VALUES (4,'B1',5,10);
    INSERT INTO nested_set (id, name, lft, rgt) VALUES (5,'B1.1',6,7);
    INSERT INTO nested_set (id, name, lft, rgt) VALUES (6,'B1.2',8,9);
    INSERT INTO nested_set (id, name, lft, rgt) VALUES (7,'B2',11,16);
    INSERT INTO nested_set (id, name, lft, rgt) VALUES (8,'B2.1',12,13);
    INSERT INTO nested_set (id, name, lft, rgt) VALUES (9,'B2.2',14,15);
    INSERT INTO nested_set (id, name, lft, rgt) VALUES (10,'C',18,25);
    INSERT INTO nested_set (id, name, lft, rgt) VALUES (11,'C1',19,20);
    INSERT INTO nested_set (id, name, lft, rgt) VALUES (12,'C2',21,22);
    INSERT INTO nested_set (id, name, lft, rgt) VALUES (13,'C3',23,24);
    INSERT INTO nested_set (id, name, lft, rgt) VALUES (14,'D',26,27);
    

    Aşağıdaki sorgu size (KAFA hariç) tüm ağaç verir:

    SELECT
      node.id
    , node.lft
    , node.rgt
    , node.name
    ,  GROUP_CONCAT(parent.name ORDER BY parent.lft  SEPARATOR "/" ) AS path
    ,  (COUNT(parent.lft) - 1) AS depth
    FROM nested_set AS node
    inner join nested_set AS parent
    on node.lft BETWEEN parent.lft AND parent.rgt
    where parent.lft > 1
    GROUP BY node.id
    

    Örnek veri karşı çalıştırdığınızda, aşağıdaki bir çıkış ile:

    +------+-----+-----+------+-----------+-------+
    | id   | lft | rgt | name | path      | depth |
    +------+-----+-----+------+-----------+-------+
    |    2 |   2 |   3 | A    | A         |     0 |
    |    3 |   4 |  17 | B    | B         |     0 |
    |    4 |   5 |  10 | B1   | B/B1      |     1 |
    |    5 |   6 |   7 | B1.1 | B/B1/B1.1 |     2 |
    |    6 |   8 |   9 | B1.2 | B/B1/B1.2 |     2 |
    |    7 |  11 |  16 | B2   | B/B2      |     1 |
    |    8 |  12 |  13 | B2.1 | B/B2/B2.1 |     2 |
    |    9 |  14 |  15 | B2.2 | B/B2/B2.2 |     2 |
    |   10 |  18 |  25 | C    | C         |     0 |
    |   11 |  19 |  20 | C1   | C/C1      |     1 |
    |   12 |  21 |  22 | C2   | C/C2      |     1 |
    |   13 |  23 |  24 | C3   | C/C3      |     1 |
    |   14 |  26 |  27 | D    | D         |     0 |
    +------+-----+-----+------+-----------+-------+
    

    Yukarıdaki sorgu için aşağıdaki eklemeler size çeşitli bölümleri açmak için gereken kontrol verecektir:

    having
    depth = 0
    or ('<PATH_TO_OPEN>' =  left(path, length('<PATH_TO_OPEN>'))
       and depth = length('<PATH_TO_OPEN>') - length(replace('<PATH_TO_OPEN>', '/', '')) + 1)
    

    Olan fıkra sorgunun grubun sonuçlarına filtreleri geçerlidir. "Derinliği = 0" parçası, biz her zaman baz menü düğümleri (A, B, C, ve D) dışarı sağlamaktır. Bir sonraki bölümde düğümler açık olduğu kontrol eden bir parçasıdır. O bunu maçlar ve aynı zamanda sadece yoluna seviyesi açılır emin yaparsa görmek için ('') açmak istediğiniz bir dizi yolu ile düğümlerin yolunu karşılaştırır. '' Mantığı ile tamamı veya bölüm çoğaltılmış ve gerektiğinde birden çok yol açmak için gerekli olarak ilave edilebilir. '' Bölü çizgisi (/) bitmiyor emin olun.

    Aşağıdaki istediğini çıktılarını almak için sorguları oluşturmak nasıl göstermek için bazı çıktı örnekler:

    =========Open B==========
    
    SELECT
      node.id
    , node.lft
    , node.rgt
    , node.name
    ,  GROUP_CONCAT(parent.name ORDER BY parent.lft  SEPARATOR "/" ) AS path
    ,  (COUNT(parent.lft) - 1) AS depth
    FROM nested_set AS node
    inner join nested_set AS parent
    on node.lft BETWEEN parent.lft AND parent.rgt
    where parent.lft > 1
    GROUP BY node.id
    having
    depth = 0
    or ('B' =  left(path, length('B'))
       and depth = length('B') - length(replace('B', '/', '')) + 1)
    
    +------+-----+-----+------+------+-------+
    | id   | lft | rgt | name | path | depth |
    +------+-----+-----+------+------+-------+
    |    2 |   2 |   3 | A    | A    |     0 |
    |    3 |   4 |  17 | B    | B    |     0 |
    |    4 |   5 |  10 | B1   | B/B1 |     1 |
    |    7 |  11 |  16 | B2   | B/B2 |     1 |
    |   10 |  18 |  25 | C    | C    |     0 |
    |   14 |  26 |  27 | D    | D    |     0 |
    +------+-----+-----+------+------+-------+
    
    =========Open B and B/B1==========
    
    SELECT
      node.id
    , node.lft
    , node.rgt
    , node.name
    ,  GROUP_CONCAT(parent.name ORDER BY parent.lft  SEPARATOR "/" ) AS path
    ,  (COUNT(parent.lft) - 1) AS depth
    FROM nested_set AS node
    inner join nested_set AS parent
    on node.lft BETWEEN parent.lft AND parent.rgt
    where parent.lft > 1
    GROUP BY node.id
    having
    depth = 0
    or ('B' =  left(path, length('B'))
       and depth = length('B') - length(replace('B', '/', '')) + 1)
    or ('B/B1' =  left(path, length('B/B1'))
       and depth = length('B/B1') - length(replace('B/B1', '/', '')) + 1)
    
    +------+-----+-----+------+-----------+-------+
    | id   | lft | rgt | name | path      | depth |
    +------+-----+-----+------+-----------+-------+
    |    2 |   2 |   3 | A    | A         |     0 |
    |    3 |   4 |  17 | B    | B         |     0 |
    |    4 |   5 |  10 | B1   | B/B1      |     1 |
    |    5 |   6 |   7 | B1.1 | B/B1/B1.1 |     2 |
    |    6 |   8 |   9 | B1.2 | B/B1/B1.2 |     2 |
    |    7 |  11 |  16 | B2   | B/B2      |     1 |
    |   10 |  18 |  25 | C    | C         |     0 |
    |   14 |  26 |  27 | D    | D         |     0 |
    +------+-----+-----+------+-----------+-------+
    
    =========Open B and B/B1 and C==========
    
    SELECT
      node.id
    , node.lft
    , node.rgt
    , node.name
    ,  GROUP_CONCAT(parent.name ORDER BY parent.lft  SEPARATOR "/" ) AS path
    ,  (COUNT(parent.lft) - 1) AS depth
    FROM nested_set AS node
    inner join nested_set AS parent
    on node.lft BETWEEN parent.lft AND parent.rgt
    where parent.lft > 1
    GROUP BY node.id
    having
    depth = 0
    or ('B' =  left(path, length('B'))
       and depth = length('B') - length(replace('B', '/', '')) + 1)
    or ('B/B1' =  left(path, length('B/B1'))
       and depth = length('B/B1') - length(replace('B/B1', '/', '')) + 1)
    or ('C' =  left(path, length('C'))
       and depth = length('C') - length(replace('C', '/', '')) + 1)
    
    +------+-----+-----+------+-----------+-------+
    | id   | lft | rgt | name | path      | depth |
    +------+-----+-----+------+-----------+-------+
    |    2 |   2 |   3 | A    | A         |     0 |
    |    3 |   4 |  17 | B    | B         |     0 |
    |    4 |   5 |  10 | B1   | B/B1      |     1 |
    |    5 |   6 |   7 | B1.1 | B/B1/B1.1 |     2 |
    |    6 |   8 |   9 | B1.2 | B/B1/B1.2 |     2 |
    |    7 |  11 |  16 | B2   | B/B2      |     1 |
    |   10 |  18 |  25 | C    | C         |     0 |
    |   11 |  19 |  20 | C1   | C/C1      |     1 |
    |   12 |  21 |  22 | C2   | C/C2      |     1 |
    |   13 |  23 |  24 | C3   | C/C3      |     1 |
    |   14 |  26 |  27 | D    | D         |     0 |
    +------+-----+-----+------+-----------+-------+
    

    İşte bu kadar. sadece bu veya açmak için gereken her yolu için bölüm çoğaltarak devam.

    http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/ durumda MySQL iç içe setleri ile çalışma hakkında genel bilgi gerekir bakın.

    Herhangi bir sorunuz varsa bana bildirin.

    HTH,

    -Dipin

    Bir arkadaş yazdı toprağa bir setin inşa etmek için nasıl bir iyi bir post burada; Nested Set in MySQL

    Belki size yardımcı olur.

    Bu eski bir soru olabilir farkındayım, ama ben aynı sorunu tökezledi, ben diğerleri de yarar böylece bazı girdi vermeye karar verdi.

    -Dipins cevabı ben benim ilerleme dayalı bir, bir şimdi ben bütün 'OR'' nin olmadan bir çözüm olduğunu düşünüyorum oldu.

    Ile sadece bir kısmına sahip değiştirin:

    HAVING
      depth = 1
      OR
      '".$path."' LIKE CONCAT(SUBSTRING(path, 1, (LENGTH(path) - LENGTH(menu_node_name) -1)), '%')
    
    $path = requested path. parent node's path that the user clicked, "A/B" for example
    
    path = the path of the current node including the nodes name "A/B/B1" for example, which is a child for the node the user clicked.
    
    menu-node-name = the name of the node in progress, "B1" for example.
    

    What it does, is compares the requested path, lets say A/B/B1 With the path of the node. The path of the node needed some work tough. LIKE path-of-node % did work, but it only gave the upper level and did not give any other nodes on the same level. This version does.

    BİZ şey ondan sonra gelebilir yani bir joker (%) ile path_of_node bağlamak. Substring REMOVES düğümler path_of_node aslında bunun yol parent's düğüm yapma, isim ve çizgi kendi. Yani A/B/B1 yeni bir alt ağacı açmak için linke tıklayın eğer isteğimiz maçları "A / B%" olur.

    I = 1 derinliği nedeni i aynı ağaçta birden menüler olabilir ki, ve ben insanlar "MENÜ-FOR-ZENGİN-PEOPLE", "MENÜ-FOR-FAKİR-PEOPLE", ya da ne olursa olsun gibi bir şey görmek istemiyorum isimleri her durumda bulunmaktadır. Benim setin üst düzey düğümlerin kindof düğümleri tutarak, ben gerçek sonucu dışlıyor.

    Ben bu en azından ben bir kaç saat için bir çözüm aradık ve sonra onunla geldi, birisi için yararlı olmaktadır umuyoruz.

    Bence, bu www.race.fi bakarak çalışmış olduğunu teyit edebilirsiniz birkaç gün ia

    EDIT / NOT:

    Biraz daha test ve sipariş hatalı olduğu görünüyor. Burada doğru sipariş ile benim sorgu hızlı bir CopyPaste olduğunu. Orada yerel, içeriği gibi bazı gereksiz şeyler olduğunu, ve content_localised ama önemli noktaları açık olmalıdır.

    SELECT
        REPEAT('-',(COUNT(MENU.par_name) - 2)) as indt,
        GROUP_CONCAT(MENU.par_name ORDER BY MENU.par_lft  SEPARATOR '/' ) AS path,
        (COUNT(MENU.par_lft) - 1) AS depth,
        MENU.*,
        MENU.content
    FROM 
        (SELECT 
            parent.menu_node_name AS par_name,
            parent.lft AS par_lft,
            node.menu_node_id,
            node.menu_node_name,
            node.content_id,
            node.node_types,
            node.node_iprop,
            node.node_aprop,
            node.node_brands,
            node.rgt,
            node.lft,
            [TPF]content_localised.content
    
        FROM [TPF]" . $this->nestedset_table . " AS node 
        JOIN [TPF]" . $this->nestedset_table . " AS parent
                ON node.lft BETWEEN parent.lft AND parent.rgt
        JOIN [TPF]content
            ON node.content_id = [TPF]content.content_id
        JOIN [TPF]content_localised
            ON [TPF]content.content_id = [TPF]content_localised.content_id  
        JOIN [TPF]locales 
            ON [TPF]content_localised.locale_id = [TPF]locales.locale_id
    
        ORDER BY node.rgt, FIELD(locale, '" . implode("' , '", $locales) . "', locale) ASC
        ) AS MENU
    
    GROUP BY MENU.menu_node_id
    HAVING depth = 1
        OR '".$path."' LIKE CONCAT(SUBSTRING(path, 1, (LENGTH(path) - LENGTH(MENU.menu_node_name) -1)), '%')
        AND depth > 0
    ORDER BY MENU.lft";