SQL-запросы и PHP-манипуляции с моделью вложенных множеств - PullRequest
1 голос
/ 08 февраля 2012

Я читал эту статью, http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/.

Я хотел привести простой пример, а затем спросить вас, как мне получить желаемый результат?Итак, вот пример:

+---------+-----------------------------+
|  product_id | product_name            |
+---------+-----------------------------+
|           1 | Example Product         |
+---------+-----------------------------+
+---------+-----------------------------+
|  product_id | category_id             | 
+---------+-----------------------------+
|           1 | 2                       |
|           1 | 4                       |
+---------+-----------------------------+
+-------------+--------------------+------+------+
| category_id | name                 | lft | rgt |
+-------------+--------------------+------+------+
|           1 | Electronics          |  1  |  8  |
|           2 | Televisions          |  2  |  3  |
|           3 | Portable Electronics |  4  |  7  | 
|           4 | CD Players           |  5  |  6  |
+-------------+--------------------+------+------+

Я хочу иметь возможность отображать следующий результат в HTML после запроса и затем манипулирования данными в PHP:

"Example Product" Categories:
Electronics
    Televisions 
    Portable Electronics
        CD Players

Можете ли вы помочь ходитьмне через запрос и манипуляции в PHP для достижения этого результата?

Некоторые особенности, о которых нужно подумать:

  1. Обратите внимание, как обе категории относятся к электронике, но «Электроника» появляется только один раз здесь, отображая каждую из подкатегорий, к которым она принадлежит, ниже
  2. Результатом должен стать многомерный массив PHP с категорией, содержащей массив подкатегорий, и каждая подкатегория, содержащая массив подкатегорий, еслиони существуют.

Я предполагаю, что печать глубины будет очень важна для построения правильного дерева в HTML.

1 Ответ

3 голосов
/ 08 февраля 2012

Я подумал, что это хороший вызов ... вот мое решение:

По сути: прочитайте узел, затем все последующие узлы с rgt меньше, чем rgt, являются вашими детьми, делайте это рекурсивно,Я использовал peek / consume для чтения из mysql, как вы это обычно делаете.

Сценарий будет прерываться или зацикливаться, если запрос не даст результатов, или если набор данных будет сломан .

class NestedNodeReader {

    private $mysql_result;
    private $peeked = false;
    private $last_peek;

    public function __construct($mysql_result) {
        $this->mysql_result = $mysql_result;
    }

    public function getTree() {
        $root = $this->consume();
        $root["children"] = $this->getSubTree($root["rgt"]);
        return $root;
    }

    private function getSubTree($stop_at) {
        $nodes = array();
        $node = $this->peek();
        while ($node["rgt"] < $stop_at) {
            $node = $this->consume();
            $node["children"] = $this->getSubTree($node["rgt"]);
            $nodes[] = $node;
            $node = $this->peek();
            if (false === $node) {
                break;
            }
        }
        return $nodes;
    }

    private function peek() {
        if (false === $this->peeked) {
            $this->peeked = true;
            $this->last_peek = mysql_fetch_assoc($this->mysql_result);
        }
        return $this->last_peek;
    }

    private function consume() {
        if (false === $this->peeked) {
            return mysql_fetch_assoc($this->mysql_result);
        } else {
            $this->peeked = false;
            return $this->last_peek;
        }
    }
}

$query = "SELECT node.name, node.lft, node.rgt
    FROM nested_category AS node,
        nested_category AS parent
    WHERE node.lft BETWEEN parent.lft AND parent.rgt
        AND parent.name = 'ELECTRONICS'
    ORDER BY node.lft;"
$mysql_result = mysql_query($query);
$nnr = new NestedNodeReader($mysql_result);
print_r($nnr->getTree());
...