2015-02-09 56 views
1

我目前正在使用PHP的評論系統,我正在使用「父ID」解決方案來連接一個答覆到另一個。問題是我還沒有想出如何將這些'父母身份'連接的數據存儲在MySQL數據庫中並將其渲染出來。我一直在尋找迭代解決方案,但沒有發現。我的數據庫結構如下: Parent_id 0表示頂級註釋。在PHP中使用迭代嵌套註釋

comment_id content parent_id 
1   xxx  0 
2   xxx  0 
3   xxx  1 
4   xxx  3 
5   xxx  4 
6   xxx  3 
...  ...  ... 

這裏是我做了什麼,我拿來所有的意見出一個數組,數組看起來像這樣:

$comment_list = array(0=>array('comment_id'=>1,'content'=>'xxx','parent_id'=>0), 
         0=>array('comment_id'=>2,'content'=>'xxx','parent_id'=>0), 
         0=>array('comment_id'=>3,'content'=>'xxx','parent_id'=>1), 
         0=>array('comment_id'=>4,'content'=>'xxx','parent_id'=>3), 
         ... 

) 

我需要附上與PARENT_ID 1 COMMENT_ID評論發表評論1,等等,深度應該是無限的,工作幾個小時仍然無法找到一種正確迭代的方式,有人可以給我一些指導如何做到這一點?我知道一個解決方案,但它對數據庫提出新的請求在每一次迭代中,所以我更願意一次性使用PHP數組,所以謝謝!

+0

你目前如何讓你的數組離開數據庫?還有,你如何將你的評論與某些東西聯繫起來...這沒有任何價值。 – cmorrissey 2015-02-09 19:01:51

回答

1

當面對這樣的複雜的結構,有時最好創建一個面向對象的溶液,然後使用的對象,以創建所需要的陣列。

例如,根據您以上,我可能會定義以下類:

class Comment{ 
    protected $id; 
    protected $children; 
    protected $content; 

    public function __construct($id, $content){ 
     $this->id = $id; 
     $this->content = $content; 
     $this->children = array(); 
    } 
    public function addChild($child){ 
     $this->children[] = $child; 
    } 
} 

現在,我們使用這個對象到你的數據庫轉移到工作內存如下:

$workingMemory = array(); //a place to store our objects 
$unprocessedRows = array(); //a place to store unprocessed records 

// here, add some code to fill $unproccessedRows with your database records 

do{ 
    $row = $unprocessedRows; //transfer unprocessed rows to a working array 
    $unprocessedRows = array(); //clear unprocessed rows to receive any rows that we need to process out of order. 
    foreach($row as $record){ 
    $id = $record[0]; //assign your database value for comment id here. 
    $content = $record[1]; //assign your database value for content here. 
    $parentId = $record[2]; //assign your database value for parent id here 

    $comment = new Comment($id, $content); 

    //for this example, we will refer to unlinked comments as 
    //having a parentId === null. 
    if($parentId === null){ 
     //this is just a comment and does not need to be linked to anything, add it to working memory indexed by it's id. 
     $workingMemory[ $id ] = $comment; 
    }else if(isset($workingMemory[ $parentId ])){ 
     //if we are in this code block, then we processed the parent earlier. 
     $parentComment = $workingMemory[ $parentId ]; 
     $parentComment->addChild($comment); 
     $workingMemory[ $id] = $comment; 
    }else{ 
     //if we are in this code block, the parent has not yet been processed. Store the row for processing again later. 
     $unprocessedRows[] = $record; 
    } 

    } 
    }while(count($unprocessedRows) > 0); 

一旦所有未處理的行都完成了,您現在可以完全存儲您的註釋表示形式,存儲在變量$ workingMemory中,並且此數組的每個單元格都是一個Comment對象,它具有$ id,$ content和指向所有子元素的註釋$ comments 。

我們現在可以通過查看此數組並做出力所能及的數據數組或表我們想要的。我們必須記住,我們存儲數組的方式,我們可以直接從$ workingMemory數組直接訪問任何註釋。

