From f4f6ac26a476c56775fecd7afe1771c3126f2aa3 Mon Sep 17 00:00:00 2001 From: Karoly Negyesi Date: Sun, 6 Dec 2015 15:02:17 -0800 Subject: [PATCH 1/5] rename GroupManager to GroupMap and lighten its constructor --- og.services.yml | 4 ++-- src/{GroupManager.php => GroupMap.php} | 18 +++++++++++++----- src/Og.php | 4 ++-- tests/src/Unit/GroupManagerTest.php | 6 +++--- tests/src/Unit/OgAccessTestBase.php | 8 ++++---- 5 files changed, 24 insertions(+), 16 deletions(-) rename src/{GroupManager.php => GroupMap.php} (84%) diff --git a/og.services.yml b/og.services.yml index 6a6360d00..1a5180aa4 100644 --- a/og.services.yml +++ b/og.services.yml @@ -2,8 +2,8 @@ services: plugin.manager.og.fields: class: Drupal\og\OgFieldsPluginManager parent: default_plugin_manager - og.group.manager: - class: Drupal\og\GroupManager + og.group_map: + class: Drupal\og\GroupMap arguments: ['@config.factory'] og.permissions: class: Drupal\og\OgPermissionHandler diff --git a/src/GroupManager.php b/src/GroupMap.php similarity index 84% rename from src/GroupManager.php rename to src/GroupMap.php index 13f317958..17f82a44f 100644 --- a/src/GroupManager.php +++ b/src/GroupMap.php @@ -12,7 +12,7 @@ /** * A manager to keep track of which entity type/bundles are OG group enabled. */ -class GroupManager { +class GroupMap { /** * The OG settings configuration key. @@ -47,9 +47,14 @@ class GroupManager { */ public function __construct(ConfigFactoryInterface $config_factory) { $this->configFactory = $config_factory; - $this->refreshGroupMap(); } + protected function groupMap() { + if (!isset($this->groupMap)) { + $this->refreshGroupMap(); + } + return $this->groupMap; + } /** * Determines whether an entity type ID and bundle ID are group enabled. * @@ -59,7 +64,8 @@ public function __construct(ConfigFactoryInterface $config_factory) { * @return bool */ public function isGroup($entity_type_id, $bundle) { - return isset($this->groupMap[$entity_type_id]) && in_array($bundle, $this->groupMap[$entity_type_id]); + $group_map = $this->groupMap(); + return isset($group_map[$entity_type_id]) && in_array($bundle, $group_map[$entity_type_id]); } /** @@ -68,7 +74,8 @@ public function isGroup($entity_type_id, $bundle) { * @return array */ public function getGroupsForEntityType($entity_type_id) { - return isset($this->groupMap[$entity_type_id]) ? $this->groupMap[$entity_type_id] : []; + $group_map = $this->groupMap(); + return isset($group_map[$entity_type_id]) ? $group_map[$entity_type_id] : []; } /** @@ -77,7 +84,8 @@ public function getGroupsForEntityType($entity_type_id) { * @return array */ public function getAllGroupBundles($entity_type = NULL) { - return !empty($this->groupMap[$entity_type]) ? $this->groupMap[$entity_type] : $this->groupMap; + $group_map = $this->groupMap; + return !empty($group_map[$entity_type]) ? $group_map[$entity_type] : $group_map; } /** diff --git a/src/Og.php b/src/Og.php index c2821e21d..f4bdb9eb6 100644 --- a/src/Og.php +++ b/src/Og.php @@ -318,11 +318,11 @@ public static function getAllGroupAudienceFields($entity_type_id, $bundle, $grou /** * Returns the group manager instance. * - * @return \Drupal\og\GroupManager + * @return \Drupal\og\GroupMap */ public static function groupManager() { // @todo store static reference for this? - return \Drupal::service('og.group.manager'); + return \Drupal::service('og.group_manager'); } /** diff --git a/tests/src/Unit/GroupManagerTest.php b/tests/src/Unit/GroupManagerTest.php index fc412b319..aa3244d3d 100644 --- a/tests/src/Unit/GroupManagerTest.php +++ b/tests/src/Unit/GroupManagerTest.php @@ -7,7 +7,7 @@ namespace Drupal\Tests\og\Unit; -use Drupal\og\GroupManager; +use Drupal\og\GroupMap; use Drupal\Tests\UnitTestCase; /** @@ -214,14 +214,14 @@ public function testRemoveGroup() { /** * Creates a group manager instance with a mock config factory. * - * @return \Drupal\og\GroupManager + * @return \Drupal\og\GroupMap */ protected function createGroupManager() { $this->configFactoryProphecy->get('og.settings') ->willReturn($this->configProphecy->reveal()) ->shouldBeCalled(); - return new GroupManager($this->configFactoryProphecy->reveal()); + return new GroupMap($this->configFactoryProphecy->reveal()); } } diff --git a/tests/src/Unit/OgAccessTestBase.php b/tests/src/Unit/OgAccessTestBase.php index 009ab78c2..0e4f950b6 100644 --- a/tests/src/Unit/OgAccessTestBase.php +++ b/tests/src/Unit/OgAccessTestBase.php @@ -17,7 +17,7 @@ use Drupal\Tests\UnitTestCase; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Session\AccountInterface; -use Drupal\og\GroupManager; +use Drupal\og\GroupMap; use Prophecy\Argument; class OgAccessTestBase extends UnitTestCase { @@ -40,7 +40,7 @@ class OgAccessTestBase extends UnitTestCase { protected $bundle; /** - * @var \Drupal\og\GroupManager + * @var \Drupal\og\GroupMap */ protected $groupManager; @@ -48,7 +48,7 @@ public function setUp() { $this->entityTypeId = $this->randomMachineName(); $this->bundle = $this->randomMachineName(); - $this->groupManager = $this->prophesize(GroupManager::class); + $this->groupManager = $this->prophesize(GroupMap::class); $this->groupManager->isGroup($this->entityTypeId, $this->bundle)->willReturn(TRUE); $cache_contexts_manager = $this->prophesize(CacheContextsManager::class); @@ -66,7 +66,7 @@ public function setUp() { $this->user->hasPermission(OgAccess::ADMINISTER_GROUP_PERMISSION)->willReturn(FALSE); $container = new ContainerBuilder(); - $container->set('og.group.manager', $this->groupManager->reveal()); + $container->set('og.group_manager', $this->groupManager->reveal()); $container->set('cache_contexts_manager', $cache_contexts_manager->reveal()); $container->set('config.factory', $config_factory->reveal()); $container->set('module_handler', $this->prophesize(ModuleHandlerInterface::class)->reveal()); From 421a508a9a1d30e59ae1cf31802a121fec9ebff8 Mon Sep 17 00:00:00 2001 From: Karoly Negyesi Date: Sun, 6 Dec 2015 15:26:49 -0800 Subject: [PATCH 2/5] say hi to group repository --- og.services.yml | 3 ++ src/GroupRepository.php | 44 +++++++++++++++++++++++++++ src/Og.php | 37 +++++++--------------- tests/src/Unit/OgAccessEntityTest.php | 19 +++--------- 4 files changed, 63 insertions(+), 40 deletions(-) create mode 100644 src/GroupRepository.php diff --git a/og.services.yml b/og.services.yml index 1a5180aa4..886049a11 100644 --- a/og.services.yml +++ b/og.services.yml @@ -8,3 +8,6 @@ services: og.permissions: class: Drupal\og\OgPermissionHandler arguments: ['@module_handler', '@string_translation', '@controller_resolver'] + og.group_repository: + cllass: Drupal\og\GroupRepository + arguments: ['@entity_field.manager', '@entity.query'] diff --git a/src/GroupRepository.php b/src/GroupRepository.php new file mode 100644 index 000000000..c89ed96f9 --- /dev/null +++ b/src/GroupRepository.php @@ -0,0 +1,44 @@ +entityFieldManager = $entity_field_manager; + $this->queryFactory = $query_factory; + } + + public function getAllGroupAudienceFields($entity_type_id, $bundle, $group_type_id = NULL, $group_bundle = NULL) { + $filter = function (FieldDefinitionInterface $field_definition) use ($group_type_id, $group_bundle) { + if (!Og::isGroupAudienceField($field_definition)) { + // Not a group audience field. + return FALSE; + } + $target_type = $field_definition->getFieldStorageDefinition() + ->getSetting('target_type'); + + if (isset($group_type_id) && $target_type != $group_type_id) { + // Field doesn't reference this group type. + return FALSE; + } + + $handler_settings = $field_definition->getSetting('handler_settings'); + if (isset($group_bundle) && !empty($handler_settings['target_bundles']) && !in_array($group_bundle, $handler_settings['target_bundles'])) { + return FALSE; + } + return TRUE; + }; + return array_filter($this->entityFieldManager->getFieldDefinitions($entity_type_id, $bundle), $filter); + } + +} diff --git a/src/Og.php b/src/Og.php index f4bdb9eb6..12480cced 100644 --- a/src/Og.php +++ b/src/Og.php @@ -287,32 +287,7 @@ public static function isGroupAudienceField(FieldDefinitionInterface $field_defi * none found. */ public static function getAllGroupAudienceFields($entity_type_id, $bundle, $group_type_id = NULL, $group_bundle = NULL) { - $return = []; - - foreach (\Drupal::entityManager()->getFieldDefinitions($entity_type_id, $bundle) as $field_definition) { - if (!static::isGroupAudienceField($field_definition)) { - // Not a group audience field. - continue; - } - - $target_type = $field_definition->getFieldStorageDefinition()->getSetting('target_type'); - - if (isset($group_type_id) && $target_type != $group_type_id) { - // Field doesn't reference this group type. - continue; - } - - $handler_settings = $field_definition->getSetting('handler_settings'); - - if (isset($group_bundle) && !empty($handler_settings['target_bundles']) && !in_array($group_bundle, $handler_settings['target_bundles'])) { - continue; - } - - $field_name = $field_definition->getName(); - $return[$field_name] = $field_definition; - } - - return $return; + return static::groupRepository()->getAllGroupAudienceFields($entity_type_id, $bundle, $group_type_id, $group_bundle); } /** @@ -325,6 +300,16 @@ public static function groupManager() { return \Drupal::service('og.group_manager'); } + /** + * Returns the group repository instance. + * + * @return \Drupal\og\GroupRepository + */ + public static function groupRepository() { + // @todo store static reference for this? + return \Drupal::service('og.group_repository'); + } + /** * Return the og permission handler instance. * diff --git a/tests/src/Unit/OgAccessEntityTest.php b/tests/src/Unit/OgAccessEntityTest.php index 6db29ad61..4533702ba 100644 --- a/tests/src/Unit/OgAccessEntityTest.php +++ b/tests/src/Unit/OgAccessEntityTest.php @@ -5,13 +5,11 @@ * Contains \Drupal\Tests\og\Unit\OgAccessEntity. */ - namespace Drupal\Tests\og\Unit; + use Drupal\Core\Entity\EntityInterface; -use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Entity\EntityTypeInterface; -use Drupal\Core\Field\FieldDefinitionInterface; -use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\og\GroupRepository; use Drupal\og\OgAccess; /** @@ -31,13 +29,6 @@ public function setUp() { define('OG_STATE_ACTIVE', 1); } - $field_definition = $this->prophesize(FieldDefinitionInterface::class); - $field_definition->getType()->willReturn('og_membership_reference'); - $field_definition->getFieldStorageDefinition() - ->willReturn($this->prophesize(FieldStorageDefinitionInterface::class)->reveal()); - $field_definition->getSetting("handler_settings")->willReturn([]); - $field_definition->getName()->willReturn($this->randomMachineName()); - $entity_type_id = $this->randomMachineName(); $bundle = $this->randomMachineName(); $entity_id = mt_rand(20, 30); @@ -55,9 +46,9 @@ public function setUp() { $this->groupManager->isGroup($entity_type_id, $bundle)->willReturn(FALSE); - $entity_manager = $this->prophesize(EntityManagerInterface::class); - $entity_manager->getFieldDefinitions($entity_type_id, $bundle)->willReturn([$field_definition->reveal()]); - \Drupal::getContainer()->set('entity.manager', $entity_manager->reveal()); + $group_repository = $this->prophesize(GroupRepository::class); + $group_repository->getAllGroupAudienceFields($entity_type_id, $bundle, NULL, NULL)->willReturn(['some group we did not mock']); + \Drupal::getContainer()->set('og.group_repository', $group_repository->reveal()); $r = new \ReflectionClass('Drupal\og\Og'); $reflection_property = $r->getProperty('entityGroupCache'); From 1850086f92ee1726f91f945aa048c5607c17ffee Mon Sep 17 00:00:00 2001 From: Karoly Negyesi Date: Sun, 6 Dec 2015 16:18:44 -0800 Subject: [PATCH 3/5] moved getEntityGroups into the repo --- src/GroupRepository.php | 99 ++++++++++++++++++++++++++- src/Og.php | 55 +-------------- tests/src/Unit/OgAccessEntityTest.php | 3 +- 3 files changed, 101 insertions(+), 56 deletions(-) diff --git a/src/GroupRepository.php b/src/GroupRepository.php index c89ed96f9..d73c3e70d 100644 --- a/src/GroupRepository.php +++ b/src/GroupRepository.php @@ -8,14 +8,37 @@ namespace Drupal\og; use Drupal\Core\Entity\EntityFieldManagerInterface; -use Drupal\Core\Entity\Query\QueryFactoryInterface; +use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Entity\Query\QueryFactory; use Drupal\Core\Field\FieldDefinitionInterface; class GroupRepository { - public function __construct(EntityFieldManagerInterface $entity_field_manager, QueryFactoryInterface $query_factory) { + /** + * @var array + */ + protected $entityGroupCache = []; + + /** + * @var \Drupal\Core\Entity\Query\QueryFactory + */ + protected $queryFactory; + + /** + * @var \Drupal\Core\Entity\EntityFieldManagerInterface + */ + protected $entityFieldManager; + + /** + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + + public function __construct(EntityFieldManagerInterface $entity_field_manager, QueryFactory $query_factory, EntityTypeManagerInterface $entity_type_manager) { $this->entityFieldManager = $entity_field_manager; $this->queryFactory = $query_factory; + $this->entityTypeManager = $entity_type_manager; } public function getAllGroupAudienceFields($entity_type_id, $bundle, $group_type_id = NULL, $group_bundle = NULL) { @@ -41,4 +64,76 @@ public function getAllGroupAudienceFields($entity_type_id, $bundle, $group_type_ return array_filter($this->entityFieldManager->getFieldDefinitions($entity_type_id, $bundle), $filter); } + /** + /** + * Gets the groups an entity is associated with. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity to get groups for. + * @param $states + * (optional) Array with the state to return. Defaults to active. + * @param $field_name + * (optional) The field name associated with the group. + * + * @return array + * An array with the group's entity type as the key, and array - keyed by + * the OG membership ID and the group ID as the value. If nothing found, + * then an empty array. + */ + public function getEntityGroups(EntityInterface $entity, array $states = [OG_STATE_ACTIVE], $field_name = NULL) { + $entity_type_id = $entity->getEntityTypeId(); + $entity_id = $entity->id(); + + // Get a string identifier of the states, so we can retrieve it from cache. + if ($states) { + sort($states); + $state_identifier = implode(':', $states); + } + else { + $state_identifier = FALSE; + } + + $identifier = [ + $entity_type_id, + $entity_id, + $state_identifier, + $field_name, + ]; + + $identifier = implode(':', $identifier); + if (isset($this->entityGroupCache[$identifier])) { + // Return cached values. + return $this->entityGroupCache[$identifier]; + } + + $this->entityGroupCache[$identifier] = []; + $query = $this->queryFactory->get('og_membership') + ->condition('entity_type', $entity_type_id) + ->condition('etid', $entity_id); + + if ($states) { + $query->condition('state', $states, 'IN'); + } + + if ($field_name) { + $query->condition('field_name', $field_name); + } + + $results = $query->execute(); + + /** @var \Drupal\og\Entity\OgMembership[] $memberships */ + $memberships = $this->entityTypeManager + ->getStorage('og_membership') + ->loadMultiple($results); + + /** @var \Drupal\og\Entity\OgMembership $membership */ + foreach ($memberships as $membership) { + $this->entityGroupCache[$identifier][$membership->getGroupType()][$membership->id()] = $membership->getGroup(); + } + return $this->entityGroupCache[$identifier]; + } + + public function resetCache() { + $this->entityGroupCache = []; + } } diff --git a/src/Og.php b/src/Og.php index 12480cced..81f05dba9 100644 --- a/src/Og.php +++ b/src/Og.php @@ -116,57 +116,7 @@ public static function createField($plugin_id, $entity_type, $bundle, array $set * then an empty array. */ public static function getEntityGroups(EntityInterface $entity, array $states = [OG_STATE_ACTIVE], $field_name = NULL) { - $entity_type_id = $entity->getEntityTypeId(); - $entity_id = $entity->id(); - - // Get a string identifier of the states, so we can retrieve it from cache. - if ($states) { - sort($states); - $state_identifier = implode(':', $states); - } - else { - $state_identifier = FALSE; - } - - $identifier = [ - $entity_type_id, - $entity_id, - $state_identifier, - $field_name, - ]; - - $identifier = implode(':', $identifier); - if (isset(static::$entityGroupCache[$identifier])) { - // Return cached values. - return static::$entityGroupCache[$identifier]; - } - - static::$entityGroupCache[$identifier] = []; - $query = \Drupal::entityQuery('og_membership') - ->condition('entity_type', $entity_type_id) - ->condition('etid', $entity_id); - - if ($states) { - $query->condition('state', $states, 'IN'); - } - - if ($field_name) { - $query->condition('field_name', $field_name); - } - - $results = $query->execute(); - - /** @var \Drupal\og\Entity\OgMembership[] $memberships */ - $memberships = \Drupal::entityTypeManager() - ->getStorage('og_membership') - ->loadMultiple($results); - - /** @var \Drupal\og\Entity\OgMembership $membership */ - foreach ($memberships as $membership) { - static::$entityGroupCache[$identifier][$membership->getGroupType()][$membership->id()] = $membership->getGroup(); - } - - return static::$entityGroupCache[$identifier]; + return static::groupRepository()->getEntityGroups($entity, $states, $field_name); } /** @@ -344,8 +294,7 @@ public static function invalidateCache($group_ids = array()) { drupal_static_reset($cache); } - // @todo Consider using a reset() method. - static::$entityGroupCache = []; + static::groupRepository()->resetCache(); // Invalidate the entity property cache. \Drupal::entityManager()->clearCachedDefinitions(); diff --git a/tests/src/Unit/OgAccessEntityTest.php b/tests/src/Unit/OgAccessEntityTest.php index 4533702ba..0da75384c 100644 --- a/tests/src/Unit/OgAccessEntityTest.php +++ b/tests/src/Unit/OgAccessEntityTest.php @@ -47,7 +47,8 @@ public function setUp() { $this->groupManager->isGroup($entity_type_id, $bundle)->willReturn(FALSE); $group_repository = $this->prophesize(GroupRepository::class); - $group_repository->getAllGroupAudienceFields($entity_type_id, $bundle, NULL, NULL)->willReturn(['some group we did not mock']); + $group_repository->getEntityGroups($this->entity, [OG_STATE_ACTIVE], NULL)->willReturn([[$this->groupEntity()->reveal()]]); + $group_repository->getAllGroupAudienceFields($entity_type_id, $bundle, NULL, NULL)->willReturn(['some fields we did not mock']); \Drupal::getContainer()->set('og.group_repository', $group_repository->reveal()); $r = new \ReflectionClass('Drupal\og\Og'); From 7fb873b4f738d65a150a250bb96c206c2c142142 Mon Sep 17 00:00:00 2001 From: Karoly Negyesi Date: Sun, 6 Dec 2015 16:26:02 -0800 Subject: [PATCH 4/5] getConfigFactoryStub is not helpful config still can be simplified a little --- tests/src/Unit/OgAccessTest.php | 2 +- tests/src/Unit/OgAccessTestBase.php | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/src/Unit/OgAccessTest.php b/tests/src/Unit/OgAccessTest.php index 615777f51..8909af24e 100644 --- a/tests/src/Unit/OgAccessTest.php +++ b/tests/src/Unit/OgAccessTest.php @@ -59,7 +59,7 @@ public function testUserAccessAdminPermission($operation) { * @dataProvider operationProvider */ public function testUserAccessOwner($operation) { - $this->config->get('group_manager_full_access')->willReturn(TRUE); + $this->config->willReturn(TRUE); $user_access = OgAccess::userAccess($this->groupEntity(TRUE)->reveal(), $operation, $this->user->reveal()); $this->assertTrue($user_access->isAllowed()); } diff --git a/tests/src/Unit/OgAccessTestBase.php b/tests/src/Unit/OgAccessTestBase.php index 0e4f950b6..142cb3a47 100644 --- a/tests/src/Unit/OgAccessTestBase.php +++ b/tests/src/Unit/OgAccessTestBase.php @@ -22,6 +22,9 @@ class OgAccessTestBase extends UnitTestCase { + /** + * @var \Prophecy\Prophecy\MethodProphecy + */ protected $config; /** @@ -54,11 +57,11 @@ public function setUp() { $cache_contexts_manager = $this->prophesize(CacheContextsManager::class); $cache_contexts_manager->assertValidTokens(Argument::any())->willReturn(TRUE); - $this->config = $this->addCache($this->prophesize(Config::class)); - $this->config->get('group_manager_full_access')->willReturn(FALSE); + $config = $this->addCache($this->prophesize(Config::class)); + $this->config = $config->get('group_manager_full_access')->willReturn(FALSE); $config_factory = $this->prophesize(ConfigFactory::class); - $config_factory->get('og.settings')->willReturn($this->config); + $config_factory->get('og.settings')->willReturn($config); $this->user = $this->prophesize(AccountInterface::class); $this->user->isAuthenticated()->willReturn(TRUE); From 333daaee273b9ebd01f31e6cfacab9c5759b726c Mon Sep 17 00:00:00 2001 From: Karoly Negyesi Date: Sun, 6 Dec 2015 16:30:06 -0800 Subject: [PATCH 5/5] more doxygen --- tests/src/Unit/OgAccessTestBase.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/src/Unit/OgAccessTestBase.php b/tests/src/Unit/OgAccessTestBase.php index 142cb3a47..865a2674c 100644 --- a/tests/src/Unit/OgAccessTestBase.php +++ b/tests/src/Unit/OgAccessTestBase.php @@ -20,6 +20,9 @@ use Drupal\og\GroupMap; use Prophecy\Argument; +/** + * Base class for the og access tests. + */ class OgAccessTestBase extends UnitTestCase { /**