While working on the next release of my open-source Drupal module Reference Links, I needed to delete all votes for links attached to a node when the node itself was being deleted. Here, remember the votes were stored for the links attached to the nodes (and not the nodes themselves). As there could be (and almost always would be) multiple links attached to the nodes, the problem was either finding a way to delete votes for all links together, or iterate over the links to delete each individual link’s votes independently. The latter approach clearly was highly undesirable.

A quick Google search threw up nothing related to what I was looking. There was of-course the Voting API’s votingapi_delete_votes($votes = array()) method, which accepts multiple vote objects to be deleted as an array, the problem was getting votes for different links into a single array without hitting the database for each individual link’s votes independently.

The documentation for votingapi_select_votes($criteria) nowhere mentions whether it is supports passing in multiple content ids for fetching votes together, and if yes, how should those ids be passed. Fortunately, finding this out was not too difficult.

Probably 3-4 recursive drill-downs into the internal Voting API code led me to the internal helper method of this module: _votingapi_query_builder($name, $value, &$query, &$args, $col_is_string) and I was immediately ecstatic seeing the following code at the beginning of the method:

 

{syntaxhighlighter brush: php;fontsize: 100; first-line: 1; } if (!isset($value)) {
// Do nothing
}
elseif ($name === ‘timestamp’) {
……
}
else {
if (is_array($value)) {
if ($col_is_string) {
$query .= ” AND $name IN (” . db_placeholders($value, ‘varchar’) . “)”;
$args = array_merge($args, $value);
….
{/syntaxhighlighter}

That clearly indicated that Voting API allowed passing arrays as any of its search arguments inside the $criteria for the votingapi_select_votes($criteria) method.

Having figured this out, the rest of the code was trivial. Here’s the source-code I ended up employing for deleting votes of all links together in one-go, related to the node being deleted (sourced from the Reference Links module itself):

 

{syntaxhighlighter brush: php;fontsize: 100; first-line: 1; }$result = db_query(“SELECT lid FROM {reference_links} WHERE nid=%d”, $node->nid);
$ids = array();
while ($link = db_fetch_object($result)) {
$ids[] = $link->lid;
}

$criteria[‘content_type’] = ‘reference_links’;
$criteria[‘content_id’] = $ids;
$votes = votingapi_select_votes($criteria);
votingapi_delete_votes($votes);

db_query(“DELETE FROM {reference_links} WHERE nid=%d”, $node->nid);
{/syntaxhighlighter}

Basically the code assembles an array of all link ids whose votes are to be deleted, constructs a $criteria object to fetch votes for these ids (the content_type is important above), fetches the votes, and finally requests the Voting API to delete all these votes. It was simpler in the end than I expected it to be!!!