You are here

public function FlagCountManager::decrementFlagCounts in Flag 8.4

Decrements count of flagged entities.

Parameters

\Drupal\flag\Event\UnflaggingEvent $event: The unflagging event.

File

src/FlagCountManager.php, line 221

Class

FlagCountManager
Class FlagCountManager.

Namespace

Drupal\flag

Code

public function decrementFlagCounts(UnflaggingEvent $event) {
  $flaggings_count = [];
  $flag_ids = [];
  $entity_ids = [];
  $flaggings = $event
    ->getFlaggings();

  // Attempt to optimize the amount of queries that need to be executed if
  // a lot of flaggings are deleted. Build a list of flags and entity_ids
  // that will need to be updated. Entity type is ignored since one flag is
  // specific to a given entity type.
  foreach ($flaggings as $flagging) {
    $flag_id = $flagging
      ->getFlagId();
    $entity_id = $flagging
      ->getFlaggableId();
    $flag_ids[$flag_id] = $flag_id;
    $entity_ids[$entity_id] = $entity_id;
    if (!isset($flaggings_count[$flag_id][$entity_id])) {
      $flaggings_count[$flag_id][$entity_id] = 1;
    }
    else {
      $flaggings_count[$flag_id][$entity_id]++;
    }
    $this
      ->resetLoadedCounts($flagging
      ->getFlaggable(), $flagging
      ->getFlag());
  }

  // Build a query that fetches the count for all flag and entity ID
  // combinations.
  $result = $this->connection
    ->select('flag_counts')
    ->fields('flag_counts', [
    'flag_id',
    'entity_type',
    'entity_id',
    'count',
  ])
    ->condition('flag_id', $flag_ids, 'IN')
    ->condition('entity_id', $entity_ids, 'IN')
    ->execute();
  $to_delete = [];
  foreach ($result as $row) {

    // The query above could fetch combinations that are not being deleted
    // skip them now.
    // Most cases will either delete flaggings of a single flag or a single
    // entity where that does not happen.
    if (!isset($flaggings_count[$row->flag_id][$row->entity_id])) {
      continue;
    }
    if ($row->count <= $flaggings_count[$row->flag_id][$row->entity_id]) {

      // If all flaggings for the given flag and entity are deleted, delete
      // the row.
      $to_delete[$row->flag_id][] = $row->entity_id;
    }
    else {

      // Otherwise, update the count.
      $this->connection
        ->update('flag_counts')
        ->expression('count', 'count - :decrement', [
        ':decrement' => $flaggings_count[$row->flag_id][$row->entity_id],
      ])
        ->condition('flag_id', $row->flag_id)
        ->condition('entity_id', $row->entity_id)
        ->execute();
    }
  }

  // Execute a delete query per flag.
  foreach ($to_delete as $flag_id => $entity_ids) {
    $this->connection
      ->delete('flag_counts')
      ->condition('flag_id', $flag_id)
      ->condition('entity_id', $entity_ids, 'IN')
      ->execute();
  }
}