My setup:
Review content type with :
1) Entity reference field
2) fivestar field with target the reference field the votes are casted towards the reference and not the current review (as supported by the fivestar module)

all that is great but as the reviews need approval and might be deleted later on the votes are not calculated correctly later on because :
1) votingapi is set so that one use can cast multiple votes on same content and each vote will be considered a new one as one user can write different reviews and some of them might be accepted and some not

In order to simulate all you need to do is setup the votingapi as described above , then create a review and then delete the review. You can see that the votes are not deleted. The reason is :
1) in function _fivestar_cast_vote you are calling votingapi_select_votes and expect that the voting will handle it but it is not possible. Also when votingapi check what criteria it should add it always adds " REQUEST_TIME - timeset" , so even if you say that the votes casted from the user for this entity for 1hour will be treated as one vote , that still will fail because you can delete/disable the review after 1 day.
2) when you are inserting the votes you are using the same criteria and again expect the votingapi to handle it which as described above is not possible

so what i did was :
1) change in function _fivestar_field_helper and add soruce option so later on when a field is deleted/updates it knows exactly which votes it should delete or update
also remove the recalculation of the results cause the _fivestar_cast_vote does that so no need to repeat it
2) add the vote_source to the _fivestar_cast_vote as argument and made a few changes cuase the deletion should be done only when we have 0 value and no need to even try to select user votes when we are not going to delete them

so here is how the 2 function look now :
1) in fivestar.field.inc file :

function _fivestar_field_helper($entity_type, $entity, $field, $instance, $langcode, &$items, $op = '') {
  list ($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
  foreach ($items as $delta => $item) {
    if ((isset($entity->status) && !$entity->status) || $op == 'delete') {
      $rating = 0;
    }
    else {
      $rating = (isset($items[$delta]['rating'])) ? $items[$delta]['rating'] : 0;
    }
    $target = _fivestar_field_target($entity, $field, $instance, $item, $langcode);
    if (!empty($target)) {
      $sources = array(
        $entity_type,
        $bundle,
        $vid,
        $langcode,
        $delta,
      );
      $vote_source = implode(':', $sources);
      _fivestar_cast_vote($target['entity_type'], $target['entity_id'], $rating, $field['settings']['axis'], $entity->uid, TRUE, $vote_source);
    }
  }
}

2) in fivestar.module :

function _fivestar_cast_vote($entity_type, $id, $value, $tag = NULL, $uid = NULL, $skip_validation = FALSE, $vote_source = '') {
  global $user;
  $tag = empty($tag) ? 'vote' : $tag;
  $uid = isset($uid) ? $uid : $user->uid;
  // Bail out if the user's trying to vote on an invalid object.
  if (!$skip_validation && !fivestar_validate_target($entity_type, $id, $tag, $uid)) {
    return array();
  }
  // Sanity-check the incoming values.
  if (is_numeric($id) && is_numeric($value)) {
    if ($value > 100) {
      $value = 100;
    }

    // Get the user's current vote.
    $criteria = array('entity_type' => $entity_type, 'entity_id' => $id, 'tag' => $tag, 'uid' => $uid);
    // Add vote_source for cck fields.
    if (!empty($vote_source)) {
      $criteria['vote_source'] = $vote_source;
    }

    if ($value == 0) {
      // Select the votes we need to remove.
      $user_criteria = array();
      if (!$uid && empty($vote_source)) {
        // Get the unique identifier for the user (IP Address if anonymous).
        $user_criteria = votingapi_current_user_identifier();
      }
      $user_votes_criteria = $criteria + $user_criteria;
      $function = variable_get('votingapi_storage_module', 'votingapi') . '_votingapi_storage_select_votes';
      $user_votes = $function($user_votes_criteria, 0);
      votingapi_delete_votes($user_votes);
    }
    else {
      $votes = $criteria += array('value' => $value);
      votingapi_set_votes($votes);
    }

    // Moving the calculationg after saving/deleting the vote but before getting the votes.
    votingapi_recalculate_results($entity_type, $id);    
    return fivestar_get_votes($entity_type, $id, $tag, $uid);
  }
}

If you think I have done something wrong please write.

Kind Regards,
Dobromir

Comments

whiteph’s picture

