创建递归类别树函数

时间:2012-09-05 16:17:45

标签: php tree categories

我有一个包含许多类别的数据库,有些是儿童:

Array
(
    [0] => Array
        (
            [id] => 1
            [name] => Home Improvement
            [slug] => Home-Improvement
            [parent] => 
            [user_id] => 1
            [order] => 1
        )

    [1] => Array
        (
            [id] => 2
            [name] => Asbestos Abatement & Removal
            [slug] => Asbestos-Abatement-Removal
            [parent] => 1
            [user_id] => 1
            [order] => 8
        )

    [2] => Array
        (
            [id] => 3
            [name] => Asphalt & Asphalt Products
            [slug] => Asphalt-Asphalt-Products
            [parent] => 1
            [user_id] => 1
            [order] => 9
        )

    [3] => Array
        (
            [id] => 4
            [name] => Bathroom
            [slug] => Bathroom
            [parent] => 1
            [user_id] => 1
            [order] => 10
        )

    [4] => Array
        (
            [id] => 5
            [name] => Kitchen Cabinets
            [slug] => Kitchen-Cabinets
            [parent] => 1
            [user_id] => 1
            [order] => 11
        )

    [5] => Array
        (
            [id] => 6
            [name] => Ceilings
            [slug] => Ceilings
            [parent] => 1
            [user_id] => 1
            [order] => 12
        )

    [6] => Array
        (
            [id] => 7
            [name] => Cleaning
            [slug] => Cleaning
            [parent] => 1
            [user_id] => 1
            [order] => 13
        )

    [7] => Array
        (
            [id] => 8
            [name] => Closet Organizers & Accessories
            [slug] => Closet-Organizers-Accessories
            [parent] => 1
            [user_id] => 1
            [order] => 14
        )

    [8] => Array
        (
            [id] => 9
            [name] => Concrete
            [slug] => Concrete
            [parent] => 1
            [user_id] => 1
            [order] => 15
        )

    [9] => Array
        (
            [id] => 10
            [name] => Contractors & Service Providers
            [slug] => Contractors-Service-Providers
            [parent] => 1
            [user_id] => 1
            [order] => 16
        )

我想要输出的是这样的:

<ul>
    <li>Parent
        <ul>
            <li>Child</li>
        </ul>
    </li>
    <li>Parent with no Children</li>
</ul>

我正在尝试用PHP构建一个递归树脚本,但是我被卡住了。这是我到目前为止所拥有的。我坚持要在别人之间做什么:和endif;在foreach。 (我正在使用这种语法只是为了更容易阅读。)有什么建议吗?

echo $this->categories->makeTree(0, $this->db->get('categories')->result_array());

public static function makeTree($parent, $array)
{
  if (!is_array($array)) return '';

  $output = '<ul>';

  foreach($array as $key => $value):
    if ($value['parent'] == $parent):
        $output .= '<li>';

        if ($value['parent'] == NULL):
            $output .= $value['name'];
        else:

        endif;
    endif;

    $output .= '</li>';
  endforeach;

  $output .= '</ul>';
  return $output;
}

编辑1

虽然我在foreach循环中有一个数据库调用,但我能够正常工作,这可能不是最好的想法:

public function makeTree($parent, $array)
{
  if (!is_array($array)) return FALSE;

  $output = '<ul>';

  foreach($array as $key => $value):
    if ($value['parent'] == $parent):
        $output .= '<li>';

        if ($value['parent'] == NULL):
            $output .= $value['name'];

            $subcategories = ci()->db->get_where('categories', array('parent' => $value['id']));

            if ($subcategories->num_rows() > 0):
                $output .= $this->makeTree($value['id'], $subcategories->result_array());
            endif;
        else:
            $output .= $value['name'];
            $output .= '</li>';
        endif;
    endif;

  endforeach;

  $output .= '</ul>';
  return $output;
}

编辑2

这是我的最终解决方案,重用数组而不是进行数据库查询:

public function makeTree($parent, $array)
{
  if (!is_array($array) OR empty($array)) return FALSE;

  $output = '<ul>';

  foreach($array as $key => $value):
    if ($value['parent'] == $parent):
        $output .= '<li>';

        if ($value['parent'] == NULL):
            $output .= $value['name'];

            $matches = array();

            foreach($array as $subkey => $subvalue):
                if ($subvalue['parent'] == $value['id']):
                    $matches[$subkey] = $subvalue;
                endif;
            endforeach;

            $output .= $this->makeTree($value['id'], $matches);

        else:
            $output .= $value['name'];
            $output .= '</li>';
        endif;
    endif;

  endforeach;

  $output .= '</ul>';

  return $output;
}

5 个答案:

答案 0 :(得分:9)

虽然这似乎得到了解答,但请查看here。使用显示的功能,您只需一次迭代即可将平面数据转换为嵌套数据。从那个嵌套数据创建ul-list非常容易。例如:

function nested2ul($data) {
  $result = array();

  if (sizeof($data) > 0) {
    $result[] = '<ul>';
    foreach ($data as $entry) {
      $result[] = sprintf(
        '<li>%s %s</li>',
        $entry['name'],
        nested2ul($entry['children'])
      );
    }
    $result[] = '</ul>';
  }

  return implode($result);
}

echo nested2ul(array(flat2nested( $yourFlatData ));

这种方法的好处在于您不必为了找到子元素而一次又一次地对输入数据进行重复迭代。

答案 1 :(得分:2)

这是我的最终解决方案,重用数组而不是进行数据库查询。如果您有更好的解决方案,请发布!

public function makeTree($parent, $array)
{
  if (!is_array($array) OR empty($array)) return FALSE;

  $output = '<ul>';

  foreach($array as $key => $value):
    if ($value['parent'] == $parent):
        $output .= '<li>';

        if ($value['parent'] == NULL):
            $output .= $value['name'];

            $matches = array();

            foreach($array as $subkey => $subvalue):
                if ($subvalue['parent'] == $value['id']):
                    $matches[$subkey] = $subvalue;
                endif;
            endforeach;

            $output .= $this->makeTree($value['id'], $matches);

        else:
            $output .= $value['name'];
            $output .= '</li>';
        endif;
    endif;

  endforeach;

  $output .= '</ul>';

  return $output;
}

答案 2 :(得分:1)

我通常使用这样的东西,请注意

第一段这段代码使用了已弃用的 mysql _ *

第二个你应该有一个名为level的数据库字段,如果是NULL它是主要类别,如果它有一个数字,它是该类别的子类别,该数字为id

function getFamilies($level = 0) {
    $level++;
    $sql = "SELECT id from families WHERE level IS NULL";
    if (mysql_num_rows($result) > 0) {
        echo "<ul>";
            while($row = mysql_fetch_assoc($result)) {
                echo "<li>".$row['id'];
                    getSubFamilies($level, $row['id']);
                echo "</li>";
            }
        echo "</ul>";
    }
}

function getSubFamilies($level, $id) {
    $level++;
    $sqlSubFamilies = "SELECT id  FROM families WHERE level = ".$id."";
    $resultSubFamilies = mysql_query($sqlSubFamilies);
    if (mysql_num_rows($resultSubFamilies) > 0) {
        echo = "<ul>";
            while($rowSubFamilies = mysql_fetch_assoc($resultSubFamilies)) {
                echo "<li>".$rowSubFamilies['id'];
                    getSubFamilies($level, $rowSubFamilies['id']);
                echo "</li>";
            }
        echo "</ul>";
    }
}

getFamilies($level = 0);

答案 3 :(得分:0)

试试这个:

$cats = $this->db->get('categories')->result_array();

echo $this->categories->makeTree(0, $cats);

public static function makeTree($parent, $array)
{
  if (!is_array($array)) return '';

  $output = '<ul>';

  foreach($array as $key => $value):
    if ($value['parent'] == $parent):
        $output .= '<li>';

        if ($value['parent'] == NULL):
            $output .= $value['name'];
        else:

        endif;
    endif;

    $output .= '</li>';

    $output .= $this->categories->makeTree($value['parent'], $cats);

  endforeach;

  $output .= '</ul>';
  return $output;
}

答案 4 :(得分:0)

我认为使用匿名函数的方法非常简单。

//--------------------------- PRINT NESTED CATEGORIES
$cats_childs = array();

$q = $db->query("SELECT id, parent, name FROM categories");

while ($r = $db->row($q))
{
    $cats_childs[$r['parent']][$r['id']] = $r;
}

$nested2ul = function($data) use (&$nested2ul, &$cats_childs) {
    if (!empty($data)) {
        echo '<ul>';
        foreach ($data as $r) {
            echo '<li>';
            echo $r['name'];
            $flat2ul($cats_childs[$r['id']]);
            echo '</li>';
        }
        echo '</ul>';
    }
};

echo $nested2ul($cats_childs[0]);