/** * File name: TreeTable.class.php * Author: run.gao 312854458@qq.com Date: 2012-07-24 23:22 GMT+8 * Description: 通用的表格無限級分類 * */ /** * 表格展示無限分類是將無線分類已表格的形式表現出來,更好的能體現出分類的所屬關係 * 使用方法: * 1. 執行個體化分類 * $treeTable = new TreeTable(); * 2. 初始化分類,$treearr必須是一個多維陣列且包含 id,parentid,name欄位 * $treeTable->init($treearr); * 3. 擷取無限分類HTML代碼 * echo $treeTable->get_treetable(); * */ class TreeTable { /** * 產生樹型結構所需要的2維數組 * @var array */ public $arr = array(); /** * 表格列數 * @var int */ public $columns = 0; /** * 表格行數 * @var int */ public $rows = 0; /** * 初始化TreeTable資料 * @param array 2維數組 * array( * 1 => array('id'=>'1','parentid'=>0,'name'=>'一級欄目一'), * 2 => array('id'=>'2','parentid'=>0,'name'=>'一級欄目二'), * 3 => array('id'=>'3','parentid'=>1,'name'=>'二級欄目一'), * 4 => array('id'=>'4','parentid'=>1,'name'=>'二級欄目二'), * 5 => array('id'=>'5','parentid'=>2,'name'=>'二級欄目三'), * 6 => array('id'=>'6','parentid'=>3,'name'=>'三級欄目一'), * 7 => array('id'=>'7','parentid'=>3,'name'=>'三級欄目二') * ) */ public function init($arr=array()){ if(!is_array($arr)) return false; foreach ($arr as $k=>$v) { $this->arr[$v['id']] = $v; } foreach ($this->arr as $k => $v){ $this->arr[$k]['column'] = $this->get_level($v['id']); // Y軸位置 $this->arr[$k]['arrchildid'] = $this->get_arrchildid($v['id']); // 所有子節點 $this->arr[$k]['arrparentid'] = $this->get_arrparentid($v['id']); // 所有父節點 $this->arr[$k]['child_bottom_num'] = $this->get_child_count($v['id']); // 所有底層元素節點 } $this->columns = $this->get_columns(); // 總行數 $this->rows = $this->get_rows(); // 總列數 // 按照arrparentid和id號進行排序 $this->sort_arr(); foreach ($this->arr as $k => $v){ $this->arr[$k]['row'] = $this->get_row_location($v['id']); // X軸位置 $this->arr[$k]['rowspan'] = $v['child_bottom_num']; // 行合并數 $this->arr[$k]['colspan'] = $v['child_bottom_num'] == 0 ? $this->columns - $v['column'] + 1 : 0; //列合并數 } return $this->get_tree_arr(); } /** * 擷取數組 * */ public function get_tree_arr(){ return is_array($this->arr) ? $this->arr : false; } /** * 按arrparentid/id號依次重新排序數組 * */ public function sort_arr(){ // 要進行排序的欄位 foreach ($this->arr as $k => $v){ $order_pid_arr[$k] = $v['arrparentid']; $order_iscost[] = $v['sort']; $order_id_arr[$k] = $v['id']; } // 先根據arrparentid排序,再根據排序,id號排序 array_multisort( $order_pid_arr, SORT_ASC, SORT_STRING, $order_iscost, SORT_DESC, SORT_NUMERIC, $order_id_arr, SORT_ASC, SORT_NUMERIC, $this->arr); // 擷取每一個節點層次 for ($column = 1; $column <= $this->columns; $column++) { $row_level = 0; foreach ($this->arr as $key => $node){ if ($node['column'] == $column){ $row_level++; $this->arr[$key]['column_level'] = $row_level; } } } // 重新計算以ID作為鍵名 foreach ($this->arr as $k=>$v) { $arr[$v['id']] = $v; } $this->arr = $arr; } /** * 得到父級數組 * @param int * @return array */ public function get_parent($myid){ $newarr = array(); if(!isset($this->arr[$myid])) return false; $pid = $this->arr[$myid]['parentid']; $pid = $this->arr[$pid]['parentid']; if(is_array($this->arr)){ foreach($this->arr as $id => $a){ if($a['parentid'] == $pid) $newarr[$id] = $a; } } return $newarr; } /** * 得到子級數組 * @param int * @return array */ public function get_child($myid){ $a = $newarr = array(); if(is_array($this->arr)){ foreach($this->arr as $id => $a){ if($a['parentid'] == $myid) $newarr[$id] = $a; } } return $newarr ? $newarr : false; } /** * 擷取當前節點所在的層級 * @param $myid 當前節點ID號 * */ public function get_level($myid, $init = true){ static $level = 1; if($init) $level = 1; if ($this->arr[$myid]['parentid']) { $level++; $this->get_level($this->arr[$myid]['parentid'], false); } return $level; } /** * 擷取當前節點所有底層節點(沒有子節點的節點)的數量 * @param $myid 節點ID號 * @param $init 第一次載入將情況static變數 * */ public function get_child_count($myid, $init = true){ static $count = 0; if($init) $count = 0; if(!$this->get_child($myid) && $init) return 0; if($childarr = $this->get_child($myid)){ foreach ($childarr as $v){ $this->get_child_count($v['id'], false); } }else{ $count++; } return $count; } /** * 擷取節點所有子節點ID號 * @param $catid 節點ID號 * @param $init 第一次載入將情況static初始化 * */ public function get_arrchildid($myid, $init = true) { static $childid; if($init) $childid = ''; if(!is_array($this->arr)) return false; foreach($this->arr as $id => $a){ if($a['parentid'] == $myid) { $childid = $childid ? $childid.','.$a['id'] : $a['id']; $this->get_arrchildid($a['id'], false); } } return $childid ; } /** * 擷取該節點所有父節點ID號 * @param $id 節點ID號 * */ public function get_arrparentid($id, $arrparentid = '') { if(!is_array($this->arr)) return false; $parentid = $this->arr[$id]['parentid']; if($parentid > 0) $arrparentid = $arrparentid ? $parentid.','.$arrparentid : $parentid; if($parentid) $arrparentid = $this->get_arrparentid($parentid, $arrparentid); return $arrparentid; } /** * 擷取節點所在地行定位 * @param $myid 節點ID號 */ public function get_row_location($myid){ $nodearr = $this->arr; // 擷取每一個節點所在行的位置 foreach ($nodearr as $key => $node){ if($myid == $node['id']) { $node_row_count = 0; $arrparentid = explode(',', $node['arrparentid']); // 所有父節點小於當前節點層次的底層節點等於0的元素 foreach ($arrparentid as $pid){ foreach ($nodearr as $node_row){ if($node_row['column'] == $nodearr[$pid]['column'] && $nodearr[$pid]['column_level'] > $node_row['column_level'] && $node_row['child_bottom_num'] == 0){ $node_row_count ++; } } } // 所有當前節點並且節點層次(rowid_level)小於當前節點層次的個數 foreach ($nodearr as $node_row){ if($node['column'] == $node_row['column'] && $node_row['column_level'] < $node['column_level']){ $node_row_count += $node_row['child_bottom_num'] ? $node_row['child_bottom_num'] : 1; } } $node_row_count++; break; } } return $node_row_count; } /** * 擷取表格的行數 * */ public function get_rows(){ $row = 0; foreach ($this->arr as $key => $node){ if($node['child_bottom_num'] == 0){ $rows++; // 總行數 } } return $rows; } /** * 擷取表格的列數 * */ public function get_columns(){ $columns = 0 ; foreach ($this->arr as $key => $node){ if($node['column'] > $columns){ $columns = $node['column']; // 總列數 } } return $columns; } /** * 擷取分類的表格展現形式(不包含表頭) * */ public function get_treetable(){ $table_string = ''; for($row = 1; $row <= $this->rows; $row++){ $table_string .= "rt |