2011-04-25 55 views
0

我們有兩種模型。電子書HABTM標籤,其中標籤遵循​​樹的行爲。用樹模型計算相關記錄(全深度)

對於每個標籤,我們需要兩個數字。首先,與標籤關聯的電子書數量,其次是與標籤關聯的電子書數量+每個後代的關聯電子書數量。

我們如何才能得到這些數字樹形格式的數字標籤?

非常感謝您的幫助。

更新:有一個datetime參數Ebook.published,它定義了何時該書被計數。所有有codeEbook.published < NOW()的電子書應該被計數。

+0

除非我誤解你的問題。這應該由cake默認設置。當你把它放在你的電子書控制器中時會丟失什麼數據...''這個數字在你的電子書控制器中丟失了......'pr($ this-> Ebook-> find('all'));' – 2011-04-25 20:03:52

+0

我需要'$ this-> Tag-> find '選擇,其中包括結果中每個後代標記的相關電子書的總數。 – 2011-04-26 08:44:15

回答

0

實際上,我找到了一個更簡單的解決方案,因爲我已經構建了返回標籤樹的函數。我使用每個標籤的查詢來獲得當時的實際數量。這是我建立的。隨意根據您的需求使用它。

在變量模型

// Returns the number of published ebooks of selected tag 
function count_direct_published($tag_id = 0){ 
    $temp = $this->query('SELECT count(*) as count FROM ebooks_tags LEFT JOIN ebooks ON ebooks_tags.ebook_id = ebooks.id WHERE ebooks.published < NOW() AND ebooks_tags.tag_id = '.$tag_id); 
    return $temp[0][0]['count']; 
} 


// Returns an array in tree format with $id tag and all his children 
// $id = 0 start from the top (parent_id = null), or, from $id = the top's tag id 
// $limit = boolean (default false) 
// $level = Is the limit of depth applied only if $limit = true 
// $ext = true Means this is the first time the function is called 
// You can run tree_builder(), returns all the tree, 
function tree_builder($id = 0, $limit = false, $level = 1, $ext = 1){ 
    if($ext == 1){ 
     $ext = 0; 
     $undo = true; 
    }else{ 
     $undo = false; 
    } 
$this->recursive=-1; 

    $this->contain('EbooksTag'); 

    $var = array(); 
    $count_all = 0; 
    // If limit = too big , exit 
    if($limit !== false && $level > $limit){ 
     return ''; 
    } 
    // Or else, 
    // If $id=0, find all the children 
    if($id == 0){ 
     $tags = $this->find('all',array('conditions'=>array('Tag.parent_id IS NULL'), 'order'=>array('Tag.gre'))); 
    // If $id!=0 && runs internally 
    }elseif($id != 0 && !$undo){ 
     $tags = $this->find('all',array('conditions'=>array('Tag.parent_id'=>$id), 'order'=>array('Tag.gre'))); 
    } 
    // If $id!=0 && is called from outside 
    elseif($id != 0 && $undo){ 
     $tags = $this->find('all',array('conditions'=>array('Tag.id'=>$id))); 

    } 

    foreach($tags as $key => $tag){ 
     $var[] = $tag; 
     $next = $this->tree_builder($tag['Tag']['id'], $limit, $level+1, $ext); 
     end($var); // move the internal pointer to the end of the array 
     $last_key = key($var); // fetches the key of the element pointed to by the internal pointer 
     $var[$last_key]['children'] = $next['var']; 
     $counter_direct = $this->count_direct_published($id); 
     $var[$last_key]['Tag']['count_all'] = $next['count_all']+$counter_direct; 
     $count_all += $var[$last_key]['Tag']['count_all']; 

    } 

    if($undo) 
    { 
     return $var; 
    }else{ 
     return array('count_all'=> $count_all, 'var' => $var); 
    } 

} 

在tags_controller.php

$this->set('tags', $this->Tag->tree_builder()); 

