2009-05-08 2 views
2

У меня есть таблица в базе данных, которая имеет категории данных:PHP SPL манипулировать рекурсивного меню

 
id title  parent 
1 category 1 0 
2 category 2 2 
3 category 3 3 
4 category 4 0 

Eeach родитель может иметь родительский идентификатор строки.

Например, категория 3 ребенок категории 2, который является дочерним по категории 1.

 
category 1 
    category 2 
     category 3 

category 4 

1 - Есть ли лучший способ управлять этой техникой? 2 - Моей реализацией является выборка всех строк в одном SQL-запросе, а затем использование рекурсивной функции для построения многомерного массива, затем я прохожу через нее с использованием многоуровневого foreach для создания меню или чего-то еще. Мне нужен лучший способ использования PHP SPL.

Я хочу, чтобы создать либо полное меню или путь элемента, как:

 
category1 -> catgory 2 -> etc. 

и создать сетку, которая удерживает уровень категории в каждой строке.

ответ

1

Недавно я купил нечто подобное, используя один запрос и один цикл while. Он использует ссылки для построения древовидных структур данных (массива) с помощью плоского (массива). Это не связано с SPL, потому что я не чувствую, что это необходимо. Там в a gist on GitHub с лучшей цветовой гаммой :)

/** 
* Each element in the return array has a 'data' key, holding category data, 
* like name, and a 'children' key holding its subcategories. 
* 
* @param resource $resource MySQL resource resulted from mysql_query 
* @param string $id_key Name of the 'id' field 
* @param string $parent_id_key Name of the 'parent_id' field 
* @param boolean $use_cache Use cached result from previous calls. Defaults to TRUE 
* @return array 
*/ 
function categories($resource, $id_key, $parent_id_key, $use_cache = true) { 
    // Cache the categories in a static local variable. This way, the query 
    // will be executed just for the first function call. Subsequent calls 
    // will return imediatelly, unless you tell it not to. 
    static $tree = array(); 

    if ($tree && $use_cache) { 
     return $tree; 
    } 

    // Flat representation of the categories for fast retrieval using array 
    // keys. Each element will be referenced in the $tree array. This 
    // allows to build a tree data structure using a flat one. 
    $flat = array(); 

    // Reset the $tree, in case $use_cache=false in a subsequent call 
    $tree = array(); 

    while ($row = mysql_fetch_object($resource)) { 
     $flat[$row->$id_key] = array(
      'data' => $row, 
      'children' => array(), 
     ); 

     if (array_key_exists($row->$parent_id_key, $flat)) { 
      // Assign children by reference so that possible subcategories of 
      // this one will appear in the tree structure ($tree) 
      $flat[$row->$parent_id_key]['children'][] =& $flat[$row->$id_key]; 
     } 

     if ($row->$parent_id_key == 0) { 
      // Assign by reference for synchronizing $flat with $tree; 
      $tree[] =& $flat[$row->$id_key]; 
     } 
    } 

    return $tree; 
} 

Кроме того, функция отделена от структуры базы данных. Вам нужно передать ему ресурс mysql_query, строку, представляющую поле id, и строку, представляющую поле parent_id. Плохая часть состоит в том, что она связана с расширением mysql PHP, потому что он использует вызов для mysql_fetch_object. Вероятно, это может быть улучшено.

Другим преимуществом является то, что он кэширует результат для последовательных вызовов, если вы не укажете ему, чтобы он сделал недействительным кеш, который является четвертым (логическим) параметром.

Посмотрите, не поможет ли вам это.

+0

«... функция полностью отделена от базы данных. Вам необходимо передать ей ресурс mysql_query ...», противоречивые утверждения. –

+0

@ LeviMorrison спасибо. Я имел в виду структуру базы данных, т. Е. Не делает предположений о имени полей. Возможно, он, возможно, еще более обобщен, чтобы работать с другими поставщиками БД. Во всяком случае, теперь я немного старше, и я, вероятно, больше не буду использовать эту функцию :) –

3

Если ваши данные строго иерархичны, и похоже, что это так, я бы рекомендовал метод измененного дерева меток предварительного упорядочения для хранения ваших данных.

Существует superb article at Sitepoint, который обсуждает эту проблему. Кажется, вы используете модель списка адресов, которая обсуждается на первой странице, но MPTT намного эффективнее для хранения данных этого типа с высокой степенью защиты.

Отъезд page 2, чтобы ознакомиться с примерами. Это действительно замечательная часть архитектуры.

+0

Я полагаю, что причины, по которым модель отклонения списка не рекомендуется, были смягчены моим решением. В моей функции есть только один запрос и нет рекурсии, просто итерация. –

+0

Если ваше дерево мало, я думаю, ваше решение в порядке. Однако, если вы представляете дерево с 1000 или даже миллионами узлов, вы не захотите читать всю таблицу в памяти.Преимущество MPTT состоит в том, что любой сегмент дерева можно изолировать в одном запросе, будь то все дерево или путь к одному узлу, и вам нужно только прочитать записи, которые являются частью пути, и ничего больше. Определенно, немного больше работы по реализации. – zombat

Смежные вопросы