PHP 反向类别树数组到痕迹导航列表



>我有一个从MySQL表中获取的类别树数组。我想使用 PHP 将此类别数组树恢复为面包屑列表。

PHP 分类树构建函数

function buildTree(array &$elements, $parentId = 0) 
{
$branch = array();
foreach ($elements as $element) {
if ($element['parent_category_id'] == $parentId) {
$children = buildTree($elements, $element['category_id']);
if ($children) {
$element['children'] = $children;
}
$branch[$element['category_id']] = $element;
unset($elements[$element['category_id']]);
}
}
return $branch;
}

结果数组

[48] => Array
(
[category_id] => 48
[category_name] => Cat 1 
[parent_category_id] => 0
[children] => Array
(
[957] => Array
(
[category_id] => 957
[category_name] =>  Cat 2
[parent_category_id] => 48
[children] => Array
(
[1528] => Array
(
[category_id] => 1528
[category_name] =>  Cat 3
[parent_category_id] => 957
)
[1890] => Array
(
[category_id] => 1890
[category_name] =>  Cat 4
[parent_category_id] => 957
)
[1570] => Array
(
[category_id] => 1570
[category_name] =>  Cat 5
[parent_category_id] => 957
)
[958] => Array
(
[category_id] => 958
[category_name] =>  Cat 6
[parent_category_id] => 957
)
)
)

现在我想使用 PHP 将此数组树转换回面包屑列表,例如

"第1类>第2类>第3类">

"第1类>第2类>第4类">

"第1类>第2类>第5类">

"第1类>第2类>第6类">

任何帮助将不胜感激。

截图

屏幕截图参考

关键概念是将树转换为平面数组,其中每个类别都按其 ID 进行索引。从该平面结构中,您可以向上走过层次结构,直到到达每个类别的根目录,从而创建级别的数组。我创建了一个帮助程序类来封装您可能希望的痕迹导航的基本功能。递归发生在_unwindTree方法中。_buildBreadcrumbs方法调用此函数,并使用生成的平面数组为每个类别构建痕迹导航"行"。这是要了解如何将树转换为类别路径数组的两个函数。

有一些公共函数以不同的方式提供对痕迹导航数据的访问。

<?php
$tree = [
48 => [
'category_id' => 48,
'category_name' => 'Cat 1',
'parent_category_id' => 0,
'children' =>
[
957 =>
[
'category_id' => 957,
'category_name' => 'Cat 2',
'parent_category_id' => 48,
'children' =>
[
1528 =>
[
'category_id' => 1528,
'category_name' => 'Cat 3',
'parent_category_id' => 957
],
1890 =>
[
'category_id' => 1890,
'category_name' => 'Cat 4',
'parent_category_id' => 957
],
1570 =>
[
'category_id' => 1570,
'category_name' => 'Cat 5',
'parent_category_id' => 957
],
958 =>
[
'category_id' => 958,
'category_name' => 'Cat 6',
'parent_category_id' => 957
]
]
]
]
]
];
class BreadcrumbHelper
{
private $_leafOnly = true;
private $_defaultBaseUrlPath = '/category/';
private $_tree        = [];
private $_idMap       = [];
private $_leafIds     = [];
private $_breadcrumbs = [];
/**
* BreadcrumbHelper constructor.
* @param array $tree The tree of category data
*/
public function __construct($tree)
{
$this->_tree = $tree;
//Build the breadcrumb data structure
$this->_buildBreadcrumbs();
}
/**
* Return breadcrumbs as an array
* @param mixed $categoryIds optional, only specified categories will be returned
* @return array
*/
public function getBreadcrumbArray($categoryIds = [])
{
//If a bare ID is passed, wrap it in an array so we can treat all input the same way
if (!is_array($categoryIds))
{
$categoryIds = [$categoryIds];
}
//If we have category input, return a filtered array of the breadcrumbs
if (!empty($categoryIds))
{
return array_intersect_key($this->_breadcrumbs, array_flip($categoryIds));
}
//If no input, return the fill array
return $this->_breadcrumbs;
}
/**
* Return breadcrumbs as an array containing HTML markup
* You may want to modify this to echo HTML directly, or return markup only instead of an array
* @param mixed $categoryIds optional, only specified categories will be returned
* @return array
*/
public function getBreadcrumbHtml($categoryIds = [], $baseUrlPath = null)
{
//If a bare ID is passed, wrap it in an array so we can treat all input the same way
if (!is_array($categoryIds))
{
$categoryIds = [$categoryIds];
}
//If a base URL path is provided, use it, otherwise use default
$baseUrlPath = (empty($baseUrlPath)) ? $this->_defaultBaseUrlPath : $baseUrlPath;
//Filter breadcrumbs if IDs provided
$breadcrumbs = (empty($categoryIds)) ? $this->_breadcrumbs : array_intersect_key($this->_breadcrumbs, array_flip($categoryIds));
$output = [];
foreach ($breadcrumbs as $currCategoryId => $currLine)
{
$currLinkBuffer = [];
foreach ($currLine as $currCategory)
{
//Build the markup - customize the URL for your application
$currLinkBuffer[] = '<a href="' . $baseUrlPath . $currCategory['category_id'] . '">' . $currCategory['category_name'] . '</a>';
}
$output[$currCategoryId] = implode(' &gt; ', $currLinkBuffer);
}
return $output;
}
/**
* Print the breadcrumbs
* @param array $categoryIds optional, only specified categories will be printed
*/
public function printBreadcrumbs($categoryIds = [])
{
//If a bare ID is passed, wrap it in an array so we can treat all input the same way
if (!is_array($categoryIds))
{
$categoryIds = [$categoryIds];
}
//Filter breadcrumbs if IDs provided
$breadcrumbs = (empty($categoryIds)) ? $this->_breadcrumbs : array_intersect_key($this->_breadcrumbs, array_flip($categoryIds));
foreach ($breadcrumbs as $currLine)
{
//Build a buffer of the category names
$currNameBuffer = [];
foreach ($currLine as $currCategory)
{
$currNameBuffer[] = $currCategory['category_name'];
}
//Join the name buffer with a separator and echo the result
echo implode(' > ', $currNameBuffer) . PHP_EOL;
}
}
/**
* Create the breadcrumb data structure from the provided tree
*/
private function _buildBreadcrumbs()
{
//Unwind the tree into a flat array
$this->_unwindTree($this->_tree);
//Traverse the flat array and build the breadcrumb lines
$categoryIds = ($this->_leafOnly) ? $this->_leafIds:array_keys($this->_idMap);
foreach ($categoryIds as $currLeafId)
{
$currCategoryId = $currLeafId;
$currLine = [];
do
{
$currLine[]     = $this->_idMap[$currCategoryId];
$currCategoryId = $this->_idMap[$currCategoryId]['parent_category_id'];
} while ($currCategoryId != 0);
$this->_breadcrumbs[$currLeafId] = array_reverse($currLine);
}
}
/**
* Recursive function that traverses the tree and builds an associative array of all categories
* indexed by ID. Categories saved in this structure do not include children.
* @param $branch
*/
private function _unwindTree($branch)
{
foreach ($branch as $currId => $currData)
{
//Set the current category in the ID map, remove the children if present
$this->_idMap[$currId] = array_diff_key($currData, array_flip(['children']));
if (!empty($currData['children']))
{
//Recursion
$this->_unwindTree($currData['children']);
}
else
{
$this->_leafIds[] = $currId;
}
}
}
}
//Instantiate our helper with the tree data
$breadcrumbHelper = new BreadcrumbHelper($tree);
echo 'All breadcrumbs: ' . PHP_EOL;
$breadcrumbHelper->printBreadcrumbs();
echo PHP_EOL;
echo 'Single breadcrumb line by category ID: ' . PHP_EOL;
$breadcrumbHelper->printBreadcrumbs(1570);
echo PHP_EOL;
echo 'Multiple categories: ' . PHP_EOL;
$breadcrumbHelper->printBreadcrumbs([957, 1570]);
echo PHP_EOL;
echo 'Breadcrumb HTML: ' . PHP_EOL;
$breadcrumbMarkup = $breadcrumbHelper->getBreadcrumbHtml();
echo $breadcrumbMarkup[1570] . PHP_EOL;
echo PHP_EOL;
echo 'Breadcrumb HTML with custom base URL: ' . PHP_EOL;
$breadcrumbMarkup = $breadcrumbHelper->getBreadcrumbHtml(1570, '/category.php?id=');
echo $breadcrumbMarkup[1570] . PHP_EOL;
echo PHP_EOL;
function treeToArray($data, &$return_data, $index = '', $sub = 'sub')
{
if (is_array($data)) {
foreach ($data as $value) {
if (isset($value[$sub])) {
$tmp = $value[$sub];
unset($value[$sub]);
if ($index) {
$return_data[$value[$index]] = $value;
} else {
$return_data[] = $value;
}
treeToArray($tmp, $return_data, $index, $sub);
} else {
if ($index) {
$return_data[$value[$index]] = $value;
} else {
$return_data[] = $value;
}
}
}
}
return $return_data;
}
$tree[48] =  Array
(
"category_id" => '48',
"category_name" => 'Cat 1',
"parent_category_id" => '0',
"children" => Array
(
'957' => Array
(
"category_id" => "957",
"category_name" =>  "Cat",
"parent_category_id" => "48",
"children" => Array
(
'1528' => Array
(
"category_id" => "1528",
"category_name" =>  "Cat3",
"parent_category_id" => "957",
)
)
)
)
);
$data = [];
treeToArray($tree, $data, 'category_id', 'children');
print_r($data);

希望能有所帮助

最新更新