diff --git a/flag.module b/flag.module index e6a2467..8796c75 100644 --- a/flag.module +++ b/flag.module @@ -7,7 +7,6 @@ define('FLAG_API_VERSION', 3); -use Drupal\Core\Access\AccessResult; use Drupal\node\NodeInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; @@ -221,20 +220,14 @@ function flag_user_delete(UserInterface $account) { * Shared helper for user account cancellation or deletion. */ function flag_user_account_removal(UserInterface $account) { - /** var \Drupal\flag\FlagServiceInterface $flag_service */ + /** @var \Drupal\flag\FlagServiceInterface $flag_service */ $flag_service = \Drupal::service('flag'); // Remove flags by this user. - $flaggings = $flag_service->getFlaggings(NULL, NULL, $account); - foreach ($flaggings as $flagging_id => $flagging) { - $flag_service->unflag($flagging->getFlag(), $flagging->getFlaggable(), $account); - } + $flag_service->unflagAll(NULL, $account); // Remove flags that have been done to this user. - $flaggings = $flag_service->getFlaggings(NULL, $account); - foreach ($flaggings as $flagging_id => $flagging) { - $flag_service->unflag($flagging->getFlag(), $flagging->getFlaggable()); - } + $flag_service->unflagAll($account); } /** diff --git a/src/FlagService.php b/src/FlagService.php index 634300a..5fc0a32 100644 --- a/src/FlagService.php +++ b/src/FlagService.php @@ -276,6 +276,25 @@ class FlagService implements FlagServiceInterface { /** * {@inheritdoc} */ + public function unflagAll(EntityInterface $entity = NULL, AccountInterface $account = NULL) { + $flaggings = $this->getFlaggings(NULL, $entity, $account); + + /** @var \Drupal\flag\FlaggingInterface $flagging */ + foreach ($flaggings as $flagging_id => $flagging) { + // We're working around the potential situation where the flagging + // is already gone and the unflag event won't get fired. + if ($flaggable = $flagging->getFlaggable()) { + $this->unflag($flagging->getFlag(), $flaggable, $account); + } + else { + $flagging->delete(); + } + } + } + + /** + * {@inheritdoc} + */ public function reset(FlagInterface $flag, EntityInterface $entity = NULL) { $query = $this->entityQueryManager->get('flagging') ->condition('flag_id', $flag->id()); diff --git a/src/FlagServiceInterface.php b/src/FlagServiceInterface.php index ff437a1..9a2d75e 100644 --- a/src/FlagServiceInterface.php +++ b/src/FlagServiceInterface.php @@ -148,16 +148,31 @@ interface FlagServiceInterface { public function unflag(FlagInterface $flag, EntityInterface $entity, AccountInterface $account = NULL); /** + * Unflag all flags given to an entity or by an account. * + * @param \Drupal\Core\Entity\EntityInterface|NULL $entity + * Will remove all flaggings done to this entity. + * @param \Drupal\Core\Session\AccountInterface|NULL $account + * Will remove all flaggings by this account. + * + * @see FlagServiceInterface::reset() + * Not be confused with reset(). + */ + public function unflagAll(EntityInterface $entity = NULL, AccountInterface $account = NULL); + + /** * Remove all flagged entities from a flag. * * @param FlagInterface $flag - * The flag to reset. + * The flag to reset. * @param EntityInterface $entity - * (optional) The entity for which to delete flaggings. + * (optional) The entity for which to delete flaggings. * * @return int - * The number of flaggings that have been deleted. + * The number of flaggings that have been deleted. + * + * @see FlagServiceInterface::unflagAll() + * Not be confused with unflagAll(). */ public function reset(FlagInterface $flag, EntityInterface $entity = NULL); diff --git a/src/Tests/FlagSimpleTest.php b/src/Tests/FlagSimpleTest.php index f4af263..5623e07 100644 --- a/src/Tests/FlagSimpleTest.php +++ b/src/Tests/FlagSimpleTest.php @@ -7,8 +7,10 @@ namespace Drupal\flag\Tests; +use Drupal\node\NodeInterface; use Drupal\user\RoleInterface; use Drupal\user\Entity\Role; +use Drupal\user\UserInterface; /** @@ -171,7 +173,7 @@ class FlagSimpleTest extends FlagTestBase { $this->drupalLogin($this->adminUser); $edit = [ - 'global' => true, + 'global' => TRUE, ]; $this->drupalPostForm('admin/structure/flags/manage/' . $this->id, $edit, t('Save Flag')); $this->drupalGet('admin/structure/flags/manage/' . $this->id); @@ -183,7 +185,7 @@ class FlagSimpleTest extends FlagTestBase { $this->drupalLogin($this->adminUser); $edit = [ - 'global' => false, + 'global' => FALSE, ]; $this->drupalPostForm('admin/structure/flags/manage/' . $this->id, $edit, t('Save Flag')); $this->drupalGet('admin/structure/flags/manage/' . $this->id); @@ -235,36 +237,48 @@ class FlagSimpleTest extends FlagTestBase { public function doUserDeletionTest() { $node = $this->drupalCreateNode(['type' => $this->nodeType]); $node_id = $node->id(); + $node2 = $this->drupalCreateNode(['type' => $this->nodeType]); // Create and login a new user. - $user_1 = $this->drupalCreateUser(); + $user_1 = $this->drupalCreateUser(['delete any article content']); $this->drupalLogin($user_1); + // Flag the nodes. $this->drupalGet('node/' . $node_id); $this->clickLink('Flag this item'); $this->assertResponse(200); $this->assertLink('Unflag this item'); + $this->drupalGet('node/' . $node2->id()); + $this->clickLink('Flag this item'); + $this->assertResponse(200); - $count_flags_before = \Drupal::entityQuery('flagging') - ->condition('uid', $user_1->id()) - ->condition('flag_id', $this->id) - ->condition('entity_type', $node->getEntityTypeId()) - ->condition('entity_id', $node_id) - ->count() - ->execute(); + /** @var \Drupal\flag\FlagCountManagerInterface $flag_count_service */ + $flag_count_service = \Drupal::service('flag.count'); - $this->assertTrue(1, $count_flags_before); + // Assert that the nodes are set to flagged. + $count_flags_before = $this->countFlagging($user_1, $node); + $this->assertEqual(1, $count_flags_before); + $count_flags_before = $this->countFlagging($user_1, $node2); + $this->assertEqual(1, $count_flags_before); - $user_1->delete(); + // Delete one node. + $this->drupalPostForm('node/' . $node2->id() . '/delete', [], t('Delete')); + $this->assertResponse(200); - $count_flags_after = \Drupal::entityQuery('flagging') - ->condition('uid', $user_1->id()) - ->condition('flag_id', $this->id) - ->condition('entity_type', $node->getEntityTypeId()) - ->condition('entity_id', $node_id) - ->count() - ->execute(); + // Assert that both nodes remain as flagged after the changes. + // @todo This will fail when fixing this issue https://www.drupal.org/node/2551311 + $count_flags_before = $this->countFlagging($user_1, $node); + $this->assertEqual(1, $count_flags_before); + $count_flags_before = $this->countFlagging($user_1, $node2); + $this->assertEqual(1, $count_flags_before); + + // Delete the user. + $user_1->delete(); + // Ensure that all the flags are deleted. + $count_flags_after = $this->countFlagging($user_1, $node); + $this->assertEqual(0, $count_flags_after); + $count_flags_after = $this->countFlagging($user_1, $node2); $this->assertEqual(0, $count_flags_after); } @@ -356,4 +370,26 @@ class FlagSimpleTest extends FlagTestBase { $this->assertEqual(0, $count_flags_before); } + + /** + * Count the number of flags of the user over an entity. + * + * @param UserInterface $user + * The user owner of the flags. + * @param NodeInterface $node + * The node flagged. + * + * @return int + * Number of flags. + */ + protected function countFlagging(UserInterface $user, NodeInterface $node) { + return \Drupal::entityQuery('flagging') + ->condition('uid', $user->id()) + ->condition('flag_id', $this->id) + ->condition('entity_type', $node->getEntityTypeId()) + ->condition('entity_id', $node->id()) + ->count() + ->execute(); + } + }