SQL-запросы и PHP-манипуляции с моделью вложенных множеств
Я читал эту статью, 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 для достижения этого результата?
Некоторые особенности, чтобы думать о:
- Обратите внимание, что обе категории относятся к электронике, но "Электроника" появляется здесь только один раз, отображая каждую из подкатегорий, к которым она относится.
- Результатом должен стать многомерный массив PHP с категорией, содержащей массив подкатегорий, и каждой подкатегорией, содержащей массив подкатегорий, если они существуют.
Я предполагаю, что печать глубины будет очень важна для построения правильного дерева в HTML.
1 ответ
Я думал, что это был хороший вызов.. вот мое решение:
В основном: читать узел, затем все последующие узлы с 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());