Can you please test the 7.x-2.0-beta1 release to see if this issue still exists?

vflirt’s picture

I would but i get "The requested URL /files/projects/fivestar-7.x-2.0-beta1.zip was not found on this server."

whiteph’s picture

I've just downloaded the zip file onto my Mac, and downloaded & tested the tar file yesterday.

vflirt’s picture

Hi,

downloading must have been problem on drupal.org.
I downloaded fivestar-7.x-2.0-beta1 but i don't see any changes in what i have mentioned as an issue.
Still in fivestar.field.inc you are just calling _fivestar_cast_vote and that function itself does not recognize what would be the voting source so could you explain me how would you do the deletion.
So only looking trough the code ( i have not tested it but i see no point in doing any tests) i don't see any change that would make the votes be differed based on the entity.
Let me explain this so you can see :
1) node type A
2) node type "review" with reference field to A and rating field that has target of the reference field (I see that entityreference support is integrated in the module but using hook fivestar_target_info can be done with custom module as well)
3) so now create content a1 from type A and then create review for this content.
if you want to delete this review however then there is no way to know which votes are to be selected form the votingapi cause for cotnent a1 you can have 100 other votes in the table as well. So what votingapi module would do is either allow 1 vote per node in which case it will delete all votes from this user for content a1 and that is definetly not what is desired , allow votes from same user for same content case within 5 min (or other configurable interval) to be treated as same vote but then you are deleting the review out of this interval so no votes will be selected for deletion. The only way for the votingapi to know which votes to select and then you delete them is by specifying the source as i have suggested in my comment.
That is not the only place though as there is ajax vote option for the widget so that functionality probably will have to be copied there as well but as i do not have ajax voting allowed i cannot test and provide fix for there.

Kind Regards,
Dobromir

end user’s picture

I just ran into this after setting Voting API (Registered user vote rollover) to allow multiple voting.

Remove the users review node(s) that have votes on them and the votes are not removed.

Luckily this is a test site as I think removing the nodes really broked the voting results and some voting fields don't even show the results anymore.

What tables in the DB do I need to empty to remove all voting results? I have about 24 fields and have no desire to recreate them again lol.

end user’s picture

Ok so I used the above code and seems to be working with a few test nodes and about 23 fivestar fields. I'll do some more testing with lots of test node and see how it works out.

I can see the new info in the vote_source cell in the votingapi_vote table. Once I delete the node this info is removed as is the info in the votingapi_cache and field_revision_field_example_field and field_data_field_example_field.

end user’s picture

After more testing the code in the first post seems to be working and didn't see any problems with count and vote % calculations. This is tested on the 2014-Mar-24 dev release.

end user’s picture

Ok so ran into a small problem. I didn't test it with users editing their own content but if I log in as admin when I make changes to the node it increases the vote count every time the node is re saved. In my situation this might not matter as users can't edit their review nodes but If I ever had to change the node on request it might not work unless I change it through phpmyadmin.

Ok in each field settings I see this "Allow users to re-vote on already voted content" Is this mean users can't change their vote when editing a review node/comment or does it mean the user can't vote again on the target node when creating a new review node/comment.

I'd test this but I have 20+ fields and would be a pain in the ass to change each one just to test.

end user’s picture

Ok after some more testing With Registered user vote rollover set to Immediately any time Admin or the User edits the node in any way the vote count it increased. So if there are 3 votes that come from a review node and once the review node is edited the vote count goes up one point.

Setting With Registered user vote rollover to anything but Immediately the rating then can be changed and the votes count doesn't increase. I guess this will do for now along with Edit Limit module I could allow review edits for a day then the user will have to create a new review. This would also allow the admin to fix any changes on request by the node creator.

adanielyan’s picture

vflirt, end user, were you guys able to find a solution?

end user’s picture

Its been a while and that was one complicated site to build but I only did what I posted in my last post. The site is no longer around. This is the first time I realized that as much as I love Drupal using so many modules and module fixes/hacks would have made maintenance a nightmare if the site got popular.

dbt102’s picture

Please test with 7.x-2.2 release and report back, as there have been a lot of fixes applied since the issue was first reported in on Oct 2013.

dbt102’s picture

Status: Active » Postponed (maintainer needs more info)