Как зациклить петлевые элементы в Php? - PullRequest
0 голосов
/ 04 августа 2009

Я создаю древовидную структуру категорий с парентидами, которую дети могут вызывать так:

ID | Name | ParentID
1    1      0
2    2      1
3    3      2
4    4      1

В результате чего:

1 = 1
2 = 1 -> 2
3 = 1 -> 2 -> 3
4 = 1 -> 4

, что означает 3 - это ребенок 2 , который является ребенком 1.

при попытке получить эту идею (с помощью ->, чтобы показать, какие отношения установлены), я получаю только второй класс (1 -> 2), но не третий (1-> 2-> 3) из-за функция зацикливания, которую я использую для этого.

//put all ID's in an array
while ($row2 = $connector->fetchArray($result2)){
 $id = $row2['ID'];
 $parents[$id] = $row2['name'];
}

// show the tree-structure
while ($row = $connector->fetchArray($result)){
    if($row['parentid']!=0)echo $parents[$row['parentid']].' -> ';
    echo $row['name'].' -    ';
    echo '<br>';
}

Я бы хотел изменить две вещи:

  1. иметь код, автоматически генерирующий дерево по размеру по необходимости.
  2. в циклах while я должен дважды выбрать $ result (один раз как $ result, один раз как $ result2), чтобы он заработал. эти $ result имеют точно такой же запрос к базе данных:
    SELECT ID,name,parentid FROM categories

для получения результатов. Я хотел бы объявить об этом только один раз.



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

$result = $connector->query('SELECT ID,name,parentid FROM categories');

// Get an array containing the results.
$parents = array();
while ($row = $connector->fetchArray($result)){
  $id = $row['ID'];
  $parents[$id] = array('ID' => $row['ID'],'name' => $row['name'],'parentid' => $row['parentid']);
}

foreach ($parents as $id => $row){
  $pid=$id;
  $arrTmp= array();
  do {      // iterate through all parents until top is reached
    $arrTmp[]=$pid;
    $pid = $parents[$pid]['parentid'];
  }while ($pid != 0);
    $arrTmp = array_reverse($arrTmp);
  foreach($arrTmp as $id){
    echo $parents[$id]['name'].' -&gt; ';
    }
  echo '<br>';
}

Ответы [ 4 ]

3 голосов
/ 04 августа 2009

Вместо того, чтобы PHP организовал элементы в дерево, почему бы не попросить базу данных сделать это для вас? Я нашел эту статью об иерархических данных очень хорошей, и примеры почти идентичны вашим.


EDIT

SQL для получения полного дерева с использованием модели смежности не идеален. Как объясняется в статье, требуется довольно много объединений даже для небольшой иерархии. Разве вы не можете использовать подход «Вложенный набор»? SQL остается неизменным независимо от размера иерархии, и INSERT и DELETE также не должны быть очень сложными.

1 голос
/ 05 августа 2009

Если вы используете PostgreSQL в качестве базы данных, вы можете использовать функцию connectby () для создания набора записей:

SELECT * 
FROM connectby('tableName', 'id', 'parent_id') 
    AS t(keyid text, parent_keyid text, level int);

Мне нравится эта функция, и я все время использую ее в своем коде. Он может делать очень мощные вещи, очень быстро, и вам не нужно поддерживать левые / правые значения, такие как ( смежность модель).

1 голос
/ 04 августа 2009

Может быть проще с ООП. Просто отсортируйте запрос по parentId

Примечание: метод listChildren и распечатка внизу как раз для того, чтобы показать, что они указаны правильно Я не интерпретировал вопрос о важности дисплея.

class Element {
    public $id;
    public $name;
    public $parent = null;
    public $children = array();

    public function __construct($id, $name)
    {
        $this->id = $id;
        $this->name = $name;
    }

    public function addChild($element)
    {
        $this->children[$element->id] = $element;
        $element->setParent($this);
    }

    public function setParent($element)
    {
        $this->parent = $element;
    }

    public function hasChildren()
    {
        return !empty($this->children);
    }

    public function listChildren()
    {
        if (empty($this->children)) {
            return null;
        }

        $out = array();
        foreach ($this->children as $child) {
            $data = $child->id . ':' . $child->name;
            $subChildren = $child->listChildren();
            if ($subChildren !== null) {
                $data .= '[' . $subChildren . ']';
            }
            $out[] = $data;
        }
        return implode(',', $out);
    }
}

$elements = array();
$noParents = array();
while ($row = $connector->fetchArray($result)) {
    $elements[$row['id']] = $element = new Element($row['id'], $row['name']);

    if (isset($elements[$row['parent']])) {
        $elements[$row['parent']]->addChild($element);
    } else {
        $noParents[] = $element;
    }
}

foreach ($noParents as $element) {
    if ($element->hasChildren()) {
        echo "Element {$element->id} has children {$element->listChildren()}.\n";
    } else {
        echo "Element {$element->id} has no children.\n";
    }
}
1 голос
/ 04 августа 2009

Если вы действительно хотите делать иерархии с родительскими идентификаторами (подходит только для небольшого количества элементов / иерархий)

Я немного изменил ваш код (я не тестировал его, поэтому могут быть некоторые синтаксические ошибки):

//put all recordsets in an array to save second query
while ($row2 = $connector->fetchArray($result2)){
  $id = $row2['ID'];
  $parents[$id] = array('name' => $row2['name'],'parent' => $row2['parentid']);
}

// show the tree-structure
foreach ($parents as $id => $row){
  $pid = $row['parentid'];
  while ($pid != 0){      // iterate through all parents until top is reached
    echo $parents[$pid]['name'].' -&gt; ';
    $pid = $parents[$pid]['parentid'];
  }
  echo $parents[$id]['name'].' -    ';
  echo '<br>';
}

Чтобы ответить на ваш комментарий:

$parents = array();
$parents[2] = array('ID'=>2,'name'=>'General','parentid'=>0); 
$parents[3] = array('ID'=>3,'name'=>'Gadgets','parentid'=>2); 
$parents[4] = array('ID'=>4,'name'=>'iPhone','parentid'=>3); 

foreach ($parents as $id => $row){
  $pid=$id;
  $arrTmp= array();
  do {      // iterate through all parents until top is reached
    $arrTmp[]=$pid;
    $pid = $parents[$pid]['parentid'];
  }while ($pid != 0);
    $arrTmp = array_reverse($arrTmp);
  foreach($arrTmp as $id){
    echo $parents[$id]['name'].' -&gt; ';
    }
  echo '<br>';
}

Распечатывается:

Общее ->

Общие сведения -> Гаджеты ->

Общие сведения -> Гаджеты -> iPhone ->

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...