[英]PHP: Loop through multidimensional array and establish parent-child relationships between array items
我正在開發一個內容管理系統,我遇到了CMS中項目的子父關系問題。
基本上我有一個可以創建頁面的系統,當創建頁面時,您可以選擇子頁面進行子導航。 在我嘗試從數據庫生成導航之前,這一切都很好。
我不確定某種連接是否會更好但我更喜歡在數組中獲取所有數據並使用php操作數組。
我的數據庫結果是這樣的:
Array
(
[0] => Array
(
[id] => 27
[name] => home
[link] => home.html
[parent] => 0
)
[1] => Array
(
[id] => 30
[name] => about
[link] => about.html
[parent] => 27
)
)
我需要遍歷這樣的數組,它可以有任意數量的導航並智能地將其排序到其父子關系中。 我能夠做到但只有一層深。 它需要管理有孩子的孩子等有無限層數的孩子,並將其輸出到HTML無序嵌套列表。
<ul>
<li>
<a>Nav</a>
<ul>
<li>
<a>Subnav</a>
<ul>
<li>
<a>Sub Sub nav</a>
</li>
</ul>
</li>
</ul>
<li>
<ul>
等......
我不認為你應該進入對象。 另外我認為生成對象等只是額外的工作。在我看來,你應該遍歷數組並生成一個代表導航層次結構的多維數組,然后遞歸循環生成的數組以生成HTML。 我已經為你做了一個示例代碼,它按你想要的方式工作,但你可能想做一些改變。
職能
// Generate your multidimensional array from the linear array
function GenerateNavArray($arr, $parent = 0)
{
$pages = Array();
foreach($arr as $page)
{
if($page['parent'] == $parent)
{
$page['sub'] = isset($page['sub']) ? $page['sub'] : GenerateNavArray($arr, $page['id']);
$pages[] = $page;
}
}
return $pages;
}
// loop the multidimensional array recursively to generate the HTML
function GenerateNavHTML($nav)
{
$html = '';
foreach($nav as $page)
{
$html .= '<ul><li>';
$html .= '<a href="' . $page['link'] . '">' . $page['name'] . '</a>';
$html .= GenerateNavHTML($page['sub']);
$html .= '</li></ul>';
}
return $html;
}
**樣品用量**
$nav = Array
(
Array
(
'id' => 27,
'name' => 'home',
'link' => 'home.html',
'parent' => 0
),
Array
(
'id' => 30,
'name' => 'about',
'link' => 'about.html',
'parent' => 27
)
);
$navarray = GenerateNavArray($nav);
echo GenerateNavHTML($navarray);
您可以一步完成這兩件事,但我認為首先生成多維數組更為簡潔。 祝好運!
Saad Imran的解決方案可以正常工作,除非你想要在同一個列表中有多個導航項目。 我必須更改幾行才能生成經過驗證的項目列表。 我還添加了縮進以使生成的代碼更具可讀性。 我正在使用空格,但如果您願意,可以很容易地將其更改為制表符,只需用"\\t"
替換4個空格即可。 (注意你必須使用雙引號,而不是單引號,否則php不會替換為制表符但實際上是\\ t)
我在codeigniter 2.1.0中使用這個與superfish(PHP5)
function GenerateNavHTML($nav, $tabs = "")
{
$tab=" ";
$html = "\n$tabs<ul class=\"sf-menu\">\n";
foreach($nav as $page)
{
//check if page is currently being viewed
if($page['link'] == uri_string()) {
$html .= "$tabs$tab<li class=\"current\">";
} else {
$html .= "$tabs$tab<li>";
}
$html .= "<a href=\"$page[link]\">$page[name]</a>";
//Don't generate empty lists
if(isset($page['sub'][0])) {
$html .= $this->GenerateNavHTML($page['sub'], $tabs.$tab);
}
$html .= "</li>\n";
}
$html .= $tabs."</ul>\n";
return $html;
}
我得到了(改為ol澄清)
1. Home
1. About Us
1. Products
1. sub-product 1
1. sub-product 2
1. Contact
現在我明白了
1. Home
2. About Us
3. Products
1. sub-product 1
2. sub-product 2
4. Contact
很好地生成HTML
<ul class="sf-menu">
<li class="current"><a href="index.html">Home</a></li>
<li><a href="about.html">About Us</a></li>
<li><a href="products.html">Products</a>
<ul class="sf-menu">
<li><a href="products-sub1.html">sub-product 1</a></li>
<li><a href="products-sub2.html">sub-product 2</a></li>
</ul>
</li>
<li><a href="contact.html">Contact</a></li>
</ul>
最簡單的方法可能是使用對象。 這些可以很容易地操作,也可以從數據庫中獲得的數組中輕松創建。
例如,每個對象都有:
您將需要一個能夠找出具有特定數據庫ID的對象的靜態函數。 這是在創建新對象期間完成的,方法是將引用放在靜態列表中。 然后可以在運行時調用並檢查此列表。
其余的很簡單:
$arr = get_array_from_database();
foreach($arr as $node){
$parent_object = get_parent_object($node_id);
$parent_object.subnodes[] = new NodeObject($node);
}
至於返回列表中的對象,最好以遞歸方式完成;
function return_in_list($objects)
{
foreach($objects as $node)
{
echo '<li>';
echo '<a>' + node.link + '</a>';
if(node.subnodes.length > 0)
{
echo '<ul>';
return_in_list($node.subnodes);
echo '</ul>';
}
puts '</li>'
}
}
我正在研究同一個項目,我還沒有發現需要使用對象。 數據庫非常關注結構,php函數可以完成其余的工作。 我的解決方案是有一個父字段,用於指向部分名稱的頁面,但也為部分表添加父字段,以便部分可以指向其他部分作為父級。 它仍然非常易於管理,因為只有2個父字段可以跟蹤,每個表一個,我可以在未來根據需要將我的結構嵌套到多個級別。
因此,對於動態樹創建,我將以遞歸方式檢查父項,直到我達到null,這表明當前元素位於doc根目錄上。 這樣我們就不需要知道函數代碼中當前頁面結構的任何細節,我們可以專注於在mysql中添加和排列頁面。 由於另一張海報顯示了一些菜單html,我想我會在這里添加一個動態痕跡路徑的例子,因為主題非常相似。
數據
// Sample 3 x 2 page array (php / html pages)
// D1 key = page name
// D2 element 1 = page name for menu display
// D2 element 2 = parent name (section)
$pages = Array
(
'sample-page-1.php' => Array ( 'M' => 'page 1', 'P' => null ),
'sample-page-2.php' => Array ( 'M' => 'page 2', 'P' => 'hello' ),
'sample-page-3.php' => Array ( 'M' => 'page 3', 'P' => 'world' )
);
// Sample 2 x 1 section array (parent directories)
// D1 key = section name
// D2 element = parent name (if null, assume root)
$sections = Array
(
'hello' => null,
'world' => 'hello'
);
$sep = ' > '; // Path seperator
$site = 'test.com'; // Home string
職能
// Echo paragraph to browser
function html_pp ( $text )
{
echo PHP_EOL . '<p>' . sprintf ( $text ) . '</p>' . PHP_EOL;
}
// Get breadcrumb for given page
function breadcrumb ( $page )
{
// Reference variables in parent scope
global $pages;
global $sections;
global $sep;
global $site;
// Get page data from array
$menu = $pages [ $page ] [ 'M' ];
$parent = $pages [ $page ] [ 'P' ];
if ( $parent == null )
{
$path = $site . $sep . $menu;
}
else
{
$path = $site . $sep . get_path ( $parent ) . $sep . $menu;
}
return $path;
}
// Trace ancestry back to root
function get_path ( $parent )
{
// Reference variables in parent scope
global $sections;
global $sep;
if ( $sections [ $parent ] == null )
{
// No more parents
return $parent;
}
else
{
// Get next parent through recursive call
return get_path ( $sections [ $parent ] ) . $sep . $parent;
}
}
用法
// Get breadcrumbs by page name
$p1 = 'sample-page-1.php';
$p2 = 'sample-page-2.php';
$p3 = 'sample-page-3.php';
html_pp ( $p1 . ' || ' . breadcrumb ( $p1 ) );
html_pp ( $p2 . ' || ' . breadcrumb ( $p2 ) );
html_pp ( $p3 . ' || ' . breadcrumb ( $p3 ) );
// or use foreach to list all pages
foreach ( $pages as $page => $data)
{
html_pp ( $page . ' || ' . breadcrumb ( $page ) );
}
OUTPUT
sample-page-1.php || test.com>第1頁
sample-page-2.php || test.com>你好>第2頁
sample-page-3.php || test.com>你好>世界>第3頁
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.