在視圖

<?php foreach($tags as $tag){?> 
    <?php // Ο Γονέας σε dropdown box ?> 
    <div class="main-categ"> 
    <?php echo $tag['Tag']['gre']; ?> 
    <?php echo $html->image('layout/arrows.png', array('alt'=> "Expand")); ?> 
    </div> 



    <div class="collapse"> 
     <?php // Τα στοιχεία του γονέα ?> 
     <div class="tag-1"> 
      <span class="tag-1"> 
       <?php // Αν ?> 
       <?php if($tag['Tag']['count_direct']>0){ 
        // Display link 
        echo $html->link($tag['Tag']['gre'],array('action'=>'view',$tag['Tag']['id'])); 
        echo ' ('.$tag['Tag']['count_direct'].')'; 
       }else{ 
        // Display text 
        echo $tag['Tag']['gre']; 

       } ?> 
      </span> 
      &nbsp;&nbsp;&nbsp;&nbsp; 
      <?php echo $html->link('view all' ,array('action'=>'view_all',$tag['Tag']['id'])); ?> 
      (<?php echo $tag['Tag']['count_all']; ?>) 
     </div> 

     <?php // Για κάθε πρώτο παιδί ?> 
     <?php foreach($tag['children'] as $tag_1){ ?> 
     <div> 
      <span class="tag-2"> 
       <?php if($tag_1['Tag']['count_direct']>0){ 
        // Display link 
        echo $html->link($tag_1['Tag']['gre'],array('action'=>'view',$tag_1['Tag']['id'])); 
        echo ' ('.$tag_1['Tag']['count_direct'].')'; 
       }else{ 
        // Display text 
        echo $tag_1['Tag']['gre']; 

       } ?> 
      </span> 
      &nbsp;&nbsp;&nbsp;&nbsp; 
      <?php echo $html->link('view all' ,array('action'=>'view_all',$tag_1['Tag']['id'])); ?> 
      (<?php echo $tag_1['Tag']['count_all']; ?>) 

       <?php // Τα δεύτερα παιδιά ?> 
       <?php $i=0; ?> 
       <?php foreach($tag_1['children'] as $tag_2){ ?> 
        <?php if($i==0){ echo '<ul class="split">'; $i++; } ?> 
        <li> 
        <?php if($tag_2['Tag']['count_direct']>0){ 
          // Display link 
          echo $html->link($tag_2['Tag']['gre'],array('action'=>'view',$tag_2['Tag']['id'])); 
          echo ' ('.$tag_2['Tag']['count_direct'].')'; 
         }else{ 
          // Display text 
          echo $tag_2['Tag']['gre']; 

         } ?>      
        </li> 
       <?php } ?> 
       <?php if($i==1) echo '</ul>'; ?> 

      <div class="clear"></div>  
     </div> 

     <?php } ?>  

    </div> 

也許它不是最好的解決方案,但它的工作原理。希望有幫助

1

蛋糕對此沒有基本的支持。您將需要立即進行計算,或者使用自定義代碼創建自己的計數器緩存以進行更新。這很混亂。

我建議覆蓋Ebooks控制器中的beforeSave()和afterSave()函數。如果進行更新,請在beforeSave()中獲取與Ebook相關的當前現有標記集。在afterSave()獲取新的標記集並將其與前一集合並。如果有任何更改,請遍歷所有標籤並調用$this->Tag->getPath($id)以獲取所有祖先的列表。現在您將擁有受保存影響的所有標籤。您現在可以遍歷它們並更新計數。

+0

謝謝你的答案,但它比這更復雜。有一個日期時間參數Ebook.published,它定義了圖書的計數時間。應該計算所有具有'codeEbook.published 2011-04-26 08:37:03

+0

然後,您可以將基本相同的解決方案應用於標記模型中的afterFind()。用它來進行計算,然後將計數注入返回的記錄中。 – Tyler 2011-04-26 17:01:31