From ab60a167e6ceeef2903db2eee09f31d35ed080e8 Mon Sep 17 00:00:00 2001 From: Andrew Aitken-Fincham Date: Wed, 21 Jun 2017 16:13:55 +0100 Subject: [PATCH] add inGroup(s) methods to Group --- src/Security/Group.php | 58 ++++++++++++++++++++++++++++++++ tests/php/Security/GroupTest.php | 31 +++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/src/Security/Group.php b/src/Security/Group.php index 4382366f5..ea61018d1 100755 --- a/src/Security/Group.php +++ b/src/Security/Group.php @@ -376,6 +376,64 @@ class Group extends DataObject return $items; } + /** + * Check if the group is a child of the given group or any parent groups + * + * @param string|int|Group $group Group instance, Group Code or ID + * @return bool Returns TRUE if the Group is a child of the given group, otherwise FALSE + */ + public function inGroup($group) + { + return in_array($this->identifierToGroupID($group), $this->collateAncestorIDs()); + } + + /** + * Check if the group is a child of the given groups or any parent groups + * + * @param (string|int|Group)[] $groups + * @param bool $requireAll set to TRUE if must be in ALL groups, or FALSE if must be in ANY + * @return bool Returns TRUE if the Group is a child of any of the given groups, otherwise FALSE + */ + public function inGroups($groups, $requireAll = false) + { + $ancestorIDs = $this->collateAncestorIDs(); + $candidateIDs = []; + foreach ($groups as $group) { + $groupID = $this->identifierToGroupID($group); + if ($groupID) { + $candidateIDs[] = $groupID; + } elseif ($requireAll) { + return false; + } + } + if (empty($candidateIDs)) { + return false; + } + $matches = array_intersect($candidateIDs, $ancestorIDs); + if ($requireAll) { + return count($candidateIDs) === count($matches); + } + return !empty($matches); + } + + /** + * Turn a string|int|Group into a GroupID + * + * @param string|int|Group $groupID Group instance, Group Code or ID + * @return int|null the Group ID or NULL if not found + */ + protected function identifierToGroupID($groupID) + { + if (is_numeric($groupID) && Group::get()->byID($groupID)) { + return $groupID; + } elseif (is_string($groupID) && $groupByCode = Group::get()->filter(['Code' => $groupID])->first()) { + return $groupByCode->ID; + } elseif ($groupID instanceof Group && $groupID->exists()) { + return $groupID->ID; + } + return null; + } + /** * This isn't a decendant of SiteTree, but needs this in case * the group is "reorganised"; diff --git a/tests/php/Security/GroupTest.php b/tests/php/Security/GroupTest.php index 0b8e9f727..17068af8a 100644 --- a/tests/php/Security/GroupTest.php +++ b/tests/php/Security/GroupTest.php @@ -171,6 +171,37 @@ class GroupTest extends FunctionalTest $this->assertSame(['childgroup', 'grandchildgroup'], $children->column('Code')); } + public function testGroupInGroupMethods() + { + $parentGroup = $this->objFromFixture(Group::class, 'parentgroup'); + $childGroup = $this->objFromFixture(Group::class, 'childgroup'); + $grandchildGroup = $this->objFromFixture(Group::class, 'grandchildgroup'); + $adminGroup = $this->objFromFixture(Group::class, 'admingroup'); + $group1 = $this->objFromFixture(Group::class, 'group1'); + + $this->assertTrue($grandchildGroup->inGroup($childGroup)); + $this->assertTrue($grandchildGroup->inGroup($childGroup->ID)); + $this->assertTrue($grandchildGroup->inGroup($childGroup->Code)); + + $this->assertTrue($grandchildGroup->inGroup($parentGroup)); + $this->assertTrue($grandchildGroup->inGroups([$parentGroup, $childGroup])); + $this->assertTrue($grandchildGroup->inGroups([$childGroup, $parentGroup])); + $this->assertTrue($grandchildGroup->inGroups([$parentGroup, $childGroup], true)); + + $this->assertFalse($grandchildGroup->inGroup($adminGroup)); + $this->assertFalse($grandchildGroup->inGroups([$adminGroup, $group1])); + $this->assertFalse($grandchildGroup->inGroups([$adminGroup, $childGroup], true)); + + $this->assertFalse($grandchildGroup->inGroup('NotARealGroup')); + $this->assertFalse($grandchildGroup->inGroup(99999999999)); + $this->assertFalse($grandchildGroup->inGroup(new TestMember())); + + // Edgecases + $this->assertTrue($grandchildGroup->inGroup($grandchildGroup)); + $this->assertFalse($grandchildGroup->inGroups([])); + $this->assertFalse($grandchildGroup->inGroups([], true)); + } + public function testDelete() { $group = $this->objFromFixture(Group::class, 'parentgroup');