Projet

Général

Profil

Paste
Télécharger (22 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / votingapi / votingapi.module @ 7942932f

1
<?php
2

    
3
/**
4
 * @file
5
 * A generalized voting API for Drupal.
6
 *
7
 * Maintains and provides an interface for a shared bin of vote and rating
8
 * data. Modules can cast votes with arbitrary properties and VotingAPI will
9
 * total them automatically. Support for basic anonymous voting by IP address,
10
 * multi-criteria voting, arbitrary aggregation functions, etc.
11
 */
12

    
13
/**
14
 * Implements of hook_menu().
15
 */
16
function votingapi_menu() {
17
  $items = array();
18
  $items['admin/config/search/votingapi'] = array(
19
    'title' => 'Voting API',
20
    'description' => 'Configure sitewide settings for user-generated ratings and votes.',
21
    'page callback' => 'drupal_get_form',
22
    'page arguments' => array('votingapi_settings_form'),
23
    'access callback' => 'user_access',
24
    'access arguments' => array('administer voting api'),
25
    'file' => 'votingapi.admin.inc',
26
    'type' => MENU_NORMAL_ITEM
27
  );
28

    
29
  if (module_exists('devel_generate')) {
30
    $items['admin/config/development/generate/votingapi'] = array(
31
      'title' => 'Generate votes',
32
      'description' => 'Generate a given number of votes on site content. Optionally delete existing votes.',
33
      'page callback' => 'drupal_get_form',
34
      'page arguments' => array('votingapi_generate_votes_form'),
35
      'access arguments' => array('administer voting api'),
36
      'file' => 'votingapi.admin.inc',
37
    );
38
  }
39

    
40
  return $items;
41
}
42

    
43
/**
44
 * Implements hook_permission().
45
 */
46
function votingapi_permission() {
47
  return array(
48
      'administer voting api' => array(
49
          'title' => t('Administer Voting API'),
50
      ),
51
  );
52
}
53

    
54
/**
55
 * Implements of hook_views_api().
56
 */
57
function votingapi_views_api() {
58
  return array(
59
    'api' => 3,
60
    'path' => drupal_get_path('module', 'votingapi') . '/views',
61
  );
62
}
63

    
64
/**
65
 * Implements of hook_cron().
66
 *
67
 * Allows db-intensive recalculations to be deferred until cron-time.
68
 */
69
function votingapi_cron() {
70
  if (variable_get('votingapi_calculation_schedule', 'immediate') == 'cron') {
71
    $time = REQUEST_TIME;
72
    $last_cron = variable_get('votingapi_last_cron', 0);
73
    $result = db_query('SELECT DISTINCT entity_type, entity_id FROM {votingapi_vote} WHERE timestamp > :timestamp', array(':timestamp' => $last_cron));
74
    foreach ($result as $content) {
75
      votingapi_recalculate_results($content->entity_type, $content->entity_id, TRUE);
76
    }
77

    
78
    variable_set('votingapi_last_cron', $time);
79
  }
80

    
81
  _votingapi_cron_delete_orphaned();
82
}
83

    
84
/**
85
 * Cast a vote on a particular piece of content.
86
 *
87
 * This function does most of the heavy lifting needed by third-party modules
88
 * based on VotingAPI. Handles clearing out old votes for a given piece of
89
 * content, saving the incoming votes, and re-tallying the results given the
90
 * new data.
91
 *
92
 * Modules that need more explicit control can call votingapi_add_votes() and
93
 * manage the deletion/recalculation tasks manually.
94
 *
95
 * @param $votes
96
 *   An array of votes, each with the following structure:
97
 *   $vote['entity_type']  (Optional, defaults to 'node')
98
 *   $vote['entity_id']    (Required)
99
 *   $vote['value_type']    (Optional, defaults to 'percent')
100
 *   $vote['value']         (Required)
101
 *   $vote['tag']           (Optional, defaults to 'vote')
102
 *   $vote['uid']           (Optional, defaults to current user)
103
 *   $vote['vote_source']   (Optional, defaults to current IP)
104
 *   $vote['timestamp']     (Optional, defaults to REQUEST_TIME)
105
 * @param $criteria
106
 *   A keyed array used to determine what votes will be deleted when the current
107
 *   vote is cast. If no value is specified, all votes for the current content
108
 *   by the current user will be reset. If an empty array is passed in, no votes
109
 *   will be reset and all incoming votes will be saved IN ADDITION to existing
110
 *   ones.
111
 *   $criteria['vote_id']     (If this is set, all other keys are skipped)
112
 *   $criteria['entity_type']
113
 *   $criteria['entity_type']
114
 *   $criteria['value_type']
115
 *   $criteria['tag']
116
 *   $criteria['uid']
117
 *   $criteria['vote_source']
118
 *   $criteria['timestamp']   (If this is set, records with timestamps
119
 *      GREATER THAN the set value will be selected.)
120
 * @return
121
 *   An array of vote result records affected by the vote. The values are
122
 *   contained in a nested array keyed thusly:
123
 *   $value = $results[$entity_type][$entity_id][$tag][$value_type][$function]
124
 *
125
 * @see votingapi_add_votes()
126
 * @see votingapi_recalculate_results()
127
 */
128
function votingapi_set_votes(&$votes, $criteria = NULL) {
129
  $touched = array();
130
  if (!empty($votes['entity_id'])) {
131
    $votes = array($votes);
132
  }
133

    
134
  // Allow other modules to modify or unset/remove votes.
135
  // module_invoke_all does not allow passing variables by reference
136
  // http://api.drupal.org/api/drupal/includes%21module.inc/function/module_invoke_all/7#comment-35778
137
  drupal_alter(array('votingapi_preset_votes'), $votes);
138
  // Handle clearing out old votes if they exist.
139
  if (!isset($criteria)) {
140
    // If the calling function didn't explicitly set criteria for vote deletion,
141
    // build up the delete queries here.
142
    foreach ($votes as $vote) {
143
      $tmp = $vote + votingapi_current_user_identifier();
144
      if (isset($tmp['value'])) {
145
        unset($tmp['value']);
146
      }
147
      votingapi_delete_votes(votingapi_select_votes($tmp));
148
    }
149
  }
150
  elseif (is_array($criteria)) {
151
    // The calling function passed in an explicit set of delete filters.
152
    if (!empty($criteria['entity_id'])) {
153
      $criteria = array($criteria);
154
    }
155
    foreach ($criteria as $c) {
156
      votingapi_delete_votes(votingapi_select_votes($c));
157
    }
158
  }
159

    
160
  foreach ($votes as $key => $vote) {
161
    _votingapi_prep_vote($vote);
162
    $votes[$key] = $vote; // Is this needed? Check to see how PHP4 handles refs.
163
  }
164

    
165
  // Cast the actual votes, inserting them into the table.
166
  votingapi_add_votes($votes);
167

    
168
  foreach ($votes as $vote) {
169
    $touched[$vote['entity_type']][$vote['entity_id']] = TRUE;
170
  }
171

    
172
  if (variable_get('votingapi_calculation_schedule', 'immediate') != 'cron') {
173
    foreach ($touched as $type => $ids) {
174
      foreach ($ids as $id => $bool) {
175
        $touched[$type][$id] = votingapi_recalculate_results($type, $id);
176
      }
177
    }
178
  }
179
  return $touched;
180
}
181

    
182
/**
183
 * Generate a proper identifier for the current user: if they have an account,
184
 * return their UID. Otherwise, return their IP address.
185
 */
186
function votingapi_current_user_identifier() {
187
  global $user;
188
  $criteria = array('uid' => $user->uid);
189
  if (!$user->uid) {
190
    $criteria['vote_source'] = ip_address();
191
  }
192
  return $criteria;
193
}
194

    
195
/**
196
 * Implements of hook_votingapi_storage_add_vote().
197
 */
198
function votingapi_votingapi_storage_add_vote(&$vote) {
199
  drupal_write_record('votingapi_vote', $vote);
200
}
201

    
202
/**
203
 * Implements of hook_votingapi_storage_delete_votes().
204
 */
205
function votingapi_votingapi_storage_delete_votes($votes, $vids) {
206
  db_delete('votingapi_vote')->condition('vote_id', $vids, 'IN')->execute();
207
}
208

    
209
/**
210
 * Implements of hook_votingapi_storage_select_votes().
211
 */
212
function votingapi_votingapi_storage_select_votes($criteria, $limit) {
213
  $query = db_select('votingapi_vote')->fields('votingapi_vote');
214
  foreach ($criteria as $key => $value) {
215
    if ($key == 'timestamp') {
216
      $query->condition($key, $value, '>');
217
    }
218
    else {
219
      $query->condition($key, $value, is_array($value) ? 'IN' : '=');
220
    }
221
  }
222
  if (!empty($limit)) {
223
    $query->range(0, $limit);
224
  }
225
  return $query->execute()->fetchAll(PDO::FETCH_ASSOC);
226
}
227

    
228
/**
229
 * Save a collection of votes to the database.
230
 *
231
 * This function does most of the heavy lifting for VotingAPI the main
232
 * votingapi_set_votes() function, but does NOT automatically triger re-tallying
233
 * of results. As such, it's useful for modules that must insert their votes in
234
 * separate batches without triggering unecessary recalculation.
235
 *
236
 * Remember that any module calling this function implicitly assumes responsibility
237
 * for calling votingapi_recalculate_results() when all votes have been inserted.
238
 *
239
 * @param $votes
240
 *   A vote or array of votes, each with the following structure:
241
 *   $vote['entity_type']  (Optional, defaults to 'node')
242
 *   $vote['entity_id']    (Required)
243
 *   $vote['value_type']    (Optional, defaults to 'percent')
244
 *   $vote['value']         (Required)
245
 *   $vote['tag']           (Optional, defaults to 'vote')
246
 *   $vote['uid']           (Optional, defaults to current user)
247
 *   $vote['vote_source']   (Optional, defaults to current IP)
248
 *   $vote['timestamp']     (Optional, defaults to REQUEST_TIME)
249
 * @return
250
 *   The same votes, with vote_id keys populated.
251
 *
252
 * @see votingapi_set_votes()
253
 * @see votingapi_recalculate_results()
254
 */
255
function votingapi_add_votes(&$votes) {
256
  if (!empty($votes['entity_id'])) {
257
    $votes = array($votes);
258
  }
259
  $function = variable_get('votingapi_storage_module', 'votingapi') . '_votingapi_storage_add_vote';
260
  foreach ($votes as $key => $vote) {
261
    _votingapi_prep_vote($vote);
262
    $function($vote);
263
    $votes[$key] = $vote;
264
  }
265
  module_invoke_all('votingapi_insert', $votes);
266
  return $votes;
267
}
268

    
269
/**
270
 * Save a bundle of vote results to the database.
271
 *
272
 * This function is called by votingapi_recalculate_results() after tallying
273
 * the values of all cast votes on a piece of content. This function will be of
274
 * little use for most third-party modules, unless they manually insert their
275
 * own result data.
276
 *
277
 * @param vote_results
278
 *   An array of vote results, each with the following properties:
279
 *   $vote_result['entity_type']
280
 *   $vote_result['entity_id']
281
 *   $vote_result['value_type']
282
 *   $vote_result['value']
283
 *   $vote_result['tag']
284
 *   $vote_result['function']
285
 *   $vote_result['timestamp']   (Optional, defaults to REQUEST_TIME)
286
 */
287
function votingapi_add_results($vote_results = array()) {
288
  if (!empty($vote_results['entity_id'])) {
289
    $vote_results = array($vote_results);
290
  }
291

    
292
  foreach ($vote_results as $vote_result) {
293
    $vote_result['timestamp'] = REQUEST_TIME;
294
    drupal_write_record('votingapi_cache', $vote_result);
295
  }
296
}
297

    
298
/**
299
 * Delete votes from the database.
300
 *
301
 * @param $votes
302
 *   An array of votes to delete. Minimally, each vote must have the 'vote_id'
303
 *   key set.
304
 */
305
function votingapi_delete_votes($votes = array()) {
306
  if (!empty($votes)) {
307
    module_invoke_all('votingapi_delete', $votes);
308
    $vids = array();
309
    foreach ($votes as $vote) {
310
      $vids[] = $vote['vote_id'];
311
    }
312
    $function = variable_get('votingapi_storage_module', 'votingapi') . '_votingapi_storage_delete_votes';
313
    $function($votes, $vids);
314
  }
315
}
316

    
317
/**
318
 * Delete cached vote results from the database.
319
 *
320
 * @param $vote_results
321
 *   An array of vote results to delete. Minimally, each vote result must have
322
 *   the 'vote_cache_id' key set.
323
 */
324
function votingapi_delete_results($vote_results = array()) {
325
  if (!empty($vote_results)) {
326
    $vids = array();
327
    foreach ($vote_results as $vote) {
328
      $vids[] = $vote['vote_cache_id'];
329
    }
330
    db_delete('votingapi_cache')->condition('vote_cache_id', $vids, 'IN')->execute();
331
  }
332
}
333

    
334
/**
335
 * Select individual votes from the database.
336
 *
337
 * @param $criteria
338
 *   A keyed array used to build the select query. Keys can contain
339
 *   a single value or an array of values to be matched.
340
 *   $criteria['vote_id']       (If this is set, all other keys are skipped)
341
 *   $criteria['entity_id']
342
 *   $criteria['entity_type']
343
 *   $criteria['value_type']
344
 *   $criteria['tag']
345
 *   $criteria['uid']
346
 *   $criteria['vote_source']
347
 *   $criteria['timestamp']   (If this is set, records with timestamps
348
 *      GREATER THAN the set value will be selected.)
349
 * @param $limit
350
 *   An optional integer specifying the maximum number of votes to return.
351
 * @return
352
 *   An array of votes matching the criteria.
353
 */
354
function votingapi_select_votes($criteria = array(), $limit = 0) {
355
  $window = -1;
356
  if (empty($criteria['uid']) || $criteria['uid'] == 0) {
357
    if (!empty($criteria['vote_source'])) {
358
      $window = variable_get('votingapi_anonymous_window', 86400);
359
    }
360
  } else {
361
    $window = variable_get('votingapi_user_window', -1);
362
  }
363
  if ($window >= 0) {
364
    $criteria['timestamp'] = REQUEST_TIME - $window;
365
  }
366
  $function = variable_get('votingapi_storage_module', 'votingapi') . '_votingapi_storage_select_votes';
367
  return $function($criteria, $limit);
368
}
369

    
370
/**
371
 * Select cached vote results from the database.
372
 *
373
 * @param $criteria
374
 *   A keyed array used to build the select query. Keys can contain
375
 *   a single value or an array of values to be matched.
376
 *   $criteria['vote_cache_id']     (If this is set, all other keys are skipped)
377
 *   $criteria['entity_id']
378
 *   $criteria['entity_type']
379
 *   $criteria['value_type']
380
 *   $criteria['tag']
381
 *   $criteria['function']
382
 *   $criteria['timestamp']   (If this is set, records with timestamps
383
 *      GREATER THAN the set value will be selected.)
384
 * @param $limit
385
 *   An optional integer specifying the maximum number of votes to return.
386
 * @return
387
 *   An array of vote results matching the criteria.
388
 */
389
function votingapi_select_results($criteria = array(), $limit = 0) {
390
  $query = db_select('votingapi_cache')->fields('votingapi_cache');
391
  foreach ($criteria as $key => $value) {
392
    $query->condition($key, $value, is_array($value) ? 'IN' : '=');
393
  }
394
  if (!empty($limit)) {
395
    $query->range(0, $limit);
396
  }
397
  return $query->execute()->fetchAll(PDO::FETCH_ASSOC);
398
}
399

    
400
/**
401
 * Recalculates the aggregate results of all votes for a piece of content.
402
 *
403
 * Loads all votes for a given piece of content, then calculates and caches the
404
 * aggregate vote results. This is only intended for modules that have assumed
405
 * responsibility for the full voting cycle: the votingapi_set_vote() function
406
 * recalculates automatically.
407
 *
408
 * @param $entity_type
409
 *   A string identifying the type of content being rated. Node, comment,
410
 *   aggregator item, etc.
411
 * @param $entity_id
412
 *   The key ID of the content being rated.
413
 * @return
414
 *   An array of the resulting votingapi_cache records, structured thusly:
415
 *   $value = $results[$ag][$value_type][$function]
416
 *
417
 * @see votingapi_set_votes()
418
 */
419
function votingapi_recalculate_results($entity_type, $entity_id, $force_calculation = FALSE) {
420
  // if we're operating in cron mode, and the 'force recalculation' flag is NOT set,
421
  // bail out. The cron run will pick up the results.
422

    
423
  if (variable_get('votingapi_calculation_schedule', 'immediate') != 'cron' || $force_calculation == TRUE) {
424
    $query = db_delete('votingapi_cache')
425
      ->condition('entity_type', $entity_type)
426
      ->condition('entity_id', $entity_id)
427
      ->execute();
428

    
429
    $function = variable_get('votingapi_storage_module', 'votingapi') . '_votingapi_storage_standard_results';
430
    // Bulk query to pull the majority of the results we care about.
431
    $cache = $function($entity_type, $entity_id);
432

    
433
    // Give other modules a chance to alter the collection of votes.
434
    drupal_alter('votingapi_results', $cache, $entity_type, $entity_id);
435

    
436
    // Now, do the caching. Woo.
437
    $cached = array();
438
    foreach ($cache as $tag => $types) {
439
      foreach ($types as $type => $functions) {
440
        foreach ($functions as $function => $value) {
441
          $cached[] = array(
442
            'entity_type' => $entity_type,
443
            'entity_id' => $entity_id,
444
            'value_type' => $type,
445
            'value' => $value,
446
            'tag' => $tag,
447
            'function' => $function,
448
          );
449
        }
450
      }
451
    }
452
    votingapi_add_results($cached);
453

    
454
    // Give other modules a chance to act on the results of the vote totaling.
455
    module_invoke_all('votingapi_results', $cached, $entity_type, $entity_id);
456

    
457
    return $cached;
458
  }
459
}
460

    
461

    
462
/**
463
 * Returns metadata about tags, value_types, and results defined by vote modules.
464
 *
465
 * If your module needs to determine what existing tags, value_types, etc., are
466
 * being supplied by other modules, call this function. Querying the votingapi
467
 * tables for this information directly is discouraged, as values may not appear
468
 * consistently. (For example, 'average' does not appear in the cache table until
469
 * votes have actually been cast in the cache table.)
470
 *
471
 * Three major bins of data are stored: tags, value_types, and functions. Each
472
 * entry in these bins is keyed by the value stored in the actual VotingAPI
473
 * tables, and contains an array with (minimally) 'name' and 'description' keys.
474
 * Modules can add extra keys to their entries if desired.
475
 *
476
 * This metadata can be modified or expanded using hook_votingapi_metadata_alter().
477
 *
478
 * @return
479
 *   An array of metadata defined by VotingAPI and altered by vote modules.
480
 *
481
 * @see hook_votingapi_metadata_alter()
482
 */
483
function votingapi_metadata($reset = FALSE) {
484
  static $data;
485
  if ($reset || !isset($data)) {
486
    $data = array(
487
      'tags' => array(
488
        'vote' => array(
489
          'name' => t('Normal vote'),
490
          'description' => t('The default tag for votes on content. If multiple votes with different tags are being cast on a piece of content, consider casting a "summary" vote with this tag as well.'),
491
        ),
492
      ),
493
      'value_types' => array(
494
        'percent' => array(
495
          'name' => t('Percent'),
496
          'description' => t('Votes in a specific range. Values are stored in a 1-100 range, but can be represented as any scale when shown to the user.'),
497
        ),
498
        'points' => array(
499
          'name' => t('Points'),
500
          'description' => t('Votes that contribute points/tokens/karma towards a total. May be positive or negative.'),
501
        ),
502
      ),
503
      'functions' => array(
504
        'count' => array(
505
          'name' => t('Number of votes'),
506
          'description' => t('The number of votes cast for a given piece of content.'),
507
        ),
508
        'average' => array(
509
          'name' => t('Average vote'),
510
          'description' => t('The average vote cast on a given piece of content.'),
511
        ),
512
        'sum' => array(
513
          'name' => t('Total score'),
514
          'description' => t('The sum of all votes for a given piece of content.'),
515
          'value_types' => array('points'),
516
        ),
517
      ),
518
    );
519

    
520
    drupal_alter('votingapi_metadata', $data);
521
  }
522

    
523
  return $data;
524
}
525

    
526
/**
527
 * Builds the default VotingAPI results for the three supported voting styles.
528
 */
529
function votingapi_votingapi_storage_standard_results($entity_type, $entity_id) {
530
  $cache = array();
531

    
532
  $sql  = "SELECT v.value_type, v.tag, ";
533
  $sql .= "COUNT(v.value) as value_count, SUM(v.value) as value_sum  ";
534
  $sql .= "FROM {votingapi_vote} v ";
535
  $sql .= "WHERE v.entity_type = :type AND v.entity_id = :id AND v.value_type IN ('points', 'percent') ";
536
  $sql .= "GROUP BY v.value_type, v.tag";
537
  $results = db_query($sql, array(':type' => $entity_type, ':id' => $entity_id));
538

    
539
  foreach ($results as $result) {
540
    $cache[$result->tag][$result->value_type]['count'] = $result->value_count;
541
    $cache[$result->tag][$result->value_type]['average'] = $result->value_sum / $result->value_count;
542
    if ($result->value_type == 'points') {
543
      $cache[$result->tag][$result->value_type]['sum'] = $result->value_sum;
544
    }
545
  }
546

    
547
  $sql  = "SELECT v.tag, v.value, v.value_type, COUNT(1) AS score ";
548
  $sql .= "FROM {votingapi_vote} v ";
549
  $sql .= "WHERE v.entity_type = :type AND v.entity_id = :id AND v.value_type = 'option' ";
550
  $sql .= "GROUP BY v.value, v.tag, v.value_type";
551
  $results = db_query($sql, array(':type' => $entity_type, ':id' => $entity_id));
552

    
553
  foreach ($results as $result) {
554
    $cache[$result->tag][$result->value_type]['option-' . $result->value] = $result->score;
555
  }
556

    
557
  return $cache;
558
}
559

    
560
/**
561
 * Retrieve the value of the first vote matching the criteria passed in.
562
 */
563
function votingapi_select_single_vote_value($criteria = array()) {
564
  if ($results = votingapi_select_votes($criteria, 1)) {
565
    return $results[0]['value'];
566
  }
567
}
568

    
569
/**
570
 * Retrieve the value of the first result matching the criteria passed in.
571
 */
572
function votingapi_select_single_result_value($criteria = array()) {
573
  if ($results = votingapi_select_results($criteria, 1)) {
574
    return $results[0]['value'];
575
  }
576
}
577

    
578
/**
579
 * Populate the value of any unset vote properties.
580
 *
581
 * @param $vote
582
 *   A single vote.
583
 * @return
584
 *   A vote object with all required properties filled in with
585
 *   their default values.
586
 */
587
function _votingapi_prep_vote(&$vote) {
588
  global $user;
589
  if (empty($vote['prepped'])) {
590
    $vote += array(
591
      'entity_type' => 'node',
592
      'value_type' => 'percent',
593
      'tag' => 'vote',
594
      'uid' => $user->uid,
595
      'timestamp' => REQUEST_TIME,
596
      'vote_source' => ip_address(),
597
      'prepped' => TRUE
598
    );
599
  }
600
}
601

    
602
/**
603
 * Implements hook_entity_delete().
604
 *
605
 * Delete all votes and cache entries for the deleted entities
606
 */
607
function votingapi_entity_delete($entity, $type) {
608
  $ids = entity_extract_ids($type, $entity);
609
  $id = array($ids[0]);
610
  _votingapi_delete_cache_by_entity($id, $type);
611
  _votingapi_delete_votes_by_entity($id, $type);
612
}
613

    
614
/**
615
 * Helper function to delete all cache entries on given entities.
616
 *
617
 * @param array entity ids
618
 * @param string entity type
619
 */
620
function _votingapi_delete_cache_by_entity($entity_ids, $type) {
621
  $result = db_select('votingapi_cache', 'v')
622
    ->fields('v', array('vote_cache_id'))
623
    ->condition('entity_type', $type)
624
    ->condition('entity_id', $entity_ids)
625
    ->execute();
626
  $votes = array();
627
  foreach ($result as $row) {
628
    $votes[]['vote_cache_id'] = $row->vote_cache_id;
629
  }
630
  votingapi_delete_results($votes);
631
}
632

    
633
/**
634
 * Helper function to delete all votes on given entities.
635
 *
636
 * @param array entity ids
637
 * @param string entity type
638
 */
639
function _votingapi_delete_votes_by_entity($entity_ids, $type) {
640
  $result = db_select('votingapi_vote', 'v')
641
    ->fields('v', array('vote_id', 'entity_type', 'entity_id'))
642
    ->condition('entity_type', $type)
643
    ->condition('entity_id', $entity_ids)
644
    ->execute();
645
  $votes = array();
646
  foreach ($result as $row) {
647
    $votes[] = (array) $row;
648
  }
649
  votingapi_delete_votes($votes);
650
}
651

    
652
/**
653
 * Delete votes and cache entries for a number of entities in the queue.
654
 */
655
function _votingapi_cron_delete_orphaned() {
656
  $queue = DrupalQueue::get('VotingAPIOrphaned');
657
  $limit = variable_get('votingapi_cron_orphaned_max', 50);
658
  $done = 0;
659
  while (($item = $queue->claimItem()) && $done++ < $limit) {
660
    _votingapi_delete_cache_by_entity(array($item->data['entity_id']), $item->data['entity_type']);
661
    _votingapi_delete_votes_by_entity(array($item->data['entity_id']), $item->data['entity_type']);
662
    $queue->deleteItem($item);
663
  }
664
}