When the cached votes are recalculated, the module first deletes the existing cached entry, then inserts a new line into the db with a new vote_cache_id.
The result of this is that the vote_cache_id is constantly growing on each tally.
This can be avoided by simply updating the existing cached entry. To do this, I modified votingapi_recalculate_results() and added a new function _votingapi_update_cache_result() which is quite similar to _votingapi_insert_cache_result().
Actually, with _votingapi_update_cache_result() in place, I'm pretty sure that _votingapi_insert_cache_result() is redundant.
Here's the code:
function votingapi_recalculate_results($content_type, $content_id, $force_calculation = FALSE) {
// if we're operating in cron mode, and the 'force recalculation' flag is NOT set,
// bail out. The cron run will pick up the results.
if (variable_get('votingapi_calculation_schedule', 'immediate') != 'cron' && $force_calculation != TRUE) {
// blow away the existing cache records.
/**
* vote_cache_id patch. Entry not deleted, just getting updated.
*/
//db_query("DELETE FROM {votingapi_cache} WHERE content_type = '%s' AND content_id = %d", $content_type, $content_id);
$cache = array();
$votes = _votingapi_get_raw_votes($content_type, $content_id);
// Loop through, calculate per-type and per-tag totals, etc.
foreach($votes as $vote) {
switch ($vote->value_type) {
case 'percent':
$cache[$vote->tag][$vote->value_type]['count'] += 1;
$cache[$vote->tag][$vote->value_type]['sum'] += $vote->value;
break;
case 'points':
$cache[$vote->tag][$vote->value_type]['count'] += 1;
$cache[$vote->tag][$vote->value_type]['sum'] += $vote->value;
break;
case 'option':
$cache[$vote->tag][$vote->value_type][$vote->value] += 1;
break;
}
}
// Do a quick loop through to calculate averages.
// This is also a good example of how external modules can do their own processing.
foreach ($cache as $tag=>$types) {
foreach ($types as $type=>$functions) {
if ($type == 'percent' || $type == 'points') {
$cache[$tag][$type]['average'] = $functions['sum'] / $functions['count'];
}
if ($type == 'percent') {
// we don't actually need the sum for this. discard it to avoid cluttering the db.
unset($cache[$tag][$type]['sum']);
}
}
}
// Give other modules a chance to alter the collection of votes.
votingapi_invoke_votingapi($cache, 'calculate', $votes, $content_type, $content_id);
// Now, do the caching. Woo.
foreach ($cache as $tag=>$types) {
foreach ($types as $type=>$functions) {
foreach ($functions as $function=>$value) {
/**
* vote_cache_id patch. Entry not deleted, just getting updated.
*/
//$cached[] = _votingapi_insert_cache_result($content_type, $content_id, $value, $type, $tag, $function);
$cached[] = _votingapi_update_cache_result($content_type, $content_id, $value, $type, $tag, $function);
}
}
}
// Give other modules a chance to act on the results of the vote totaling.
votingapi_invoke_votingapi($cached, 'post calculate', $votes, $content_type, $content_id);
// If the actions module is enabled, hand off the voting results
// for possible node promotion, user banning, or what not.
if (module_exist('actions') && variable_get('votingapi_actions_mode', 'all') != 'none') {
_votingapi_process_actions($content_id, $content_type, $votes, $cached);
}
return $cached;
}
}
/**
* Update a cached aggregate vote for a given piece of content.
*
* vote_cache_id patch. Used instead of _votingapi_insert_cache_result(), to prevent
* vote_cache_id from updating each recalculation.
*
* @param $content_type
* A string identifying the type of content being rated. Node, comment, aggregator item, etc.
* @param $content_id
* The key ID of the content being rated.
* @param $value
* An int representing the aggregate value of the votes cast.
* @param $value_type
* An int representing the value_type shared by the aggregated votes.
* @param $tag
* A string to separate multiple voting criteria. For example, a voting system that rates software for 'stability'
* and 'features' would cast two votes, each with a different tag. If none is specified, the default 'vote' tag is used.
* @param $function
* The summary function being used to aggregate the votes. 'sum', 'count', and 'average' are used by votingapi.
* If the value_type is 'option', this field contains the key. Slightly ugly, but oh well.
* @return
* The resulting cached object.
*/
function _votingapi_update_cache_result($content_type, $content_id, $value, $value_type, $tag, $function) {
$vobj->content_type = $content_type;
$vobj->content_id = $content_id;
$vobj->value = $value;
$vobj->value_type = $value_type;
$vobj->tag = $tag;
$vobj->function = $function;
$vote_cache_id = db_result(db_query("SELECT vote_cache_id FROM {votingapi_cache} WHERE content_type = '%s' AND content_id = %d AND value_type = '%s' AND tag = '%s' AND function = '%s'", $vobj->content_type, $vobj->content_id, $vobj->value_type, $vobj->tag, $vobj->function));
if ($vote_cache_id) {
$vobj->vote_cache_id = $vote_cache_id;
db_query("UPDATE {votingapi_cache} SET value = %f WHERE vote_cache_id = %d", $vobj->value, $vobj->vote_cache_id);
} else {
$vobj->vote_cache_id = db_next_id('{votingapi_cache}');
db_query("INSERT INTO {votingapi_cache} (vote_cache_id, content_type, content_id, value, value_type, tag, function) VALUES (%d, '%s', %d, %f, '%s', '%s', '%s')",
$vobj->vote_cache_id, $vobj->content_type, $vobj->content_id, $vobj->value, $vobj->value_type, $vobj->tag, $vobj->function);
}
return $vobj;
}
Comments
Comment #1
ardee-1 commentedIs this still outstanding, 9 months later?
Comment #2
eaton commentedIndividual vote IDs are not preserved; this is by design. Imposing a full 'update' cycle would grow the amount of database chatter needed to cast votes dramatically.