diff --git a/og_subgroups.module b/og_subgroups.module index 4d57056..88c696f 100644 --- a/og_subgroups.module +++ b/og_subgroups.module @@ -5,7 +5,6 @@ * Provides users the ability to inherit permissions on subgroups. */ -// Add field widget related code. require drupal_get_path('module', 'og_subgroups') . '/og_subgroups.common.inc'; /** @@ -14,6 +13,21 @@ require drupal_get_path('module', 'og_subgroups') . '/og_subgroups.common.inc'; define('OG_USER_INHERITANCE_FIELD', 'og_user_inheritance'); /** + * Group content propagation field. + */ +define('OG_PROPAGATION_FIELD', 'og_propagation'); + +/** + * Group content propagation up. + */ +define('OG_PROPAGATION_UP', 0); + +/** + * Group content propagation down. + */ +define('OG_PROPAGATION_DOWN', 1); + +/** * Implements hook_og_fields_info(). */ function og_subgroups_og_fields_info() { @@ -49,6 +63,37 @@ function og_subgroups_og_fields_info() { ), ), ); + $allowed_values = array( + OG_PROPAGATION_UP => t('Up - This entity will propagate it\'s membership to all parent groups.'), + OG_PROPAGATION_DOWN => t('Down - This entity will propagate it\'s membership to all child groups.'), + ); + $items[OG_PROPAGATION_FIELD] = array( + 'type' => array('group content'), + 'description' => t('Determine membership propagation for group content.'), + 'field' => array( + 'field_name' => OG_PROPAGATION_FIELD, + 'type' => 'list_boolean', + 'cardinality' => FIELD_CARDINALITY_UNLIMITED, + 'settings' => array('allowed_values' => $allowed_values, 'allowed_values_function' => ''), + ), + 'instance' => array( + 'label' => t('Group propagation'), + 'description' => t('Note: If both up and down are selected, group content will propagate to all group entities.'), + 'widget_type' => 'options_select', + 'view modes' => array( + 'full' => array( + 'label' => t('Full'), + 'type' => 'list_default', + 'custom settings' => FALSE, + ), + 'teaser' => array( + 'label' => t('Teaser'), + 'type' => 'list_default', + 'custom settings' => FALSE, + ), + ), + ), + ); return $items; } @@ -104,4 +149,206 @@ function og_subgroups_og_user_access_alter(&$perms, $context) { } } } -} \ No newline at end of file +} + +/** + * Implements hook_og_membership_insert(). + */ +function og_subgroups_og_membership_insert($og_membership) { + og_subgroups_og_membership_create_propagate($og_membership); +} + +/** + * Implements hook_og_membership_update(). + */ +function og_subgroups_og_membership_update($og_membership) { + og_subgroups_og_membership_create_propagate($og_membership); +} + +/** + * Implements hook_og_membership_update(). + */ +function og_subgroups_og_membership_delete($og_membership) { + og_subgroups_og_membership_delete_propagate($og_membership); +} + +/** + * Propagates deletion of group membership to associated groups. Uses options set in the + * OG propagation field attached to group entity to determine propagation direction. + * + * @param OgMembership $og_membership + * The OG membership that is being inserted or updated. + * @param $storage + * A storage array for storing already added groups. + */ +function og_subgroups_og_membership_create_propagate($og_membership) { + // Cache all groups that we attach to this entity. Skip the group if we've + // encountered it already to avoid recursion. + $cache = &drupal_static(__FUNCTION__, array()); + if (in_array($og_membership->gid, $cache)) { + return; + } + $cache[] = $og_membership->gid; + cache_set('og_subgroups', $cache, 'cache'); + // Load group content entity an retrieve OG_PROPAGATION_FIELD settings. + $group_content = entity_load_single($og_membership->entity_type, $og_membership->etid); + if (isset($group_content->{OG_PROPAGATION_FIELD})) { + $settings = field_get_items($og_membership->entity_type, $group_content, OG_PROPAGATION_FIELD); + if (empty($settings)) { + return; + } + // Iterate over OG_PROPAGATION_FIELD settings and propagate membership accordingly. + foreach ($settings as $setting) { + if ($setting['value'] == OG_PROPAGATION_UP) { + og_subgroups_og_membership_create_propagate_up($og_membership, $cache); + } + if ($setting['value'] == OG_PROPAGATION_DOWN) { + og_subgroups_og_membership_create_propagate_down($og_membership, $cache); + } + } + } +} + +/** + * Helper function to propagate inserted/updated memberships upward. + * + * @param OgMembership $og_membership + * The OG membership that is being inserted or updated. + * @see: og_subgroups_og_membership_create_propagate() + */ +function og_subgroups_og_membership_create_propagate_up($og_membership, &$cache) { + $new_membership = new stdClass(); + $groups = og_get_entity_groups($og_membership->group_type, $og_membership->gid); + // Iterate over groups and group entity with each group. + if (!empty($groups)) { + foreach ($groups as $group_type => $group) { + foreach ($group as $membership_id => $gid) { + // Don't add this membership if it already exists. + if ($old_membership = og_get_membership($group_type, $gid, $og_membership->entity_type, $og_membership->etid)) { + continue; + } + // Check that we haven't added this group before. + if (in_array($gid, $cache)) { + continue; + } + // Don't allow entities to self-reference. + if ($og_membership->etid == $gid) { + continue; + } + // Group entity with group. + $new_membership = og_group($group_type, $gid, array('entity_type' => $og_membership->entity_type, 'entity' => $og_membership->etid)); + } + } + } +} + +/** + * Helper function to propagate inserted/updated memberships downward. + * + * @param OgMembership $og_membership + * The OG membership that is being inserted or updated. + * @see: og_subgroups_og_membership_create_propagate() + */ +function og_subgroups_og_membership_create_propagate_down($og_membership, &$cache) { + $new_membership = new stdClass(); + $groups = og_subgroups_get_associated_entities($og_membership->group_type, $og_membership->gid); + if (!empty($groups)) { + foreach ($groups as $group_type => $group) { + foreach ($group as $membership_id => $gid) { + // Don't add this membership if it already exists. + if ($old_membership = og_get_membership($group_type, $gid, $og_membership->entity_type, $og_membership->etid)) { + continue; + } + // Check that we haven't added this group before. + if (in_array($gid, $cache)) { + continue; + } + // Don't allow entities to self-reference. + if ($og_membership->etid == $gid) { + continue; + } + // Only group the entity with other groups. + $entity = entity_load_single($group_type, $gid); + if (!og_is_group($group_type, $entity)) { + continue; + } + // Group entity with group. + $new_membership = og_group($group_type, $gid, array('entity_type' => $og_membership->entity_type, 'entity' => $og_membership->etid)); + } + } + } +} + +/** + * Propagates deletion of group membership to associated groups. Uses options set in the + * OG propagation field attached to group entity to determine propagation direction. + * + * @param OgMembership $og_membership + * The OG membership that is being deleted. + */ +function og_subgroups_og_membership_delete_propagate($og_membership) { + // Load group content entity an retrieve OG_PROPAGATION_FIELD settings. + $group_content = entity_load_single($og_membership->entity_type, $og_membership->etid); + if (isset($group_content->{OG_PROPAGATION_FIELD})) { + $settings = field_get_items($og_membership->entity_type, $group_content, OG_PROPAGATION_FIELD); + if (empty($settings)) { + return; + } + // Iterate over OG_PROPAGATION_FIELD settings and propagate membership accordingly. + foreach ($settings as $setting) { + if ($setting['value'] == OG_PROPAGATION_UP) { + og_subgroups_og_membership_delete_propagate_up($og_membership); + } + if ($setting['value'] == OG_PROPAGATION_DOWN) { + og_subgroups_og_membership_delete_propagate_down($og_membership); + } + } + } +} + +/** + * Helper function to propagate deleted memberships upward. + * + * @param OgMembership $og_membership + * The OG membership that is being inserted or updated. + * @see: og_subgroups_og_membership_create_propagate() + */ +function og_subgroups_og_membership_delete_propagate_up($og_membership) { + $groups = og_get_entity_groups($og_membership->group_type, $og_membership->gid); + // Iterate over groups and subscribe user to each group. + if (!empty($groups)) { + foreach ($groups as $group_type => $group) { + foreach ($group as $membership_id => $gid) { + // Make sure this membership exists. + if ($old_membership = og_get_membership($group_type, $gid, $og_membership->entity_type, $og_membership->etid)) { + $roles = og_get_user_roles('node', $gid, $og_membership->etid); + if (sizeof($roles) <= 1) { + $old_membership->delete(); + } + } + } + } + } +} + +/** + * Helper function to propagate deleted memberships downward. + * + * @param OgMembership $og_membership + * The OG membership that is being inserted or updated. + * @see: og_subgroups_og_membership_create_propagate() + */ +function og_subgroups_og_membership_delete_propagate_down($og_membership) { + $groups = og_subgroups_get_associated_entities($og_membership->group_type, $og_membership->gid); + // Iterate over groups and subscribe user to each group. + if (!empty($groups)) { + foreach ($groups as $group_type => $group) { + foreach ($group as $membership_id => $gid) { + // Make sure this membership exists. + if ($old_membership = og_get_membership($group_type, $gid, $og_membership->entity_type, $og_membership->etid)) { + $old_membership->delete(); + } + } + } + } +}