我們有兩種模型。電子書HABTM標籤,其中標籤遵循樹的行爲。用樹模型計算相關記錄(全深度)
對於每個標籤,我們需要兩個數字。首先,與標籤關聯的電子書數量,其次是與標籤關聯的電子書數量+每個後代的關聯電子書數量。
我們如何才能得到這些數字樹形格式的數字標籤?
非常感謝您的幫助。
更新:有一個datetime參數Ebook.published,它定義了何時該書被計數。所有有codeEbook.published < NOW()的電子書應該被計數。
我們有兩種模型。電子書HABTM標籤,其中標籤遵循樹的行爲。用樹模型計算相關記錄(全深度)
對於每個標籤,我們需要兩個數字。首先,與標籤關聯的電子書數量,其次是與標籤關聯的電子書數量+每個後代的關聯電子書數量。
我們如何才能得到這些數字樹形格式的數字標籤?
非常感謝您的幫助。
更新:有一個datetime參數Ebook.published,它定義了何時該書被計數。所有有codeEbook.published < NOW()的電子書應該被計數。
實際上,我找到了一個更簡單的解決方案,因爲我已經構建了返回標籤樹的函數。我使用每個標籤的查詢來獲得當時的實際數量。這是我建立的。隨意根據您的需求使用它。
在變量模型
// 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>
<?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>
<?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>
也許它不是最好的解決方案,但它的工作原理。希望有幫助
蛋糕對此沒有基本的支持。您將需要立即進行計算,或者使用自定義代碼創建自己的計數器緩存以進行更新。這很混亂。
我建議覆蓋Ebooks控制器中的beforeSave()和afterSave()函數。如果進行更新,請在beforeSave()中獲取與Ebook相關的當前現有標記集。在afterSave()獲取新的標記集並將其與前一集合並。如果有任何更改,請遍歷所有標籤並調用$this->Tag->getPath($id)
以獲取所有祖先的列表。現在您將擁有受保存影響的所有標籤。您現在可以遍歷它們並更新計數。
謝謝你的答案,但它比這更復雜。有一個日期時間參數Ebook.published,它定義了圖書的計數時間。應該計算所有具有'codeEbook.published
然後,您可以將基本相同的解決方案應用於標記模型中的afterFind()。用它來進行計算,然後將計數注入返回的記錄中。 – Tyler 2011-04-26 17:01:31
除非我誤解你的問題。這應該由cake默認設置。當你把它放在你的電子書控制器中時會丟失什麼數據...''這個數字在你的電子書控制器中丟失了......'pr($ this-> Ebook-> find('all'));' – 2011-04-25 20:03:52
我需要'$ this-> Tag-> find '選擇,其中包括結果中每個後代標記的相關電子書的總數。 – 2011-04-26 08:44:15