You are here

function rate_update_8001 in Rate 8.2

Same name and namespace in other branches
  1. 8 rate.install \rate_update_8001()

Consolidates votes into new vote types.

File

./rate.install, line 64
Installation/Uninstallation functions for rate module.

Code

function rate_update_8001(&$sandbox) {

  // Ideally recreating the votes and results would go through th APIs
  // (deleting, creating, recalulating results), but as the number of votes can
  // grow quickly, the overhead of going through the API can quickly reach an
  // unreasonable amount of time for the hook to run (e.g. days), so we're
  // opting for the slightly less safe method of direct database updates. Also,
  // the module is still in an alpha state, so even having an upgrade path is a
  // nicety.
  $entityTypeManager = \Drupal::entityTypeManager();
  $voteStorage = $entityTypeManager
    ->getStorage('vote');
  $voteTypeStorage = $entityTypeManager
    ->getStorage('vote_type');
  $database = \Drupal::database();
  $oldVoteTypes = [
    'up',
    'down',
    'star1',
    'star2',
    'star3',
    'star4',
    'star5',
  ];
  if (!isset($sandbox['progress'])) {

    // Add the new vote types. Update hooks should always be run prior to
    // importing configurations, so these should not exist yet, but in the off-
    // chance that there was a failure partway through the update hook, we'll
    // check to ensure that the hook can be re-run.
    $voteType = $voteTypeStorage
      ->load('updown');
    if (!$voteType) {
      $voteTypeStorage
        ->create([
        'id' => 'updown',
        'label' => 'Up/Down',
        'value_type' => 'points',
      ])
        ->save();
    }
    $voteType = $voteTypeStorage
      ->load('fivestar');
    if (!$voteType) {
      $voteTypeStorage
        ->create([
        'id' => 'fivestar',
        'label' => 'Five star',
        'value_type' => 'points',
      ])
        ->save();
    }

    // Delete old voting results.
    $query = $database
      ->delete('votingapi_result');
    $query
      ->condition('type', $oldVoteTypes, 'IN');
    $query
      ->execute();

    // Update vote entities.
    $query = $database
      ->update('votingapi_vote');
    $query
      ->fields([
      'type' => 'updown',
      'value' => -1,
    ]);
    $query
      ->condition('type', 'down');
    $query
      ->execute();
    $query = $database
      ->update('votingapi_vote');
    $query
      ->fields([
      'type' => 'updown',
    ]);
    $query
      ->condition('type', 'up');
    $query
      ->execute();
    $query = $database
      ->update('votingapi_vote');
    $query
      ->fields([
      'type' => 'fivestar',
    ]);
    $query
      ->condition('type', 'star1');
    $query
      ->execute();
    $query = $database
      ->update('votingapi_vote');
    $query
      ->fields([
      'type' => 'fivestar',
      'value' => 2,
    ]);
    $query
      ->condition('type', 'star2');
    $query
      ->execute();
    $query = $database
      ->update('votingapi_vote');
    $query
      ->fields([
      'type' => 'fivestar',
      'value' => 3,
    ]);
    $query
      ->condition('type', 'star3');
    $query
      ->execute();
    $query = $database
      ->update('votingapi_vote');
    $query
      ->fields([
      'type' => 'fivestar',
      'value' => 4,
    ]);
    $query
      ->condition('type', 'star4');
    $query
      ->execute();
    $query = $database
      ->update('votingapi_vote');
    $query
      ->fields([
      'type' => 'fivestar',
      'value' => 5,
    ]);
    $query
      ->condition('type', 'star5');
    $query
      ->execute();

    // Ensure that any cached entities are flushed so that the results are
    // recalculated correctly.
    \Drupal::cache()
      ->deleteAll();
    $voteStorage
      ->resetCache();
    $entityTypeManager
      ->getStorage('vote_result')
      ->resetCache();

    // Initialize the batch.
    $sandbox['progress'] = 0;
    $sandbox['max'] = $voteStorage
      ->getAggregateQuery()
      ->groupBy('entity_type')
      ->groupBy('entity_id')
      ->accessCheck(FALSE)
      ->condition('type', [
      'updown',
      'fivestar',
    ], 'IN')
      ->count()
      ->execute();
  }

  // Recalculate all the voting results.
  if ($sandbox['max']) {
    $time = \Drupal::time()
      ->getRequestTime();
    $query = \Drupal::database()
      ->select('votingapi_vote', 'v')
      ->fields('v', [
      'type',
      'entity_type',
      'entity_id',
    ])
      ->groupBy('type')
      ->groupBy('entity_type')
      ->groupBy('entity_id')
      ->orderBy('type')
      ->orderBy('entity_type')
      ->orderBy('entity_id')
      ->range($sandbox['progress'], 1000);
    $query
      ->condition('type', [
      'updown',
      'fivestar',
    ], 'IN');
    $results = $query
      ->execute();
    while ($row = $results
      ->fetchAssoc()) {
      $fields = [
        'entity_id' => $row['entity_id'],
        'entity_type' => $row['entity_type'],
        'type' => 'updown',
        'timestamp' => $time,
      ];

      // Manual recalculation of voting results for the base Voting API and our
      // one result plugin.
      $query = $database
        ->select('votingapi_vote');
      $query
        ->condition('entity_type', $row['entity_type']);
      $query
        ->condition('entity_id', $row['entity_id']);
      $query
        ->condition('type', $row['type']);
      $count = $query
        ->countQuery()
        ->execute()
        ->fetchField();
      $database
        ->insert('votingapi_result')
        ->fields($fields + [
        'function' => 'vote_count',
        'value' => $count,
      ])
        ->execute();
      $query = $database
        ->select('votingapi_vote');
      $query
        ->addExpression('SUM(value)');
      $query
        ->condition('entity_type', $row['entity_type']);
      $query
        ->condition('entity_id', $row['entity_id']);
      $query
        ->condition('type', $row['type']);
      $sum = $query
        ->execute()
        ->fetchField();
      $database
        ->insert('votingapi_result')
        ->fields($fields + [
        'function' => 'vote_sum',
        'value' => $sum,
      ])
        ->execute();
      $average = $sum / $count;
      $database
        ->insert('votingapi_result')
        ->fields($fields + [
        'function' => 'vote_average',
        'value' => $average,
      ])
        ->execute();
      $query = $database
        ->select('votingapi_vote');
      $query
        ->condition('entity_type', $row['entity_type']);
      $query
        ->condition('entity_id', $row['entity_id']);
      $query
        ->condition('type', $row['type']);
      $query
        ->condition('value', 1);
      $value = $query
        ->countQuery()
        ->execute()
        ->fetchField();
      $database
        ->insert('votingapi_result')
        ->fields($fields + [
        'function' => 'rate_count_up',
        'value' => $value,
      ])
        ->execute();
      $sandbox['progress']++;
    }
  }
  $sandbox['#finished'] = empty($sandbox['max']) ? 1 : $sandbox['progress'] / $sandbox['max'];

  // Better message if running from  Drush.
  if (function_exists('drush_print')) {
    drush_print(t('@percent% of the results have been recalculated.', [
      '@percent' => round($sandbox['#finished'] * 100),
    ]));
  }
  if ($sandbox['#finished'] == 1) {

    // Delete the old vote types.
    foreach ($oldVoteTypes as $type) {
      $voteType = $voteTypeStorage
        ->load($type);
      if ($voteType) {
        $voteType
          ->delete();
      }
    }
    return t('Finished unifying vote types.');
  }
}