У меня есть таблица MySQL с древовидной структурой данных. Поля: _id
, name
и parentId
. Если в записи нет родителя, parentId
умолчанию parentId
0. Таким образом, я могу построить массив, а затем рекурсивно распечатать каждую запись.
Встроенный массив выглядит следующим образом:
Array ( [1] => Array ( [parentId] => 0 [name] => Countries [_id] => 1 [children] => Array ( [2] => Array ( [parentId] => 1 [name] => America [_id] => 2 [children] => Array ( [3] => Array ( [parentId] => 2 [name] => Canada [_id] => 3 [children] => Array ( [4] => Array ( [parentId] => 3 [name] => Ottawa [_id] => 4 ) ) ) ) ) [5] => Array ( [parentId] => 1 [name] => Asia [_id] => 5 ) [6] => Array ( [parentId] => 1 [name] => Europe [_id] => 6 [children] => Array ( [7] => Array ( [parentId] => 6 [name] => Italy [_id] => 7 ) [11] => Array ( [parentId] => 6 [name] => Germany [_id] => 11 ) [12] => Array ( [parentId] => 6 [name] => France [_id] => 12 ) ) ) [8] => Array ( [parentId] => 1 [name] => Oceania [_id] => 8 ) ) ) )
Печать неупорядоченного списка <ul>
очень проста с рекурсией. Вот функция, которую я использую:
function toUL ($arr) { $html = '<ul>' . PHP_EOL; foreach ( $arr as $v ) { $html.= '<li>' . $v['name'] . '</li>' . PHP_EOL; if ( array_key_exists('children', $v) ) { $html.= toUL($v['children']); } } $html.= '</ul>' . PHP_EOL; return $html; }
Но я застрял в печати <select>
по древовидной структуре:
Countries -- America ---- Canada ------ Ottawa -- Asia -- Europe ---- Italy ---- Germany ---- France -- Oceania
Я думал, что печатать --
столько раз, сколько глубина элемента, но я не знаю, как рассчитать глубину.
Мой вопрос: возможно ли построить <select>
не зная глубины?
Заранее спасибо.
Передайте параметр для подсчета итерации как $pass
function toUL ($arr, $pass = 0) { $html = '<ul>' . PHP_EOL; foreach ( $arr as $v ) { $html.= '<li>'; $html .= str_repeat("--", $pass); // use the $pass value to create the -- $html .= $v['name'] . '</li>' . PHP_EOL; if ( array_key_exists('children', $v) ) { $html.= toUL($v['children'], $pass+1); } } $html.= '</ul>' . PHP_EOL; return $html; }
Ваша проблема уже решена в SPL. Документы RecursiveIteratorIterator
содержат информацию о глубине элемента:
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($array), SELF_FIRST); foreach ($it as $key => $element) { if ($key !== 'name') continue; $inset = str_repeat('--', $it->getDepth()); printf('<option>%s %s</option>', $inset, $element); }
function toSelect($arr, $depth = 0) { $html = ''; foreach ( $arr as $v ) { $html.= '<option>' . str_repeat("--", $depth) . $v['name'] . '</option>' . PHP_EOL; if ( array_key_exists('children', $v) ) { $html.= toSelect($v['children'], $depth++); } } return $html; }
Мое окончательное решение (спасибо Starx и varan):
function toSelect ($arr, $depth=0) { $html = ''; foreach ( $arr as $v ) { $html.= '<option value="' . $v['_id'] . '">'; $html.= str_repeat('--', $depth); $html.= $v['name'] . '</option>' . PHP_EOL; if ( array_key_exists('children', $v) ) { $html.= toSelect($v['children'], $depth+1); } } return $html; } echo '<select>'; echo toSelect($array); echo '</select>';
Даже решение RecursiveIteratorIterator
является хорошим (спасибо hakre).
Привет, ребята, вы могли бы сделать что-то вроде этого: у меня есть этот объект для $tree
:
Array ( [0] => stdClass Object ( [id] => 1 [nombre] => Category 1 [subcategorias] => Array ( [0] => stdClass Object ( [id] => 4 [nombre] => Category 1.1 ) ) ) [1] => stdClass Object ( [id] => 2 [nombre] => Category 2 ) [2] => stdClass Object ( [id] => 3 [nombre] => Category 3 [subcategorias] => Array ( [0] => stdClass Object ( [id] => 5 [nombre] => Category 3.1 [subcategorias] => Array ( [0] => stdClass Object ( [id] => 6 [nombre] => Category 3.1.1 ) ) ) ) ) )
Затем Вот как создать массив для выбора HTML:
$tree=array();// PUT HERE YOUR TREE ARRAY $arrayiter = new RecursiveArrayIterator($tree); $iteriter = new RecursiveIteratorIterator($arrayiter); $lista=array(); $i=0; foreach ($iteriter as $key => $value) { $id=$iteriter->current(); $iteriter->next(); $nivel=$iteriter->getDepth(); $nombre=str_repeat('-',$nivel-1).$iteriter->current(); $lista[$id]=$nombre; }
Вы получите что-то вроде этого:
Array ( [1] => Category 1 [4] => --Category 1.1 [2] => Category 2 [3] => Category 3 [5] => --Category 3.1 [6] => ----Category 3.1.1 )
Затем вам просто нужно создать параметры для выбора с помощью простого foreach.
Вы можете передать длину функции и прирастить ее при вызове рекурсивно, а затем использовать переменную $length
для определения глубины
function toUL ($arr, $length = 0) { $html = '<ul>' . PHP_EOL; foreach ( $arr as $v ) { $html.= '<li>' . $v['name'] . '</li>' . PHP_EOL; if ( array_key_exists('children', $v) ) { $html.= toUL($v['children'], $length++); } } $html.= '</ul>' . PHP_EOL; return $html; }
Это то, что я обычно делаю для отслеживания глубины рекурсии, и обычно это делается
function toUL ($arr, $depth = 0) { // ... $html .= toUL($v['children'], $depth+1);
вы можете использовать optgroup как итератор. Например:
<select name="list"> <option value=1>1st option</option> <optgroup> <option value=10>1st on 1st group</option> </optgroup> </select>
если вы хотите php, вы можете попробовать следующее:
<?PHP function toSELECT($arr,$depth=0) { $html=""; if(is_array($arr)) { $html.=($depth==0)?"<select name='html'>\n":""; foreach ($arr as $key=>$value) { if(is_array($arr[$key])) { $html.=str_repeat("\t",$depth)."<optgroup>\n"; $html.=str_repeat("\t",$depth).toHTML($arr[$key],$depth+1); $html.=str_repeat("\t",$depth)."</optgroup>\n"; } else { $html.=str_repeat("\t",$depth)."<option value='".$value."'>".$key."</option>\n"; } } $html.=($depth==0)?"</select>\n":""; } return $html; } ?>