[英]php algorithm recursive tree
我正在修改一個開源腳本以通過組織結構圖樣式顯示家譜。
擁有帶有 id 和 parentid 字段的 users 表。
當我打開 /viewOrgChart?user_id=1 或不在 2 3 4 5 中的數字時,它運行良好!
但是,當我使用 user_id 2 3 4 5 打開時,它會拋出錯誤:嘗試獲取非對象的屬性“parentid”,$us->parentid 內部有另一個級別數組...錯誤只發生在這幾個用戶 id 上。 ..
/viewOrgChart?user_id=2
/viewOrgChart?user_id=3
/viewOrgChart?user_id=4
/viewOrgChart?user_id=5
無法弄清楚這里出了什么問題。
而且我還想根據傳入的 user_id 限制顯示的級別數。 假設我使用 user_id=1 傳入,我只想顯示最多 4 級的所有內容
(在這種情況下,它應該顯示到 firstname=eng 級別,在 eng 級別以下都不需要顯示)但是......在哪里......
任何算法專家?
<?php
function wpmlm_get_all_user_details_join() {
$sql = "SELECT * FROM users";
$results = \DB::select($sql);
return $results;
}
function wpmlm_get_user_details_by_id_join($user_id) {
$sql = "SELECT * FROM users where id = '" . $user_id . "'";
$results = \DB::select($sql);
return $results;
}
function wpmlm_makeNested($source) {
$nested = array();
foreach ($source as &$s) {
if (is_null($s['parent_id'])) {
// no parent_id so we put it in the root of the array
$nested[] = &$s;
} else {
$pid = $s['parent_id'];
if (isset($source[$pid])) {
if (!isset($source[$pid]['children'])) {
$source[$pid]['children'] = array();
}
$source[$pid]['children'][] = &$s;
}
}
}
return $nested;
}
function wpmlm_buildTree(array $elements, $parentId) {
static $counter = 0;
++$counter;
$tree = array();
foreach ($elements as $element) {
if ($element->id == $parentId) {
if ($counter == 1) {
$tree[] = $this->wpmlm_get_user_details_by_id_join($parentId);
}
}
if ($element->parentid == $parentId) {
$children = $this->wpmlm_buildTree($elements, $element->id);
if ($children) {
$tree[] = $children;
}
$tree[] = $element;
}
}
return $tree;
}
public function flattenArray($arr)
{
for ($i = 0; $i < count($arr); $i++) {
if (is_array($arr[$i])) {
array_splice($arr, $i, 1, $arr[$i]);
}
}
return $arr;
}
public function viewOrgChart(Request $request)
{
$user_id = $request->user_id;
$user_details = $this->wpmlm_get_all_user_details_join();
//$tree = $this->wpmlm_buildTree(elements, parentId);
$tree = $this->wpmlm_buildTree($user_details, $user_id);
foreach ($tree as $key => $data)
{
$test = $key;
if (is_array($data)) {
foreach ($data as $sub_data) {
$tree = $this->flattenArray($tree);
}
}
}
$arr = array();
$count = 0;
foreach ($tree as $us)
{
$count++;
if ($count == 1) {
$parent_id = null;
} else {
$parent_id = $us->parentid; //fail at here ERROR
}
$arr[$us->id] = Array(
'name' => $us->firstname,
'user_id' => $us->id,
'user_code' => $us->usercode,
'parent_id' => $parent_id,
'email' => $us->email,
);
}
$uniLevelTree = $this->wpmlm_makeNested($arr);
$treeJson = json_encode($uniLevelTree[0]);
}
?>
<div id="unilevel-tree">
<div class="panel-border">
<div id="chart-container"></div>
<div id="test"></div>
</div>
</div>
<link rel='stylesheet' id='wp-mlm-bootstrap-css-css' href='https://wpmlmsoftware.com/unilevel-mlm-demo/wp-content/plugins/wp-mlm/css/bootstrap.min.css?ver=5.2.1' type='text/css' media='all' />
<link rel='stylesheet' id='wp-mlm-font-awesome-css-css' href='https://wpmlmsoftware.com/unilevel-mlm-demo/wp-content/plugins/wp-mlm/css/font-awesome.min.css?ver=5.2.1' type='text/css' media='all' />
<link rel='stylesheet' id='wp-mlm-orgchart-style-css-css' href='https://wpmlmsoftware.com/unilevel-mlm-demo/wp-content/plugins/wp-mlm/css/orgchart-style.css?ver=5.2.1' type='text/css' media='all' />
<link rel='stylesheet' id='orgchart-css-css' href='https://wpmlmsoftware.com/unilevel-mlm-demo/wp-content/plugins/wp-mlm/css/jquery.orgchart.css?ver=5.2.1' type='text/css' media='all' />
<link rel='stylesheet' id='admin-wp-mlm-style-css' href='https://wpmlmsoftware.com/unilevel-mlm-demo/wp-content/plugins/wp-mlm/css/style.css?ver=5.2.1' type='text/css' media='all' />
<script type='text/javascript' src='https://wpmlmsoftware.com/unilevel-mlm-demo/wp-admin/load-scripts.php?c=0&load%5B%5D=jquery-core,jquery-migrate,utils&ver=5.2.1'></script>
<script type='text/javascript' src='https://wpmlmsoftware.com/unilevel-mlm-demo/wp-content/plugins/wp-mlm/js/bootstrap.min.js?ver=5.2.1'></script>
<script type='text/javascript' src='https://wpmlmsoftware.com/unilevel-mlm-demo/wp-content/plugins/wp-mlm/js/bootstrap-datepicker.js?ver=5.2.1'></script>
<script type='text/javascript' src='https://wpmlmsoftware.com/unilevel-mlm-demo/wp-content/plugins/wp-mlm/js/jquery.orgchart.js?ver=5.2.1'></script>
<script type="text/javascript">
jQuery( document ).ready( function( $ ) {
var datasource =<?php echo $treeJson; ?>
var nodeTemplate = function(data) {
return `
<span class = "user-image d-flex justify-content-center" >
<img src = "https://wpmlmsoftware.com/unilevel-mlm-demo/wp-content/plugins/wp-mlm/images/user.png" >
</span>
<div class = "title" > ${data.name} </div>
<div class = "" > ${data.email} </div>
<div class = "" > ${data.user_id} </div>
`;
};
var oc = $('#chart-container').orgchart({
'data' : datasource,
'nodeTemplate': nodeTemplate
});
});
</script>
SQL:
CREATE TABLE `users` (
`id` bigint(20) UNSIGNED NOT NULL,
`email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`firstname` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`parentid` int(10) UNSIGNED DEFAULT NULL
);
INSERT INTO `users` (`id`, `firstname`, `email`, `created_at`, `usercode`, `parentid`) VALUES
(1, 'andrew', 'test1@gmail.com', '2020-11-24 05:22:42', 'MB800001', 0),
(2, 'beta', 'test2@gmail.com', '2020-11-24 05:22:42', NULL, 1),
(3, 'cicak', 'test3@gmail.com', '2020-11-24 05:22:42', NULL, 2),
(4, 'dorae', 'test4@gmail.com', '2020-11-24 05:22:43', NULL, 3),
(5, 'eng', 'test5@gmail.com', '2020-11-24 05:22:43', NULL, 4),
(6, 'Fanny', 'test6@gmail.com', '2020-11-24 05:22:43', NULL, 5),
(7, 'Gary', 'test7@gmail.com', '2020-11-24 05:22:43', NULL, 6),
(8, 'Hafiz', 'test8@gmail.com', '2020-11-24 05:22:43', NULL, 7),
(9, 'Isaac', 'test9@gmail.com', '2020-11-24 05:22:43', NULL, 8),
(10, 'louis', 'test10@gmail.com', '2020-11-24 05:22:44', NULL, 1),
(11, 'shze', 'test11@gmail.com', '2020-11-24 05:22:44', NULL, 1),
(12, 'paul', 'test12@gmail.com', '2020-11-24 05:22:44', NULL, 10),
(13, 'eunice', 'test13@gmail.com', '2020-11-24 05:22:44', NULL, 10),
(14, 'shaun', 'test14@gmail.com', '2020-11-24 05:22:44', NULL, 11),
(15, 'xiao', 'test15@gmail.com', '2020-11-24 05:22:44', NULL, 11),
(16, 'hui', 'test16@gmail.com', '2020-11-24 05:22:44', NULL, 11),
(17, 'gen', 'test17@gmail.com', '2020-11-24 05:22:45', NULL, 16),
(18, 'hani', 'test18@gmail.com', '2020-11-24 05:22:45', NULL, 17),
(19, 'hola', 'test19@gmail.com', '2020-11-24 05:22:45', NULL, 18),
(20, 'hugo', 'test20@gmail.com', '2020-11-24 05:22:45', NULL, 19),
(21, 'lady', 'test21@gmail.com', '2020-11-24 05:22:45', NULL, 18);
這是我寫的 class 應該可以滿足您的需要:
<?php
class OrgTree {
public $users;
public function __construct($users) {
$this->users = $users;
}
private function getUserById($userId) {
return array_values(array_filter($this->users, function($user) use ($userId) {
return $user['id'] === $userId;
}))[0] ?? null;
}
private function getUsersByParentId($parentId) {
return array_values(array_filter($this->users, function($user) use ($parentId) {
return $user['parentid'] === $parentId;
}));
}
private function buildTree($userDetails, $maxDepth, $currentDepth = 0)
{
$info = [
"name" => $userDetails['firstname'],
"user_id" => $userDetails['id'],
"user_code" => $userDetails['usercode'],
"parent_id" => $userDetails['parentid'],
"email" => $userDetails['email'],
];
if ($maxDepth > $currentDepth) {
$childUsers = $this->getUsersByParentId($userDetails['id']);
$nextDepth = ++$currentDepth;
$info['children'] = array_map(function($childUser) use ($nextDepth, $maxDepth) {
return $this->buildTree($childUser, $maxDepth, $nextDepth);
}, $childUsers);
}
return $info;
}
public function createOrgTree($userId, $maxDepth = 4) {
return $this->buildTree($this->getUserById($userId), $maxDepth);
}
}
您只需要從您的數據庫中傳遞用戶:
public function viewOrgChart(Request $request) {
$user_id = $request->user_id;
$depth = 4; // get this from request if needed
$user_details = $this->wpmlm_get_all_user_details_join();
$orgTree = new OrgTree($user_details);
$tree = $orgTree->createOrgTree($user_id, $depth);
$treeJson = json_encode($tree);
}
您還可以更改 class 以根據需要從數據庫中提取用戶,而不是在開始時接收完整列表,就好像您有大量用戶,這種方法會更有效,尤其是在$depth
值較低的情況下。
為此,您只需刪除:
public $users;
public function __construct($users) {
$this->users;
}
並更改getUserById
和getUsersByParentId
以執行 SQL 查詢並返回數據。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.