diff --git a/src/Entity/Group.php b/src/Entity/Group.php index 0bbea96..875f489 100644 --- a/src/Entity/Group.php +++ b/src/Entity/Group.php @@ -188,6 +188,8 @@ class Group extends ContentEntityBase implements GroupInterface { public function addMember(UserInterface $account, $values = []) { if (!$this->getMember($account)) { $this->addContent($account, 'group_membership', $values); + $this->membershipLoader()->resetUserStaticCache($account); + $this->membershipLoader()->resetGroupStaticCache($this); } } @@ -197,6 +199,8 @@ class Group extends ContentEntityBase implements GroupInterface { public function removeMember(UserInterface $account) { if ($member = $this->getMember($account)) { $member->getGroupContent()->delete(); + $this->membershipLoader()->resetUserStaticCache($account); + $this->membershipLoader()->resetGroupStaticCache($this); } } diff --git a/src/GroupMembershipLoader.php b/src/GroupMembershipLoader.php index 7971c16..ffe3153 100644 --- a/src/GroupMembershipLoader.php +++ b/src/GroupMembershipLoader.php @@ -22,6 +22,20 @@ use Drupal\group\Entity\GroupInterface; class GroupMembershipLoader implements GroupMembershipLoaderInterface { /** + * Static cache of a user memberships per user. + * + * @var array + */ + protected $userMemberships = []; + + /** + * Static cache of group memberships per group. + * + * @var array + */ + protected $groupMemberships = []; + + /** * The entity type manager. * * @var \Drupal\Core\Entity\EntityTypeManagerInterface @@ -69,7 +83,7 @@ class GroupMembershipLoader implements GroupMembershipLoaderInterface { protected function wrapGroupContentEntities($entities) { $group_memberships = []; foreach ($entities as $group_content) { - $group_memberships[] = new GroupMembership($group_content); + $group_memberships[$group_content->gid->target_id] = new GroupMembership($group_content); } return $group_memberships; } @@ -78,30 +92,50 @@ class GroupMembershipLoader implements GroupMembershipLoaderInterface { * {@inheritdoc} */ public function load(GroupInterface $group, AccountInterface $account) { - $filters = ['entity_id' => $account->id()]; - $group_contents = $this->groupContentStorage()->loadByGroup($group, 'group_membership', $filters); - $group_memberships = $this->wrapGroupContentEntities($group_contents); - return $group_memberships ? reset($group_memberships) : FALSE; + $cache_id = md5($account->id()); + if (!isset($this->userMemberships[$account->id()][$cache_id])) { + $this->loadByUser($account); + } + return isset($this->userMemberships[$account->id()][$cache_id][$group->id()]) ? $this->userMemberships[$account->id()][$cache_id][$group->id()] : FALSE; } /** * {@inheritdoc} */ public function loadByGroup(GroupInterface $group, $roles = NULL) { - $filters = []; + $cache_id = md5($group->id()); + if ($roles) { + $cache_id = is_array($roles) ? ':' . md5(implode('-', $roles)) : ':' . md5($roles); + } + if (isset($this->groupMemberships[$group->id()][$cache_id])) { + return $this->groupMemberships[$group->id()][$cache_id]; + } + + $filters = []; if (isset($roles)) { $filters['group_roles'] = (array) $roles; } $group_contents = $this->groupContentStorage()->loadByGroup($group, 'group_membership', $filters); - return $this->wrapGroupContentEntities($group_contents); + $this->groupMemberships[$group->id()][$cache_id] = $this->wrapGroupContentEntities($group_contents); + + return $this->groupMemberships[$group->id()][$cache_id]; } /** * {@inheritdoc} */ public function loadByUser(AccountInterface $account = NULL, $roles = NULL) { + $cache_id = md5($account->id()); + if ($roles) { + $cache_id = is_array($roles) ? ':' . md5(implode('-', $roles)) : ':' . md5($roles); + } + + if (isset($this->userMemberships[$account->id()][$cache_id])) { + return $this->userMemberships[$account->id()][$cache_id]; + } + if (!isset($account)) { $account = $this->currentUser; } @@ -113,7 +147,8 @@ class GroupMembershipLoader implements GroupMembershipLoaderInterface { // If none were found, there can be no memberships either. if (empty($group_content_types)) { - return []; + $this->userMemberships[$account->id()][$cache_id] = []; + return $this->userMemberships[$account->id()][$cache_id]; } // Try to load all possible membership group content for the user. @@ -129,7 +164,22 @@ class GroupMembershipLoader implements GroupMembershipLoaderInterface { /** @var \Drupal\group\Entity\GroupContentInterface[] $group_contents */ $group_contents = $this->groupContentStorage()->loadByProperties($properties); - return $this->wrapGroupContentEntities($group_contents); + $this->userMemberships[$account->id()][$cache_id] = $this->wrapGroupContentEntities($group_contents); + return $this->userMemberships[$account->id()][$cache_id]; + } + + /** + * {@inheritdoc} + */ + public function resetUserStaticCache(AccountInterface $account) { + unset($this->userMemberships[$account->id()]); + } + + /** + * {@inheritdoc} + */ + public function resetGroupStaticCache(GroupInterface $group) { + unset($this->groupMemberships[$group->id()]); } } diff --git a/src/GroupMembershipLoaderInterface.php b/src/GroupMembershipLoaderInterface.php index 4da4050..50b6256 100644 --- a/src/GroupMembershipLoaderInterface.php +++ b/src/GroupMembershipLoaderInterface.php @@ -52,4 +52,20 @@ interface GroupMembershipLoaderInterface { */ public function loadByUser(AccountInterface $account = NULL, $roles = NULL); + /** + * Reset static memberships cache for a user. + * + * @param \Drupal\Core\Session\AccountInterface $account + * The user to reset the membership cache for. + */ + public function resetUserStaticCache(AccountInterface $account); + + /** + * Reset static memberships cache for a user. + * + * @param \Drupal\group\Entity\GroupInterface $group + * The group to reset the membership cache for. + */ + public function resetGroupStaticCache(GroupInterface $group); + }