如果我是用這個來生成一個網站的HTML,我將通過的WorkingMemory陣列和過程只母評論循環。然後每個過程都會遍歷孩子。從父母開始,而不是孩子開始,我們會保證我們不會兩次處理相同的評論。

我會改變我的評論類來簡化這一過程:

class Comment{ 
    protected $id; 
    protected $children; 
    protected $content; 
    protected $isRoot; 

    public function __construct($id, $content){ 
     $this->id = $id; 
     $this->content = $content; 
     $this->children = array(); 
     $this->isRoot = true; 
    } 
    public function addChild($child){ 
     $child->isRoot = false; 
     $this->children[] = $child; 
    } 
    public function getChildren(){ return $this->children; } 
    public function getId(){ return $this->id; } 
    public function getContent(){ return $this->content; } 
} 

此更改後,我可以創造我的HTML如下:

function outputCommentToHTML($aComment, $commentLevel = 0){ 
    //I am using commentLevel here to set a special class, which I would use to indent the sub comments. 
    echo "<span class'comment {$commentLevel}' id='".($aComment->getId())."'>".($aComment->getContent())."</span>"; 
    $children = $aComment->getChildren(); 
    foreach($children as $child){ 
     outputCommentToHTML($child, $commentLevel + 1); 
    } 
} 
foreach($workingMemory as $aComment){ 
    if($aComment->isRoot === true){ 
     outputCommentToHTML($aComment); 
    } 
} 

這將數據庫中的列轉換成格式,你要求。例如,如果我們有以下數據:

comment_id content parent_id 
1   xxx  0 
2   xxx  0 
3   xxx  1 
4   xxx  3 
5   xxx  4 
6   xxx  3 
...  ...  ... 

,將在HTML輸出:

Comment_1 
     Comment_3 
      Comment_4 
       Comment_5 
      Comment_6 
    Comment_2 

這是在功能,充分運動評論2.之前也處理COMMENT_1完成遞歸在轉移到評論2之前完全處理Comment_3,這是評論4,5和6在評論2之前是如何得到輸出的。

上面的例子適用於你,但如果它是我的個人項目,我不會混合線性和麪向對象的代碼,所以我會創建一個代碼工廠將註釋轉換爲HTML。工廠從源對象製作數據字符串。您可以創建一個充當HTML工廠的對象,另一個充當SQL生成器的工廠,以及像這樣的解決方案的層對象,您可以創建完全面向對象的解決方案,這對於平均而言更容易理解讀者有時甚至非編碼產生這樣的:

//these definition files get hidden and tucked away for future use 
//you use include, include_once, require, or require_once to load them 
class CommentFactory{ 
     /**** other Code *****/ 

     public function createCommentArrayFromDatabaseRecords($records){ 
        /*** add the data conversion here that we discussed above ****/ 
        return $workingMemory; 
     } 
} 
class HTMLFactory{ 
     public function makeCommentTableFromCommentArray($array){ 
      $htmlString = ""; 
      foreach($array as $comment){ 
       if($comment->isRoot){ 
         $htmlString .= $this->getHTMLStringForComment($comment); 
       } 
      } 
      return $htmlString; 
     } 
     private function getHTMLStringForComment($comment, $level=0){ 
      /*** turn your comment and all it's children into HTML here (recursively) ****/ 
      return $html; 
     } 
} 

處理得當,使其讀起來幾乎像這樣的指令的列表,它可以清理你的激活碼文件:

//let database be a mysqli or other database connection 
//let the query function be whatever method works for your database 
// of choice. 
//let the $fetch_comment_sql variable hold your SQL string to fetch the 
// comments 
$records = $database->query($fetch_comment_sql) 
$comFactory = new CommentFactory(); 
$commentArray = $comFactory->createCommentArrayFromDatabaseRecords($records); 
$htmlFactory = new HTMLFactory(); 
$htmlResult = $htmlFactory->makeCommentTableFromCommentArray($commentArray); 
echo $htmlResult;