Рекурсивное построение массива на php
Есть таблица dep с полями id, dep (название), parent (id записи родителя). Задача: отправить id в sql запрос, и в ответ принять многоуровневый ассоциативный массив по иерархии подчиненности в формате:
[
{
id: 1,
parent: 'null',
dep: 'Организация 1',
children: [
{
id: 2,
parent: '1',
dep: 'Организация 2',
children: [
{
id: 3,
parent: '2',
dep: 'Организация 3',
children : array('')
}
]
}
]
}
]
$response = array();
$query = $dbh->prepare("select id, dep, parent from dep");
$query->execute();
while ($row = $query->fetch(PDO::FETCH_ASSOC)) {$response[] = $row;} //Заполняем массив response значениями из таблицы
function createTree($arr){
$parents_arr = array();
foreach($arr as $key=>$item){
$parents_arr[$item['parent']][$item['id']] = $item;
}
$treeElem = $parents_arr[null]; //Здесь мы объявляем абсолютными родителями элементы массива с parent=null
generateElemTree($treeElem,$parents_arr);
return $treeElem;
}
function generateElemTree(&$treeElem, $parents_arr){
foreach ($treeElem as $key=>$item){
if(!isset($item['children'])){
$treeElem[$key]['children'] = array();
}
if(array_key_exists($key, $parents_arr)){
$treeElem[$key]['children']=$parents_arr[$key];
generateElemTree($treeElem[$key]['children'], $parents_arr);
}
}
}
$cats=createTree($response);
echo json_encode($cats, JSON_UNESCAPED_UNICODE);
Сейчас я могу построить иерархию вложенности с помощью рекурсии только для записей, в которых parent=null. Как мне сделать то же самое, но для записей, в которых parent не равен нулю? Например, отправив в sql запрос id=2, получить массив, начинающийся с id=2 и включающий все подчиненнные записи? (Т.е. построить ветку начиная с заднного id). Заранее спасибо!
dep, CREATE TABLE `dep` (
`id` int NOT NULL,
`dep` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`parent` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3
INSERT INTO `dep` (`id`,`dep`,`parent`) VALUES (1,'org1',NULL);
INSERT INTO `dep` (`id`,`dep`,`parent`) VALUES (2,'org1.1',1);
INSERT INTO `dep` (`id`,`dep`,`parent`) VALUES (3,'org1.1.1 ',2);
INSERT INTO `dep` (`id`,`dep`,`parent`) VALUES (4,'org1.1.1.1',3);
INSERT INTO `dep` (`id`,`dep`,`parent`) VALUES (5,'org1.1.1.1.1',4);
INSERT INTO `dep` (`id`,`dep`,`parent`) VALUES (6,'org1.1.1.1.1.1',5);
INSERT INTO `dep` (`id`,`dep`,`parent`) VALUES (7,'org1.1.1.1.1.2',5);
//Для id =1
{
"1": {
"id": "1",
"dep": "org1",
"parent": null,
"depth": "0",
"children": {
"2": {
"id": "2",
"dep": "org1.1",
"parent": "1",
"depth": "1",
"children": {
"3": {
"id": "3",
"dep": "org1.1.1 ",
"parent": "2",
"depth": "2",
"children": {
"4": {
"id": "4",
"dep": "org1.1.1.1",
"parent": "3",
"depth": "3",
"children": {
"5": {
"id": "5",
"dep": "org1.1.1.1.1",
"parent": "4",
"depth": "4",
"children": {
"6": {
"id": "6",
"dep": "org1.1.1.1.1.1",
"parent": "5",
"depth": "5",
"children": []
},
"7": {
"id": "7",
"dep": "org1.1.1.1.1.2",
"parent": "5",
"depth": "5",
"children": []
}
}
}
}
}
}
}
}
}
}
}
}
//Для id =4
{
"4": {
"id": "4",
"dep": "org1.1.1.1",
"parent": "3",
"depth": "0",
"children": {
"5": {
"id": "5",
"dep": "org1.1.1.1",
"parent": "4",
"depth": "1",
"children": {
"6": {
"id": "6",
"dep": "org1.1.1.1",
"parent": "5",
"depth": "2",
"children": []
},
"7": {
"id": "7",
"dep": "org1.1.1.1",
"parent": "5",
"depth": "2",
"children": []
}
}
}
}
}
}
Ответы (1 шт):
Автор решения: Akina
→ Ссылка
WITH RECURSIVE
cte1 AS ( SELECT *, 0 level
FROM dep
WHERE id = 1
UNION ALL
SELECT dep.*, cte1.level + 1
FROM cte1
JOIN dep ON cte1.id = dep.parent ),
cte2 AS ( SELECT JSON_OBJECTAGG( id,
JSON_OBJECT( 'id', id,
'dep', dep,
'depth', level,
'parent', parent,
'children', '[]' )) obj,
MAX(parent) parent,
level,
MAX(id) id
FROM cte1
GROUP BY level ),
cte3 AS ( ( SELECT id, level, obj, parent
FROM cte2
ORDER BY level DESC LIMIT 1 )
UNION ALL
SELECT cte2.id,
cte2.level,
JSON_MERGE_PATCH(cte2.obj,
JSON_OBJECT(cte2.id,
JSON_OBJECT('children', cte3.obj))),
cte2.parent
FROM cte3
JOIN cte2 ON cte3.parent = cte2.id )
SELECT CAST(obj AS CHAR)
FROM cte3
WHERE level = 0;