og.module

  1. cis7 sites/all/modules/ulmus/og/og.module
  2. cle7 sites/all/modules/ulmus/og/og.module
  3. ecd7 sites/all/modules/ulmus/og/og.module
  4. elmsmedia7 sites/all/modules/ulmus/og/og.module
  5. harmony7 sites/all/modules/ulmus/og/og.module
  6. icor7 sites/all/modules/ulmus/og/og.module
  7. meedjum_blog7 sites/all/modules/ulmus/og/og.module
  8. mooc7 sites/all/modules/ulmus/og/og.module

Enable users to create and manage groups with roles and permissions.

Functions

Namesort descending Description
og_action_info Implements hook_action_info().
og_check_field_cardinality Return TRUE if a field can be used and has not reached maximum values.
og_create_field Create an organic groups field in a bundle.
og_cron_queue_info Implements hook_cron_queue_info().
og_ctools_plugin_directory Implements hook_ctools_plugin_directory().
og_default_og_membership_type Implements hook_default_og_membership_type().
og_delete_user_roles_by_group Delete all roles belonging to a group.
og_entity_delete Implements hook_entity_delete().
og_entity_getter Getter callback to load the 'entity' or 'group' property from OG membership.
og_entity_info Implements hook_entity_info().
og_entity_insert Implements hook_entity_insert().
og_entity_property_info Implements hook_entity_property_info().
og_entity_query_alter Implements hook_entity_query_alter().
og_entity_setter Entity property info setter callback to set the "entity" property for groups and memberships.
og_entity_update Implements hook_entity_update().
og_features_api Implements hook_features_api().
og_features_pipe_alter Implements hook_features_pipe_alter().
og_fields_info Get all the modules fields that can be assigned to fieldable entities.
og_field_access Implements hook_field_access().
og_field_attach_form Implements hook_field_attach_form().
og_field_attach_insert Implements hook_field_attach_insert().
og_field_attach_update Implements hook_field_attach_update().
og_field_create_instance Implements hook_field_create_instance().
og_field_delete_instance Implements field_delete_instance().
og_flush_caches Implements hook_flush_caches().
og_form_group_manager_validate Validate handler; Make sure a group can be created.
og_form_group_reference_validate Validate handler; Make sure group-only content permissions are honored.
og_get_all_group Return all existing groups of an entity type.
og_get_all_group_bundle Return all bundles that are a group type.
og_get_all_group_content_bundle Return all the entities that are a group content.
og_get_all_group_content_entity Return all the entities that are a group content.
og_get_all_group_entity Return all entity types that have bundles that are a group type.
og_get_best_group_audience_field Get the first best matching group-audience field.
og_get_default_permissions Get default permissions.
og_get_default_roles Get array of default roles, keyed by their declaring module.
og_get_entity_groups Get the groups an entity is associated with.
og_get_fieldable_entity_list Return a list of fieldable entities.
og_get_field_og_membership_properties Property getter callback for OG membership per field.
og_get_groups_by_user Get the group IDs of all the groups a user is an approved member of.
og_get_group_audience_fields Get the name of the group-audience type field.
og_get_group_members_properties Property getter callback for group members.
og_get_group_type Return the group type (i.e. "group" or "group_content") of an entity.
og_get_membership Get the group membership entity by user and group.
og_get_og_membership_properties Property getter callback for OG membership.
og_get_permissions Get all permissions defined by implementing modules.
og_get_user_roles Get all roles of a user in a certain group.
og_get_user_roles_name Get the role names of role IDs.
og_group Set an association (e.g. subscribe) an entity to a group.
og_group_content_states Return the states a group content can be in.
og_group_states Return the states a group can be in.
og_help Implements hook_help().
og_invalidate_cache Invalidate cache.
og_is_group Return TRUE if the entity is acting as a group.
og_is_group_audience_field Return TRUE if field is a group audience type.
og_is_group_content_type Return TRUE if the entity type is a "group content" type.
og_is_group_default_access Check if group should use default roles and permissions.
og_is_group_type Return TRUE if the entity type is a "group" type.
og_is_member Return TRUE if entity belongs to a group.
og_list_permissions Helper function to generate standard node permission list for a given type.
og_membership_access Access callback for the group membership entity.
og_membership_create Creates a new OG membership.
og_membership_delete Delete an existing OG membership.
og_membership_delete_by_group Register memberships for deletion.
og_membership_delete_multiple Delete multiple existing OG memberships.
og_membership_invalidate_cache Reset static cache related to group membership.
og_membership_label Label callback; Return the label of OG membership entity.
og_membership_load OG membership loader.
og_membership_load_multiple Load multiple OG membership entities based on certain conditions.
og_membership_orphans_worker Queue worker; Process a queue item.
og_membership_save Inserts or updates an OG membership entity into the database.
og_membership_type_access Access callback for the OG membership type entity.
og_membership_type_create Creates a new membership type.
og_membership_type_delete Deletes an existing OG membership type.
og_membership_type_load OG membership type loader.
og_membership_type_save Inserts or updates an OG membership type entity into the database.
og_menu Implements hook_menu().
og_migrate_api Implements hook_migrate_api().
og_modules_uninstalled Implements hook_modules_uninstalled().
og_node_access Implements hook_node_access().
og_node_create_links Return a form element with crafted links to create nodes for a group.
og_og_default_roles Implements hook_og_default_roles().
og_og_fields_info Implements hook_og_fields_info().
og_og_membership_delete Implements hook_og_membership_delete().
og_og_membership_insert Implements hook_og_membership_insert().
og_og_membership_update Implements hook_og_membership_update().
og_og_permission Implements hook_og_permission().
og_operations_load_action_includes Loads the VBO actions placed in their own include files.
og_permission Implements hook_permission().
og_permissions_delete_by_module Delete all permissions defined by a module.
og_query_og_membership_alter Implements hook_query_TAG_alter().
og_roles Retrieve an array of roles matching specified conditions.
og_roles_override Create new roles, based on the default roles and permissions.
og_role_change_permissions Change permissions for a user role.
og_role_create Create a stub OG role object.
og_role_delete Delete a user role from database.
og_role_grant Grant a group role to a user.
og_role_grant_permissions Grant permissions to a user role.
og_role_load Fetch a user role from database.
og_role_permissions Determine the permissions for one or more roles.
og_role_revoke Revoke a group role from a user.
og_role_revoke_permissions Revoke permissions from a user role.
og_role_save Save a user role to the database.
og_set_breadcrumb Set breadcrumbs according to a given group.
og_ungroup Delete an association (e.g. unsubscribe) of an entity to a group.
og_user_access Determine whether a user has a given privilege.
og_user_access_entity Check if a user has access to a permission on a certain entity context.
og_views_api Implements hook_views_api().
_og_orphans_delete Helper function to delete orphan group-content.
_og_orphans_move Helper function to move orphan group-content to another group.
_og_query_og_membership_alter_conditions Recursively replace the fields to their aliases in the query's conditions.
_og_update_entity_fields Update the field values in the entity, to reflect the membership.

Constants

Namesort descending Description
OG_ADMINISTRATOR_ROLE The role name of group administrator.
OG_ANONYMOUS_ROLE The role name of group non-members.
OG_AUDIENCE_FIELD Group audience field.
OG_AUTHENTICATED_ROLE The role name of group member.
OG_DEFAULT_ACCESS_FIELD Group default roles and permissions field.
OG_GROUP_FIELD Group field.
OG_MEMBERSHIP_REQUEST_FIELD The name of the user's request field in the default group membership type.
OG_MEMBERSHIP_TYPE_DEFAULT The default group membership type that is the bundle of group membership.
OG_STATE_ACTIVE Define active group content states.
OG_STATE_BLOCKED Define blocked group content states. The user is rejected from the group.
OG_STATE_PENDING Define pending group content states. The user is subscribed to the group but isn't an active member yet.

File

sites/all/modules/ulmus/og/og.module
View source
  1. <?php
  2. /**
  3. * @file
  4. * Enable users to create and manage groups with roles and permissions.
  5. */
  6. // Add field widget related code.
  7. require DRUPAL_ROOT . '/' . drupal_get_path('module', 'og') . '/includes/og.field.inc';
  8. /**
  9. * Define active group content states.
  10. *
  11. * When a user has this membership state they are considered to be of
  12. * "member" role.
  13. */
  14. define('OG_STATE_ACTIVE', 1);
  15. /**
  16. * Define pending group content states. The user is subscribed to the group
  17. * but isn't an active member yet.
  18. *
  19. * When a user has this membership state they are considered to be of
  20. * "non-member" role.
  21. */
  22. define('OG_STATE_PENDING', 2);
  23. /**
  24. * Define blocked group content states. The user is rejected from the group.
  25. *
  26. * When a user has this membership state they are denided access to any
  27. * group related action. This state, however, does not prevent user to
  28. * access a group or group content node.
  29. */
  30. define('OG_STATE_BLOCKED', 3);
  31. /**
  32. * Group audience field.
  33. */
  34. define('OG_AUDIENCE_FIELD', 'og_group_ref');
  35. /**
  36. * Group field.
  37. */
  38. define('OG_GROUP_FIELD', 'group_group');
  39. /**
  40. * Group default roles and permissions field.
  41. */
  42. define('OG_DEFAULT_ACCESS_FIELD', 'og_roles_permissions');
  43. /**
  44. * The role name of group non-members.
  45. */
  46. define('OG_ANONYMOUS_ROLE', 'non-member');
  47. /**
  48. * The role name of group member.
  49. */
  50. define('OG_AUTHENTICATED_ROLE', 'member');
  51. /**
  52. * The role name of group administrator.
  53. */
  54. define('OG_ADMINISTRATOR_ROLE', 'administrator member');
  55. /**
  56. * The default group membership type that is the bundle of group membership.
  57. */
  58. define('OG_MEMBERSHIP_TYPE_DEFAULT', 'og_membership_type_default');
  59. /**
  60. * The name of the user's request field in the default group membership type.
  61. */
  62. define('OG_MEMBERSHIP_REQUEST_FIELD', 'og_membership_request');
  63. /**
  64. * Implements hook_help().
  65. */
  66. function og_help($path, $arg) {
  67. switch ($path) {
  68. case 'admin/help#og':
  69. $path = drupal_get_path('module', 'og');
  70. $output = '<p>' . t("Read the <a href='@url'>README.txt</a> file in the Organic groups module directory.", array('@url' => "/$path/README.txt")) . '</p>';
  71. $output .= '<p>' . t("Information about Organic Groups can also be found on the module's<a href='@og'>documentation page</a>.", array('@og' => 'http://drupal.org/documentation/modules/og')) . '</p>';
  72. return $output;
  73. }
  74. }
  75. /**
  76. * Implements hook_menu().
  77. */
  78. function og_menu() {
  79. $items = array();
  80. // Add our own autocomplete callback to pass also the group and
  81. // vocabulary info.
  82. $items['og/autocomplete/single/%/%/%/%'] = array(
  83. 'title' => 'Entity Reference Autocomplete',
  84. 'page callback' => 'og_entityreference_autocomplete_callback',
  85. 'page arguments' => array(2, 3, 4, 5, 6),
  86. 'access callback' => TRUE,
  87. 'type' => MENU_CALLBACK,
  88. );
  89. $items['og/autocomplete/tags/%/%/%/%'] = array(
  90. 'title' => 'Entity Reference Autocomplete',
  91. 'page callback' => 'og_entityreference_autocomplete_callback',
  92. 'page arguments' => array(2, 3, 4, 5, 6),
  93. 'access callback' => TRUE,
  94. 'type' => MENU_CALLBACK,
  95. );
  96. return $items;
  97. }
  98. /**
  99. * Implements hook_entity_info().
  100. */
  101. function og_entity_info() {
  102. $items['og_membership_type'] = array(
  103. 'label' => t('OG membership type'),
  104. 'controller class' => 'EntityAPIControllerExportable',
  105. 'entity class' => 'OgMembershipType',
  106. 'base table' => 'og_membership_type',
  107. 'fieldable' => TRUE,
  108. 'entity keys' => array(
  109. 'id' => 'id',
  110. 'label' => 'description',
  111. 'name' => 'name',
  112. ),
  113. 'exportable' => TRUE,
  114. 'export' => array(
  115. 'default hook' => 'default_og_membership_type',
  116. ),
  117. 'bundle of' => 'og_membership',
  118. 'module' => 'og',
  119. 'metadata controller class' => 'EntityDefaultMetadataController',
  120. 'views controller class' => 'EntityDefaultViewsController',
  121. 'access callback' => 'og_membership_type_access',
  122. 'entity cache' => module_exists('entitycache'),
  123. );
  124. if (class_exists('OgMembershipTypeUIController')) {
  125. $items['og_membership_type'] += array(
  126. // Enable the entity API's admin UI.
  127. 'admin ui' => array(
  128. // TODO: This path doesn't exist before OG-ui.
  129. 'path' => 'admin/config/group/group-membership',
  130. 'file' => 'includes/og.admin.inc',
  131. 'controller class' => 'OgMembershipTypeUIController',
  132. ),
  133. );
  134. }
  135. $items['og_membership'] = array(
  136. 'label' => t('OG membership'),
  137. 'entity class' => 'OgMembership',
  138. 'controller class' => 'EntityAPIController',
  139. 'base table' => 'og_membership',
  140. 'fieldable' => TRUE,
  141. 'entity keys' => array(
  142. 'id' => 'id',
  143. // The message has no label.
  144. 'label' => FALSE,
  145. 'bundle' => 'type',
  146. ),
  147. 'label callback' => 'og_membership_label',
  148. 'bundles' => array(),
  149. 'bundle keys' => array(
  150. 'bundle' => 'name',
  151. ),
  152. 'module' => 'og',
  153. 'metadata controller class' => 'OgMembershipMetadataController',
  154. 'views controller class' => 'OgMembershipViewsController',
  155. 'access callback' => 'og_membership_access',
  156. 'entity cache' => module_exists('entitycache'),
  157. );
  158. // Add bundle info but bypass entity_load() as we cannot use it here.
  159. if (db_table_exists('og_membership_type')) {
  160. $memberships = db_select('og_membership_type', 'g')
  161. ->fields('g')
  162. ->execute()
  163. ->fetchAllAssoc('name');
  164. foreach ($memberships as $type_name => $type) {
  165. $items['og_membership']['bundles'][$type_name] = array(
  166. 'label' => $type->name,
  167. 'admin' => array(
  168. 'path' => 'admin/config/group/group-membership/manage/%og_membership_type',
  169. 'real path' => 'admin/config/group/group-membership/manage/' . $type->name,
  170. 'bundle argument' => 5,
  171. 'access arguments' => array('administer group'),
  172. ),
  173. );
  174. }
  175. }
  176. return $items;
  177. }
  178. /**
  179. * Implements hook_entity_property_info().
  180. */
  181. function og_entity_property_info() {
  182. $info = array();
  183. // Add OG membership metadata for every bundle that is a group content.
  184. foreach (og_get_all_group_content_bundle() as $entity_type => $bundles) {
  185. foreach ($bundles as $bundle => $bundle_value) {
  186. $info[$entity_type]['bundles'][$bundle]['properties']['og_membership'] = array(
  187. 'label' => t("OG memberships"),
  188. 'type' => 'list<og_membership>',
  189. 'description' => t("A list of all OG memberships of the @name entity.", array('@name' => $entity_type)),
  190. 'getter callback' => 'og_get_og_membership_properties',
  191. );
  192. // Add per-state properties.
  193. $general = $info[$entity_type]['bundles'][$bundle]['properties']['og_membership'];
  194. foreach (og_group_content_states() as $state => $state_label) {
  195. $params = array('@state' => $state_label, '@name' => $entity_type);
  196. $info[$entity_type]['bundles'][$bundle]['properties']['og_membership__' . $state] = $general;
  197. $info[$entity_type]['bundles'][$bundle]['properties']['og_membership__' . $state]['label'] = t('@state OG membership', $params);
  198. $info[$entity_type]['bundles'][$bundle]['properties']['og_membership__' . $state]['description'] = t("A list of all OG memberships of the @name entity with @state state.", $params);
  199. }
  200. // Add OG membership per field in a bundle.
  201. foreach (og_get_group_audience_fields($entity_type, $bundle) as $field_name => $label) {
  202. $params = array('@label' => $label);
  203. $field_info = field_info_field($field_name);
  204. $group_type = $field_info['settings']['target_type'];
  205. $info[$entity_type]['bundles'][$bundle]['properties'][$field_name . '__og_membership'] = array(
  206. 'label' => t('OG membership from field @label', $params),
  207. 'type' => 'list<og_membership>',
  208. // The bundle in this context means the OG membership type.
  209. 'bundle' => $field_info['settings']['handler_settings']['membership_type'],
  210. 'description' => t('A list of all OG memberships registered in field @label.', $params),
  211. 'getter callback' => 'og_get_field_og_membership_properties',
  212. );
  213. // Add per-state properties.
  214. $general = $info[$entity_type]['bundles'][$bundle]['properties'][$field_name . '__og_membership'];
  215. foreach (og_group_content_states() as $state => $state_label) {
  216. $params = array(
  217. '@label' => $label,
  218. '@label' => $label,
  219. '@state' => $state_label,
  220. );
  221. $info[$entity_type]['bundles'][$bundle]['properties'][$field_name . '__og_membership__' . $state] = $general;
  222. $info[$entity_type]['bundles'][$bundle]['properties'][$field_name . '__og_membership__' . $state]['label'] = t('@state OG memberships from field @label', $params);
  223. $info[$entity_type]['bundles'][$bundle]['properties'][$field_name . '__og_membership__' . $state]['description'] = t('A list of all OG memberships with @state registered in field @label.', $params);
  224. }
  225. }
  226. }
  227. }
  228. foreach (og_get_all_group_bundle() as $entity_type => $bundles) {
  229. foreach ($bundles as $bundle => $bundle_value) {
  230. $info[$entity_type]['bundles'][$bundle]['properties']['members'] = array(
  231. 'label' => t("Group members"),
  232. 'type' => 'list<user>',
  233. 'description' => t("A list group members of the @name entity.", array('@name' => $entity_type)),
  234. 'getter callback' => 'og_get_group_members_properties',
  235. );
  236. // Add per-state properties.
  237. $general = $info[$entity_type]['bundles'][$bundle]['properties']['members'];
  238. foreach (og_group_content_states() as $state => $state_label) {
  239. $params = array('@state' => $state_label, '@name' => $entity_type);
  240. $info[$entity_type]['bundles'][$bundle]['properties']['members__' . $state] = $general;
  241. $info[$entity_type]['bundles'][$bundle]['properties']['members__' . $state]['label'] = t('@state group members', $params);
  242. $info[$entity_type]['bundles'][$bundle]['properties']['members__' . $state]['description'] = t("A list of all users of the @name entity with @state state.", $params);
  243. }
  244. }
  245. }
  246. return $info;
  247. }
  248. /**
  249. * Property getter callback for group members.
  250. *
  251. * @see og_entity_property_info()
  252. */
  253. function og_get_group_members_properties($entity, array $options, $name, $type) {
  254. $args = explode('__', $name);
  255. $state = !empty($args[1]) ? $args[1] : FALSE;
  256. list($id) = entity_extract_ids($type, $entity);
  257. $cache = &drupal_static(__FUNCTION__, array());
  258. if (isset($cache[$type][$id][$state])) {
  259. // Return the cached result.
  260. return $cache[$type][$id][$state];
  261. }
  262. $cache[$type][$id][$state] = array();
  263. $query = new EntityFieldQuery();
  264. $query
  265. ->entityCondition('entity_type', 'og_membership')
  266. ->propertyCondition('group_type', $type, '=')
  267. ->propertyCondition('gid', $id, '=')
  268. ->propertyCondition('entity_type', 'user', '=');
  269. if ($state) {
  270. $query->propertyCondition('state', $state, '=');
  271. }
  272. $result = $query->execute();
  273. if (!empty($result['og_membership'])) {
  274. $og_memberships = og_membership_load_multiple(array_keys($result['og_membership']));
  275. foreach ($og_memberships as $og_membership) {
  276. $cache[$type][$id][$state][] = $og_membership->etid;
  277. }
  278. }
  279. return $cache[$type][$id][$state];
  280. }
  281. /**
  282. * Property getter callback for OG membership.
  283. *
  284. * @see og_entity_property_info()
  285. */
  286. function og_get_og_membership_properties($entity, array $options, $name, $type) {
  287. // Get the state from name, if exists.
  288. if ($name == 'og_membership') {
  289. $state = array();
  290. }
  291. else {
  292. $args = explode('__', $name);
  293. $state = array($args[1]);
  294. }
  295. $ids = array();
  296. if ($gids = og_get_entity_groups($type, $entity, $state)) {
  297. $ids = array();
  298. foreach ($gids as $group_type => $values) {
  299. $ids = array_merge($ids, array_keys($values));
  300. }
  301. }
  302. return $ids;
  303. }
  304. /**
  305. * Property getter callback for OG membership per field.
  306. *
  307. * @see og_entity_property_info()
  308. */
  309. function og_get_field_og_membership_properties($entity, array $options, $name, $type) {
  310. $args = explode('__', $name);
  311. // Field name might have double underscore as-well, so we need to make
  312. // sure we get it right.
  313. $last_char = substr($name, -1);
  314. $state = is_numeric($last_char) ? $last_char : FALSE;
  315. // The number of characters to ignore in the name (i.e. remove the
  316. // "__og_membership" or "__og_membership__0").
  317. $remove_char = $state ? -18 : -15;
  318. $field_name = substr($name, 0, $remove_char);
  319. $field_name = $args[0];
  320. $field = field_info_field($field_name);
  321. $states = count($args) == 2 ? FALSE : array($args[2]);
  322. $result = og_get_entity_groups($type, $entity, $states, $field_name);
  323. $target_type = $field['settings']['target_type'];
  324. return !empty($result[$target_type]) ? array_keys($result[$target_type]) : array();
  325. }
  326. /**
  327. * Getter callback to load the 'entity' or 'group' property from OG membership.
  328. *
  329. * We have to return the entity wrapped.
  330. */
  331. function og_entity_getter($object, array $options, $property_name) {
  332. switch ($property_name) {
  333. case 'entity':
  334. return entity_metadata_wrapper($object->entity_type, $object->etid);
  335. case 'group':
  336. return entity_metadata_wrapper($object->group_type, $object->gid);
  337. }
  338. }
  339. /**
  340. * Entity property info setter callback to set the "entity" property for groups
  341. * and memberships.
  342. *
  343. * As the property is of type entity, the value will be passed as a wrapped
  344. * entity.
  345. */
  346. function og_entity_setter($object, $property_name, $wrapper) {
  347. switch ($property_name) {
  348. case 'entity':
  349. $object->entity_type = $wrapper->type();
  350. $object->etid = $wrapper->getIdentifier();
  351. break;
  352. case 'group':
  353. $object->group_type = $wrapper->type();
  354. $object->gid = $wrapper->getIdentifier();
  355. break;
  356. }
  357. }
  358. /**
  359. * Implements hook_default_og_membership_type().
  360. */
  361. function og_default_og_membership_type() {
  362. $items = array();
  363. $items['og_membership_type_default'] = entity_import('og_membership_type', '{
  364. "name" : "og_membership_type_default",
  365. "description" : "Default",
  366. "rdf_mapping" : []
  367. }');
  368. return $items;
  369. }
  370. /**
  371. * Implements hook_modules_uninstalled().
  372. */
  373. function og_modules_uninstalled($modules) {
  374. // Delete module's permissions.
  375. og_permissions_delete_by_module($modules);
  376. }
  377. /**
  378. * Implements hook_ctools_plugin_directory().
  379. */
  380. function og_ctools_plugin_directory($module, $plugin) {
  381. if ($module == 'ctools') {
  382. return 'plugins/' . $plugin;
  383. }
  384. elseif ($module == 'entityreference') {
  385. return "plugins/entityreference/$plugin";
  386. }
  387. }
  388. /**
  389. * Implements hook_permission().
  390. */
  391. function og_permission() {
  392. return array(
  393. 'administer group' => array(
  394. 'title' => t('Administer Organic groups permissions'),
  395. 'description' => t('Administer all groups and permissions.'),
  396. ),
  397. );
  398. }
  399. /**
  400. * Implements hook_og_permission().
  401. */
  402. function og_og_permission() {
  403. // Generate standard node permissions for all applicable node types.
  404. $perms = array();
  405. $perms['update group'] = array(
  406. 'title' => t('Edit group'),
  407. 'description' => t('Edit the group. Note: This permission controls only node entity type groups.'),
  408. 'default role' => array(OG_ADMINISTRATOR_ROLE),
  409. );
  410. $perms['administer group'] = array(
  411. 'title' => t('Administer group'),
  412. 'description' => t('Manage group members and content in the group.'),
  413. 'default role' => array(OG_ADMINISTRATOR_ROLE),
  414. 'restrict access' => TRUE,
  415. );
  416. foreach (node_permissions_get_configured_types() as $type) {
  417. $perms = array_merge($perms, og_list_permissions($type));
  418. }
  419. return $perms;
  420. }
  421. /**
  422. * Implements hook_og_default_roles().
  423. */
  424. function og_og_default_roles() {
  425. return array(OG_ADMINISTRATOR_ROLE);
  426. }
  427. /**
  428. * Implements hook_node_access().
  429. */
  430. function og_node_access($node, $op, $account) {
  431. $type = is_string($node) ? $node : (is_array($node) ? $node['type'] : $node->type);
  432. if ($op == 'create' && og_is_group_content_type('node', $type)) {
  433. // Save some legwork if the user has the core permission and strict node
  434. // access is not set.
  435. if (!variable_get('og_node_access_strict', TRUE) && user_access("create $type content", $account)) {
  436. // We just ignore: core access will take care of it.
  437. return NODE_ACCESS_IGNORE;
  438. }
  439. if (user_access('administer group', $account)) {
  440. return NODE_ACCESS_ALLOW;
  441. }
  442. // We can't check if user has create permissions using og_user_access(), as
  443. // there is no group context. However, we can check if there are any groups
  444. // the user will be able to select, and if not, we don't allow access.
  445. // @see OgSelectionHandler::getReferencableEntities()
  446. $required = FALSE;
  447. foreach (og_get_group_audience_fields('node', $type) as $field_name => $label) {
  448. $field = field_info_field($field_name);
  449. $instance = field_info_instance('node', $field_name, $type);
  450. // Set the "field mode" to default, before passing it to the
  451. // selection handler.
  452. $instance['field_mode'] = 'default';
  453. if (entityreference_get_selection_handler($field, $instance)->countReferencableEntities()) {
  454. return NODE_ACCESS_ALLOW;
  455. }
  456. // Allow users to create content outside of groups, if none of the
  457. // audience fields is required.
  458. if ($instance['required']) {
  459. $required = TRUE;
  460. }
  461. }
  462. // If no group audience field is required, we ignore.
  463. if (!$required) {
  464. return NODE_ACCESS_IGNORE;
  465. }
  466. // Otherwise, ignore or deny based on whether strict node access is set.
  467. return variable_get('og_node_access_strict', TRUE) ? NODE_ACCESS_DENY : NODE_ACCESS_IGNORE;
  468. }
  469. elseif (in_array($op, array('update', 'delete'))) {
  470. $access = og_user_access_entity('administer group', 'node', $node, $account);
  471. if (is_null($access)) {
  472. // The node isn't in an OG context, so no need to keep testing.
  473. return NODE_ACCESS_IGNORE;
  474. }
  475. else {
  476. $access = $access ||
  477. // Any content.
  478. og_user_access_entity("$op any $type content", 'node', $node, $account) ||
  479. // Own content.
  480. ($account->uid == $node->uid && og_user_access_entity("$op own $type content", 'node', $node, $account));
  481. }
  482. if (!$access && $op == 'update' && og_is_group('node', $node)) {
  483. // The node is a group, so check "update group" permission.
  484. $access = og_user_access_entity('update group', 'node', $node, $account);
  485. }
  486. if ($access) {
  487. return NODE_ACCESS_ALLOW;
  488. }
  489. // Check if OG should explicitly deny access or not.
  490. return variable_get('og_node_access_strict', TRUE) ? NODE_ACCESS_DENY : NODE_ACCESS_IGNORE;
  491. }
  492. return NODE_ACCESS_IGNORE;
  493. }
  494. /**
  495. * Implements hook_field_access().
  496. *
  497. * Hide group-audience fields from user's edit profile for non-privileged users.
  498. */
  499. function og_field_access($op, $field, $entity_type, $entity, $account) {
  500. global $user;
  501. if (empty($entity)) {
  502. // We are in field settings page.
  503. return;
  504. }
  505. if (!$user->uid) {
  506. // User is anonymous, and user register might try to add the
  507. // group-audience field.
  508. return;
  509. }
  510. if ($op != 'edit') {
  511. return;
  512. }
  513. $field_name = $field['field_name'];
  514. list($id, $vid, $bundle_name) = entity_extract_ids($entity_type, $entity);
  515. if ($field_name == OG_GROUP_FIELD) {
  516. $wrapper = entity_metadata_wrapper($entity_type, $entity);
  517. if ($wrapper->getIdentifier() && !$wrapper->{OG_GROUP_FIELD}->value()) {
  518. // Entity isn't an active group.
  519. return;
  520. }
  521. $instance = field_info_instance($entity_type, $field_name, $bundle_name);
  522. if (!empty($instance['widget']['settings']['og_hide'])) {
  523. return FALSE;
  524. }
  525. return;
  526. }
  527. if (!og_is_group_audience_field($field_name)) {
  528. return;
  529. }
  530. $field = field_info_field($field_name);
  531. $settings = $field['settings']['handler_settings'];
  532. // Check if we are editing the user entity.
  533. if ($entity_type == 'user') {
  534. return user_access('administer group', $account);
  535. }
  536. }
  537. /**
  538. * Implements hook_views_api().
  539. */
  540. function og_views_api() {
  541. return array(
  542. 'api' => 3,
  543. 'path' => drupal_get_path('module', 'og') . '/includes/views',
  544. );
  545. }
  546. /**
  547. * Implements hook_field_create_instance().
  548. *
  549. * - Create default OG roles per entity-type and bundle.
  550. * - Create a group audience field on the user's entity, referencing the first
  551. * group defined.
  552. */
  553. function og_field_create_instance($instance) {
  554. if ($instance['field_name'] != OG_GROUP_FIELD) {
  555. return;
  556. }
  557. // Create default roles per entity-type per bundle.
  558. og_roles_override($instance['entity_type'], $instance['bundle'], 0);
  559. // Check if we need to add a group audience on the user's entity.
  560. // We add a different field, so each field can be set differently.
  561. $entity_type = $instance['entity_type'];
  562. $bundle = $instance['bundle'];
  563. foreach (array_keys(og_get_group_audience_fields()) as $field_name) {
  564. $field = field_info_field($field_name);
  565. if ($field['settings']['target_type'] == $entity_type && empty($field['settings']['handler_settings']['target_bundles'])) {
  566. return;
  567. }
  568. if ($field['settings']['target_type'] == $entity_type && in_array($bundle, $field['settings']['handler_settings']['target_bundles'])) {
  569. return;
  570. }
  571. }
  572. // If we reached here, it means we need to create a field.
  573. // Pick an unused name.
  574. $field_name = substr("og_user_$entity_type", 0, 32);
  575. $i = 1;
  576. while (field_info_field($field_name)) {
  577. $field_name = substr("og_user_$entity_type", 0, 32 - strlen($i)) . $i;
  578. ++$i;
  579. }
  580. $og_field = og_fields_info(OG_AUDIENCE_FIELD);
  581. $og_field['field']['settings']['target_type'] = $entity_type;
  582. $og_field['instance']['label'] = t('Group membership');
  583. // If the user entity type has multiple bundles, make sure to attach a field
  584. // instance to all of them.
  585. $entity_info = entity_get_info('user');
  586. foreach (array_keys($entity_info['bundles']) as $user_bundle) {
  587. og_create_field($field_name, 'user', $user_bundle, $og_field);
  588. }
  589. }
  590. /**
  591. * Implements field_delete_instance().
  592. *
  593. * - Invalidate OG's static cache if a group-audience field is deleted.
  594. * - Delete the default OG roles per entity-type and bundle.
  595. */
  596. function og_field_delete_instance($instance) {
  597. if (og_is_group_audience_field($instance['field_name'])) {
  598. og_invalidate_cache();
  599. }
  600. if ($instance['field_name'] != OG_GROUP_FIELD) {
  601. return;
  602. }
  603. // Get the per-bundle roles.
  604. $roles = og_roles($instance['entity_type'], $instance['bundle']);
  605. foreach ($roles as $rid => $name) {
  606. og_role_delete($rid);
  607. }
  608. }
  609. /**
  610. * Implements hook_field_attach_form().
  611. */
  612. function og_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
  613. list(,, $bundle) = entity_extract_ids($entity_type, $entity);
  614. if (og_get_group_audience_fields($entity_type, $bundle)) {
  615. $form['#validate'][] = 'og_form_group_reference_validate';
  616. }
  617. if ($entity_type == 'user' || !og_is_group_type($entity_type, $bundle)) {
  618. return;
  619. }
  620. $form['#validate'][] = 'og_form_group_manager_validate';
  621. }
  622. /**
  623. * Validate handler; Make sure group-only content permissions are honored.
  624. *
  625. * If a user does not have site-wide node permissions, throw an error if they
  626. * try to post site-wide instead of within a group.
  627. *
  628. * Note: This function does not check group -access- just if a group has been
  629. * Selected.
  630. */
  631. function og_form_group_reference_validate($form, &$form_state) {
  632. global $user;
  633. $entity_type = $form['#entity_type'];
  634. if (empty($form_state[$entity_type])) {
  635. // We are inside field settings page.
  636. return;
  637. }
  638. $account = user_load($user->uid);
  639. $bundle = $form['#bundle'];
  640. $entity = $form['#entity'];
  641. list($id) = entity_extract_ids($entity_type, $entity);
  642. $op = empty($id) ? 'create' : 'update';
  643. if ($entity_type == 'node') {
  644. $node = empty($id) ? $bundle : $entity;
  645. // We call node_node_access() directly as we just want to check the
  646. // permissions using user_acces().
  647. if (node_node_access($node, $op, $account)) {
  648. // User has site-wide permissions to create or edit the node.
  649. return;
  650. }
  651. }
  652. elseif (entity_access($op, $entity_type, $entity, $account)) {
  653. // User has site-wide permissions to create or edit the entity.
  654. return;
  655. }
  656. foreach (array_keys(og_get_group_audience_fields($entity_type, $bundle)) as $field_name) {
  657. // If there is at least one group selected, return.
  658. if (!empty($form_state['values'][$field_name][LANGUAGE_NONE])) {
  659. return;
  660. }
  661. }
  662. // No group selected, throw an error.
  663. form_set_error('og', t('You must select one or more groups for this content.'));
  664. }
  665. /**
  666. * Validate handler; Make sure a group can be created.
  667. *
  668. * We check if the group manager has a matching group-audience field for the
  669. * OG membership to be created in.
  670. */
  671. function og_form_group_manager_validate($form, &$form_state) {
  672. $entity_type = $form['#entity_type'];
  673. $bundle = $form['#bundle'];
  674. if (empty($form_state[$entity_type])) {
  675. // We are inside field settings page.
  676. return;
  677. }
  678. $entity = $form_state[$entity_type];
  679. $langcode = $form_state['values']['language'];
  680. if (!isset($form_state['values']['uid']) || !isset($entity->uid)) {
  681. // There is no user ID property on the entity.
  682. return;
  683. }
  684. if (isset($form_state['values'][OG_GROUP_FIELD]) && empty($form_state['values'][OG_GROUP_FIELD][$langcode][0]['value'])) {
  685. // Not a group.
  686. return;
  687. }
  688. if (!isset($form_state['values'][OG_GROUP_FIELD])) {
  689. // Field doesn't appear in the form, so it is probably hidden by
  690. // hook_field_access(). So check the default value of the field.
  691. $field = field_info_field(OG_GROUP_FIELD);
  692. $instance = field_info_instance($entity_type, OG_GROUP_FIELD, $bundle);
  693. $items = field_get_default_value($entity_type, $entity, $field, $instance, $langcode);
  694. if (empty($items[0]['value'])) {
  695. // Default value is not a group.
  696. return;
  697. }
  698. }
  699. if ($entity_type == 'node') {
  700. // A user might assign the node author by entering a user name in the
  701. // node form, which we then need to translate to a user ID.
  702. // However, this happens later on, in node_submit(), so we do a special
  703. // check for the node entity.
  704. if (!$account = user_load_by_name($form_state['values']['name'])) {
  705. // Invalid username.
  706. return;
  707. }
  708. }
  709. else {
  710. $account = user_load($form_state['values']['uid']);
  711. }
  712. list($id) = entity_extract_ids($entity_type, $entity);
  713. if ($id && $entity->uid == $account->uid) {
  714. // The entity's user ID hasn't changed.
  715. return;
  716. }
  717. if ($access = og_get_best_group_audience_field('user', $account, $entity_type, $bundle)) {
  718. // Matching group audience field found.
  719. return;
  720. }
  721. form_error($form, t("Can't save entity as group, because user @name can't be subscribed to group and become a manager.", array('@name' => format_username($account))));
  722. }
  723. /**
  724. * Implements hook_entity_insert().
  725. */
  726. function og_entity_insert($entity, $entity_type) {
  727. if (!og_is_group($entity_type, $entity)) {
  728. return;
  729. }
  730. list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
  731. if (!empty($entity->uid)) {
  732. // Subscribe the group manager.
  733. og_group($entity_type, $id, array('entity' => $entity->uid));
  734. // Assign roles to group manager.
  735. $name = 'og_group_manager_default_rids_' . $entity_type . '_' . $bundle;
  736. if ($rids = variable_get($name)) {
  737. foreach ($rids as $rid) {
  738. og_role_grant($entity_type, $id, $entity->uid, $rid);
  739. }
  740. }
  741. }
  742. if (!og_is_group_default_access($entity_type, $entity)) {
  743. // Override default roles.
  744. og_roles_override($entity_type, $bundle, $id);
  745. }
  746. }
  747. /**
  748. * Implements hook_entity_update().
  749. */
  750. function og_entity_update($entity, $entity_type) {
  751. if (!og_is_group($entity_type, $entity)) {
  752. return;
  753. }
  754. list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
  755. if (!empty($entity->uid) && !og_is_member($entity_type, $entity, 'user', $entity->uid)) {
  756. // Subscribe the group manager, in case the owner changed.
  757. og_group($entity_type, $id, array('entity' => $entity->uid));
  758. // Assign roles to group manager.
  759. $name = 'og_group_manager_default_rids_' . $entity_type . '_' . $bundle;
  760. if ($rids = variable_get($name)) {
  761. foreach ($rids as $rid) {
  762. og_role_grant($entity_type, $id, $entity->uid, $rid);
  763. }
  764. }
  765. }
  766. $original_entity = $entity->original;
  767. $property = OG_DEFAULT_ACCESS_FIELD;
  768. if (!empty($entity->{$property}) && $entity->{$property} != $original_entity->{$property}) {
  769. if (!og_is_group_default_access($entity_type, $entity)) {
  770. // Override default roles.
  771. og_roles_override($entity_type, $bundle, $id);
  772. }
  773. else {
  774. // Delete overridden roles.
  775. og_delete_user_roles_by_group($entity_type, $entity);
  776. }
  777. }
  778. }
  779. /**
  780. * Implements hook_field_attach_insert().
  781. */
  782. function og_field_attach_insert($entity_type, $entity) {
  783. _og_update_entity_fields($entity_type, $entity);
  784. }
  785. /**
  786. * Implements hook_field_attach_update().
  787. */
  788. function og_field_attach_update($entity_type, $entity) {
  789. _og_update_entity_fields($entity_type, $entity);
  790. }
  791. /**
  792. * Update the field values in the entity, to reflect the membership.
  793. *
  794. * This is used to allow other modules that save a new/ existing entity
  795. * to act on the field values, even before hook_field_load() is called.
  796. */
  797. function _og_update_entity_fields($entity_type, $entity) {
  798. list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
  799. if (!og_is_group_content_type($entity_type, $bundle)) {
  800. return;
  801. }
  802. $wrapper = entity_metadata_wrapper($entity_type, $entity);
  803. foreach (og_get_group_audience_fields($entity_type, $bundle) as $field_name => $label) {
  804. $field = field_info_field($field_name);
  805. $gids = array();
  806. if ($field['cardinality'] == 1) {
  807. if ($og_membership = $wrapper->{$field_name . '__og_membership'}->value()) {
  808. // Wrapper return an array.
  809. $gids = $og_membership[0]->gid;
  810. }
  811. }
  812. else {
  813. foreach ($wrapper->{$field_name . '__og_membership'}->value() as $og_membership) {
  814. $gids[] = $og_membership->gid;
  815. }
  816. }
  817. if ($gids) {
  818. $wrapper->{$field_name}->set($gids);
  819. }
  820. }
  821. }
  822. /**
  823. * Implements hook_entity_delete().
  824. */
  825. function og_entity_delete($entity, $entity_type) {
  826. list($id, , $bundle) = entity_extract_ids($entity_type, $entity);
  827. if (og_is_group($entity_type, $entity)) {
  828. og_delete_user_roles_by_group($entity_type, $entity);
  829. og_membership_delete_by_group($entity_type, $entity);
  830. }
  831. if (og_is_group_content_type($entity_type, $bundle)) {
  832. // As the field attachers are called after hook_entity_presave() we
  833. // can't delete the OG memberships here. So we just mark the entity
  834. // as being deleted, and we will do the actual delete in
  835. // OgBehaviorHandler::delete().
  836. $entity->delete_og_membership = TRUE;
  837. }
  838. }
  839. /**
  840. * Implements hook_og_membership_insert().
  841. */
  842. function og_og_membership_insert($og_membership) {
  843. if ($og_membership->entity_type == 'user' && module_exists('rules')) {
  844. rules_invoke_event('og_user_insert', $og_membership, entity_metadata_wrapper('user', $og_membership->etid));
  845. }
  846. }
  847. /**
  848. * Implements hook_og_membership_update().
  849. */
  850. function og_og_membership_update($og_membership) {
  851. if ($og_membership->entity_type == 'user' && module_exists('rules')) {
  852. if ($og_membership->original->state != OG_STATE_ACTIVE && $og_membership->state == OG_STATE_ACTIVE) {
  853. rules_invoke_event('og_user_approved', $og_membership, entity_metadata_wrapper('user', $og_membership->etid));
  854. }
  855. if ($og_membership->original->state != OG_STATE_BLOCKED && $og_membership->state == OG_STATE_BLOCKED) {
  856. rules_invoke_event('og_user_blocked', $og_membership, entity_metadata_wrapper('user', $og_membership->etid));
  857. }
  858. }
  859. }
  860. /**
  861. * Implements hook_og_membership_delete().
  862. */
  863. function og_og_membership_delete($og_membership) {
  864. if ($og_membership->entity_type != 'user') {
  865. return;
  866. }
  867. // Remove possible records in the {og_users_roles} table.
  868. db_delete('og_users_roles')
  869. ->condition('uid', $og_membership->etid)
  870. ->condition('gid', $og_membership->gid)
  871. ->condition('group_type', $og_membership->group_type)
  872. ->execute();
  873. if (module_exists('rules')) {
  874. rules_invoke_event('og_user_delete', $og_membership, entity_metadata_wrapper('user', $og_membership->etid));
  875. }
  876. }
  877. /**
  878. * Implements hook_og_fields_info().
  879. */
  880. function og_og_fields_info() {
  881. $items[OG_GROUP_FIELD] = array(
  882. 'type' => array('group'),
  883. 'description' => t('Determine if this should be a group.'),
  884. 'field' => array(
  885. 'field_name' => OG_GROUP_FIELD,
  886. 'type' => 'list_boolean',
  887. 'cardinality' => 1,
  888. 'settings' => array(
  889. 'allowed_values' => array(0 => 'Not a group', 1 => 'Group'),
  890. 'allowed_values_function' => '',
  891. ),
  892. ),
  893. 'instance' => array(
  894. 'label' => t('Group'),
  895. 'description' => t('Determine if this is an OG group.'),
  896. 'display_label' => 1,
  897. 'widget' => array(
  898. 'module' => 'options',
  899. 'settings' => array(
  900. 'og_hide' => TRUE,
  901. ),
  902. 'type' => 'options_onoff',
  903. 'weight' => 0,
  904. ),
  905. 'default_value' => array(0 => array('value' => 1)),
  906. 'view modes' => array(
  907. 'full' => array(
  908. 'label' => t('Full'),
  909. 'type' => 'og_group_subscribe',
  910. 'custom settings' => FALSE,
  911. ),
  912. 'teaser' => array(
  913. 'label' => t('Teaser'),
  914. 'type' => 'og_group_subscribe',
  915. 'custom settings' => FALSE,
  916. ),
  917. ),
  918. ),
  919. );
  920. $items[OG_DEFAULT_ACCESS_FIELD] = array(
  921. 'type' => array('group'),
  922. 'description' => t('Determine if group should use default roles and permissions.'),
  923. 'field' => array(
  924. 'field_name' => OG_DEFAULT_ACCESS_FIELD,
  925. 'type' => 'list_boolean',
  926. 'cardinality' => 1,
  927. 'settings' => array('allowed_values' => array(0 => 'Use default roles and permissions', 1 => 'Override default roles and permissions'), 'allowed_values_function' => ''),
  928. ),
  929. 'instance' => array(
  930. 'label' => t('Group roles and permissions'),
  931. 'widget' => array(
  932. 'module' => 'options',
  933. 'settings' => array(),
  934. 'type' => 'options_select',
  935. ),
  936. 'required' => TRUE,
  937. // Use default role and permissions as default value.
  938. 'default_value' => array(0 => array('value' => 0)),
  939. 'view modes' => array(
  940. 'full' => array(
  941. 'label' => t('Full'),
  942. 'type' => 'list_default',
  943. 'custom settings' => FALSE,
  944. ),
  945. 'teaser' => array(
  946. 'label' => t('Teaser'),
  947. 'type' => 'list_default',
  948. 'custom settings' => FALSE,
  949. ),
  950. ),
  951. ),
  952. );
  953. $items[OG_AUDIENCE_FIELD] = array(
  954. 'multiple' => TRUE,
  955. 'type' => array('group content'),
  956. 'description' => t('Determine to which groups this group content is assigned to.'),
  957. 'field' => array(
  958. 'field_name' => OG_AUDIENCE_FIELD,
  959. 'type' => 'entityreference',
  960. 'cardinality' => FIELD_CARDINALITY_UNLIMITED,
  961. 'settings' => array(
  962. 'handler' => 'og',
  963. 'handler_submit' => 'Change handler',
  964. 'handler_settings' => array(
  965. 'behaviors' => array(
  966. 'og_behavior' => array(
  967. 'status' => TRUE,
  968. ),
  969. ),
  970. 'target_bundles' => array(),
  971. 'membership_type' => OG_MEMBERSHIP_TYPE_DEFAULT,
  972. ),
  973. 'target_type' => 'node',
  974. ),
  975. ),
  976. 'instance' => array(
  977. 'label' => t('Groups audience'),
  978. 'widget' => array(
  979. 'type' => 'og_complex',
  980. 'module' => 'og',
  981. 'settings' => array(),
  982. ),
  983. 'settings' => array(
  984. 'behaviors' => array(
  985. 'og_widget' => array(
  986. 'status' => TRUE,
  987. 'default' => array(
  988. 'widget_type' => 'options_select',
  989. ),
  990. 'admin' => array(
  991. 'widget_type' => 'entityreference_autocomplete',
  992. ),
  993. ),
  994. ),
  995. ),
  996. 'view modes' => array(
  997. 'full' => array(
  998. 'label' => t('Full'),
  999. 'type' => 'og_list_default',
  1000. 'custom settings' => FALSE,
  1001. ),
  1002. 'teaser' => array(
  1003. 'label' => t('Teaser'),
  1004. 'type' => 'og_list_default',
  1005. 'custom settings' => FALSE,
  1006. ),
  1007. ),
  1008. ),
  1009. );
  1010. return $items;
  1011. }
  1012. /**
  1013. * Creates a new membership type.
  1014. *
  1015. * If a message type already exists, an exception will be thrown.
  1016. *
  1017. * @return OgMembershipType
  1018. * Returns a new OG membership type object.
  1019. */
  1020. function og_membership_type_create($name, $values = array()) {
  1021. global $language;
  1022. // Make sure the message type doesn't already exist, to prevent duplicate key
  1023. // error.
  1024. if (og_membership_type_load($name)) {
  1025. throw new OgException('Group membership type ' . check_plain($name) . ' already exists.');
  1026. }
  1027. $values['name'] = $name;
  1028. $values += array(
  1029. 'language' => $language->language,
  1030. );
  1031. $wrapper = entity_property_values_create_entity('og_membership_type', $values);
  1032. return $wrapper->value();
  1033. }
  1034. /**
  1035. * OG membership type loader.
  1036. *
  1037. * @param $type_name
  1038. * (optional) The name for this message type. If no type is given all existing
  1039. * types are returned.
  1040. *
  1041. * @return MessageType
  1042. * Returns a fully-loaded message type definition if a type name is passed.
  1043. * Else an array containing all types is returned.
  1044. */
  1045. function og_membership_type_load($name = NULL) {
  1046. // Replace dashes with underscores so this can be used as menu argument
  1047. // loader too.
  1048. $types = entity_load_multiple_by_name('og_membership_type', isset($name) ? array(strtr($name, array('-' => '_'))) : FALSE);
  1049. if (isset($name)) {
  1050. return isset($types[$name]) ? $types[$name] : FALSE;
  1051. }
  1052. return $types;
  1053. }
  1054. /**
  1055. * Inserts or updates an OG membership type entity into the database.
  1056. *
  1057. * @param $og_membership
  1058. * The OG membership type entiyt to be saved.
  1059. *
  1060. * @return
  1061. * Failure to write a record will return FALSE. Otherwise SAVED_NEW or
  1062. * SAVED_UPDATED is returned depending on the operation performed.
  1063. */
  1064. function og_membership_type_save($og_membership) {
  1065. return entity_save('og_membership_type', $og_membership);
  1066. }
  1067. /**
  1068. * Deletes an existing OG membership type.
  1069. *
  1070. * @param $og_membership
  1071. * The OG membership type entity to be deleted.
  1072. */
  1073. function og_membership_type_delete($og_membership) {
  1074. return entity_delete('og_membership_type', $og_membership);
  1075. }
  1076. /**
  1077. * Access callback for the OG membership type entity.
  1078. */
  1079. function og_membership_type_access($op, $entity, $account = NULL, $entity_type = 'og_membership') {
  1080. // No-end user needs access to this entity, so restrict it to admins.
  1081. return user_access('administer group');
  1082. }
  1083. /**
  1084. * Reset static cache related to group membership.
  1085. */
  1086. function og_membership_invalidate_cache() {
  1087. $caches = array(
  1088. 'og_get_entity_groups',
  1089. 'og_get_membership',
  1090. 'og_get_field_og_membership_properties',
  1091. );
  1092. foreach ($caches as $cache) {
  1093. drupal_static_reset($cache);
  1094. }
  1095. }
  1096. /**
  1097. * Creates a new OG membership.
  1098. *
  1099. * If a group membership already exists, an exception will be thrown.
  1100. *
  1101. * @param $group_type
  1102. * The entity type of the group.
  1103. * @param $gid
  1104. * The group ID.
  1105. * @param $entity_type
  1106. * The entity type of the group content.
  1107. * @param $etid
  1108. * The entity ID of the group content.
  1109. * @param $field_name
  1110. * The group audience field name.
  1111. * @param $values
  1112. * (optional) Array of fields values to be attached to the OG membership, that
  1113. * will be processed using entity-metadata wrapper.
  1114. *
  1115. * @return OgMembership
  1116. * Returns a new OG membership object.
  1117. *
  1118. * @see entity_property_values_create_entity()
  1119. */
  1120. function og_membership_create($group_type, $gid, $entity_type, $etid, $field_name, $values = array()) {
  1121. global $language;
  1122. $values += array(
  1123. 'group_type' => $group_type,
  1124. 'gid' => $gid,
  1125. 'entity_type' => $entity_type,
  1126. 'etid' => $etid,
  1127. 'state' => OG_STATE_ACTIVE,
  1128. 'created' => time(),
  1129. 'field_name' => $field_name,
  1130. 'language' => $language->language,
  1131. );
  1132. if (!og_is_group_audience_field($field_name)) {
  1133. throw new OgException(format_string('%field-name is not a valid group-audience field.', array('%field-name' => $field_name)));
  1134. }
  1135. // Get the type from the field.
  1136. $field = field_info_field($field_name);
  1137. $values['type'] = $field['settings']['handler_settings']['membership_type'];
  1138. $wrapper = entity_property_values_create_entity('og_membership', $values);
  1139. return $wrapper->value();
  1140. }
  1141. /**
  1142. * OG membership loader.
  1143. *
  1144. * @param $name
  1145. * (optional) The name for this group membership. If no type is given all existing
  1146. * types are returned.
  1147. *
  1148. * @return OgMembership
  1149. * Returns a fully-loaded group membership definition if a type name is passed.
  1150. * Else an array containing all types is returned.
  1151. */
  1152. function og_membership_load($id) {
  1153. return entity_load_single('og_membership', $id);
  1154. }
  1155. /**
  1156. * Load multiple OG membership entities based on certain conditions.
  1157. *
  1158. * @param $gids
  1159. * An array of group membership IDs.
  1160. * @param $conditions
  1161. * An array of conditions to match against the {entity} table.
  1162. * @param $reset
  1163. * A boolean indicating that the internal cache should be reset.
  1164. *
  1165. * @return
  1166. * An array of group entities, indexed by group ID.
  1167. */
  1168. function og_membership_load_multiple($ids = array(), $conditions = array(), $reset = FALSE) {
  1169. return entity_load('og_membership', $ids, $conditions, $reset);
  1170. }
  1171. /**
  1172. * Get the group membership entity by user and group.
  1173. *
  1174. * @return
  1175. * The OgMembership object if found, or FALSE.
  1176. */
  1177. function og_get_membership($group_type, $gid, $entity_type, $etid) {
  1178. $return = &drupal_static(__FUNCTION__, array());
  1179. $identifier = $group_type . ':' . $gid . ':' . $entity_type . ':' . $etid;
  1180. if (!isset($return[$identifier])) {
  1181. $return[$identifier] = FALSE;
  1182. $query = new EntityFieldQuery();
  1183. $result = $query
  1184. ->entityCondition('entity_type', 'og_membership')
  1185. ->propertyCondition('gid', $gid, '=')
  1186. ->propertyCondition('group_type', $group_type, '=')
  1187. ->propertyCondition('etid', $etid, '=')
  1188. ->propertyCondition('entity_type', $entity_type, '=')
  1189. ->execute();
  1190. if (!empty($result['og_membership'])) {
  1191. $key = key($result['og_membership']);
  1192. $return[$identifier] = $key;
  1193. }
  1194. }
  1195. if (!empty($return[$identifier])) {
  1196. $og_membership = og_membership_load($return[$identifier]);
  1197. return $og_membership;
  1198. }
  1199. return FALSE;
  1200. }
  1201. /**
  1202. * Implements hook_entity_query_alter().
  1203. *
  1204. * Add "og_membership" tag if there's a group audience field in the query.
  1205. *
  1206. * @see og_query_og_membership_alter().
  1207. */
  1208. function og_entity_query_alter(EntityFieldQuery $query) {
  1209. foreach ($query->fieldConditions as $values) {
  1210. if (og_is_group_audience_field($values['field']['field_name'])) {
  1211. $query->addTag('og_membership');
  1212. return;
  1213. }
  1214. }
  1215. }
  1216. /**
  1217. * Implements hook_query_TAG_alter().
  1218. *
  1219. * Join the {og_membership} table and alter the query.
  1220. */
  1221. function og_query_og_membership_alter(QueryAlterableInterface $query) {
  1222. $tables = &$query->getTables();
  1223. $fields = &$query->getFields();
  1224. $conditions = &$query->conditions();
  1225. // Find the group-audience fields.
  1226. $field_names = array();
  1227. foreach ($query->alterMetaData['entity_field_query']->fieldConditions as $values) {
  1228. $field_name = $values['field']['field_name'];
  1229. if (og_is_group_audience_field($field_name)) {
  1230. $field_names[] = $field_name;
  1231. }
  1232. }
  1233. $aliases = array();
  1234. $base_table = FALSE;
  1235. $base_table_alias = '';
  1236. foreach ($tables as $alias => $values) {
  1237. if (!$base_table_alias && empty($values['join type'])) {
  1238. $base_table_alias = $alias;
  1239. }
  1240. if (strpos($alias, 'field_data') !== 0) {
  1241. continue;
  1242. }
  1243. $field_name = substr($values['table'], 11);
  1244. if (!in_array($field_name, $field_names)) {
  1245. continue;
  1246. }
  1247. if (empty($values['join type'])) {
  1248. // This is the base table, so remove it in favor of OG membership.
  1249. $base_table = TRUE;
  1250. }
  1251. unset($tables[$alias]);
  1252. $aliases[$alias] = $field_name;
  1253. }
  1254. foreach ($aliases as $alias => $field_name) {
  1255. foreach ($tables as $key => $values) {
  1256. $condition = str_replace("$alias.entity_type", 'ogm.entity_type', $values['condition']);
  1257. $condition = str_replace("$alias.entity_id", 'ogm.etid', $condition);
  1258. $tables[$key]['condition'] = $condition;
  1259. }
  1260. }
  1261. $entity_type = $query->alterMetaData['entity_field_query']->entityConditions['entity_type']['value'];
  1262. $entity_type = is_array($entity_type) ? $entity_type[0] : $entity_type;
  1263. $entity_info = entity_get_info($entity_type);
  1264. $id = $entity_info['entity keys']['id'];
  1265. if ($base_table) {
  1266. // If the table of the base entity does not exist (e.g. there is no
  1267. // property condition), we need to add it, as we don't have the
  1268. // revision ID and bundle in {og_membership} table.
  1269. $base_table = $entity_info['base table'];
  1270. if (strpos($base_table_alias, 'field_data') === 0) {
  1271. // Check if the entity base table already exists.
  1272. $base_table_alias = FALSE;
  1273. foreach ($tables as $table) {
  1274. if ($table['table'] == $base_table) {
  1275. $base_table_alias = $table['alias'];
  1276. break;
  1277. }
  1278. }
  1279. if (!$base_table_alias) {
  1280. $base_table_alias = $query->innerJoin($base_table, NULL, "$base_table.$id = ogm.etid");
  1281. }
  1282. }
  1283. // Point the revision ID and bundle to the base entity.
  1284. $fields['revision_id']['table'] = $base_table;
  1285. // If there is no revision table, use the bundle.
  1286. if (!empty($entity_info['entity keys']['revision'])) {
  1287. // Entity doesn't support revisions.
  1288. $fields['revision_id']['field'] = $entity_info['entity keys']['revision'];
  1289. }
  1290. elseif (!empty($entity_info['entity keys']['bundle'])) {
  1291. $fields['revision_id']['field'] = $entity_info['entity keys']['bundle'];
  1292. }
  1293. else {
  1294. // Entity doesn't have bundles (e.g. user).
  1295. $fields['revision_id']['field'] = $id;
  1296. }
  1297. $fields['bundle']['table'] = $base_table;
  1298. $fields['bundle']['field'] = !empty($entity_info['entity keys']['bundle']) ? $entity_info['entity keys']['bundle'] : $id;
  1299. $fields['entity_type']['table'] = 'ogm';
  1300. $fields['entity_id']['table'] = 'ogm';
  1301. $fields['entity_id']['field'] = 'etid';
  1302. $ogm = array(
  1303. 'join type' => NULL,
  1304. 'table' => 'og_membership',
  1305. 'alias' => 'ogm',
  1306. 'condition' => '',
  1307. 'arguments' => array(),
  1308. );
  1309. $tables = array_merge(array('ogm' => $ogm), $tables);
  1310. }
  1311. else {
  1312. $query->join('og_membership', 'ogm', "ogm.etid = $base_table_alias.entity_id");
  1313. }
  1314. _og_query_og_membership_alter_conditions($conditions, $aliases, $base_table_alias, $entity_info);
  1315. }
  1316. /**
  1317. * Recursively replace the fields to their aliases in the query's conditions.
  1318. *
  1319. * See og_query_og_membership_alter().
  1320. */
  1321. function _og_query_og_membership_alter_conditions(&$conditions, $aliases, $base_table_alias, $entity_info) {
  1322. foreach ($conditions as $delta => $values) {
  1323. if (!is_array($values)) {
  1324. continue;
  1325. }
  1326. // Handle conditions in a sub-query.
  1327. if (is_object($values['value'])) {
  1328. _og_query_og_membership_alter_conditions($values['value']->conditions(), $aliases, $base_table_alias, $entity_info);
  1329. }
  1330. // Handle sub-conditions.
  1331. if (is_object($values['field'])) {
  1332. _og_query_og_membership_alter_conditions($values['field']->conditions(), $aliases, $base_table_alias, $entity_info);
  1333. continue;
  1334. }
  1335. if (strpos($values['field'], 'field_data_') !== 0) {
  1336. continue;
  1337. }
  1338. // Explode spaces on the fiels, for handling only the first part in values
  1339. // such as "foo.nid = bar.nid".
  1340. $field_parts = explode(' ', $values['field'], 2);
  1341. list($table, $column) = explode('.', $field_parts[0]);
  1342. if (empty($aliases[$table])) {
  1343. continue;
  1344. }
  1345. $table = 'ogm';
  1346. // Replace entity_id or any other primary id (e.g. nid for the node
  1347. // entity).
  1348. $id_columns = array('entity_id', $entity_info['entity keys']['id']);
  1349. if (in_array($column, $id_columns)) {
  1350. $column = 'etid';
  1351. }
  1352. if ($column == 'deleted') {
  1353. unset($conditions[$delta]);
  1354. continue;
  1355. }
  1356. elseif (strpos($column, 'target_id')) {
  1357. $column = 'gid';
  1358. }
  1359. elseif ($column == 'bundle') {
  1360. // Add the bundle of the base entity type.
  1361. $table = $base_table_alias;
  1362. $column = $entity_info['entity keys']['bundle'];
  1363. }
  1364. $conditions[$delta]['field'] = "$table.$column";
  1365. // Add the second part if it exists.
  1366. if (!empty($field_parts[1])) {
  1367. $conditions[$delta]['field'] .= ' ' . $field_parts[1];
  1368. }
  1369. }
  1370. }
  1371. /**
  1372. * Inserts or updates an OG membership entity into the database.
  1373. *
  1374. * @param $og_membership
  1375. * The OG membership entity to be inserted.
  1376. *
  1377. * @return
  1378. * Failure to write a record will return FALSE. Otherwise SAVED_NEW or
  1379. * SAVED_UPDATED is returned depending on the operation performed.
  1380. */
  1381. function og_membership_save($og_membership) {
  1382. return entity_save('og_membership', $og_membership);
  1383. }
  1384. /**
  1385. * Delete an existing OG membership.
  1386. *
  1387. * @param $id
  1388. * The OG membership entity ID to be deleted.
  1389. */
  1390. function og_membership_delete($id) {
  1391. return og_membership_delete_multiple(array($id));
  1392. }
  1393. /**
  1394. * Delete multiple existing OG memberships.
  1395. *
  1396. * We can't use entity_delete_multiple(), as we need to make sure the field
  1397. * cache is invalidated.
  1398. *
  1399. * @param $ids
  1400. * Array with OG membership entity IDs to be deleted.
  1401. */
  1402. function og_membership_delete_multiple($ids = array()) {
  1403. entity_delete_multiple('og_membership', $ids);
  1404. og_membership_invalidate_cache();
  1405. }
  1406. /**
  1407. * Implements hook_cron_queue_info().
  1408. */
  1409. function og_cron_queue_info() {
  1410. $items['og_membership_orphans'] = array(
  1411. 'title' => t('OG orphans'),
  1412. 'worker callback' => 'og_membership_orphans_worker',
  1413. 'time' => 60,
  1414. );
  1415. return $items;
  1416. }
  1417. /**
  1418. * Queue worker; Process a queue item.
  1419. *
  1420. * Delete memberships, and if needed all related group-content.
  1421. */
  1422. function og_membership_orphans_worker($data) {
  1423. $group_type = $data['group_type'];
  1424. $gid = $data['gid'];
  1425. $query = new EntityFieldQuery();
  1426. $result = $query
  1427. ->entityCondition('entity_type', 'og_membership')
  1428. ->propertyCondition('group_type', $group_type, '=')
  1429. ->propertyCondition('gid', $gid, '=')
  1430. ->propertyOrderBy('id')
  1431. ->range(0, 50)
  1432. ->execute();
  1433. if (empty($result['og_membership'])) {
  1434. return;
  1435. }
  1436. $ids = array_keys($result['og_membership']);
  1437. if ($data['orphans']['move']) {
  1438. _og_orphans_move($ids, $data['orphans']['move']['group_type'], $data['orphans']['move']['gid']);
  1439. $queue = DrupalQueue::get('og_membership_orphans');
  1440. return $queue->createItem($data);
  1441. }
  1442. elseif ($data['orphans']['delete']) {
  1443. _og_orphans_delete($ids);
  1444. // Create a new item.
  1445. $queue = DrupalQueue::get('og_membership_orphans');
  1446. return $queue->createItem($data);
  1447. }
  1448. }
  1449. /**
  1450. * Helper function to delete orphan group-content.
  1451. *
  1452. * @param $ids
  1453. * Array of OG membership IDs.
  1454. *
  1455. * @see og_membership_delete_by_group_worker()
  1456. */
  1457. function _og_orphans_delete($ids) {
  1458. // Get all the group-content that is now orphan.
  1459. $orphans = array();
  1460. $og_memberships = og_membership_load_multiple($ids);
  1461. foreach ($og_memberships as $og_membership) {
  1462. $entity_type = $og_membership->entity_type;
  1463. $id = $og_membership->etid;
  1464. // Don't delete users.
  1465. if ($entity_type == 'user') {
  1466. continue;
  1467. }
  1468. $entity_groups = og_get_entity_groups($entity_type, $id);
  1469. // Orphan node can be relate to only one type of entity group.
  1470. if (count($entity_groups) == 1) {
  1471. $gids = reset($entity_groups);
  1472. // Orphan node can be relate to only one node.
  1473. if (count($gids) > 1) {
  1474. continue;
  1475. }
  1476. }
  1477. $orphans[$entity_type][] = $id;
  1478. }
  1479. if ($orphans) {
  1480. foreach ($orphans as $entity_type => $orphan_ids) {
  1481. entity_delete_multiple($entity_type, $orphan_ids);
  1482. }
  1483. }
  1484. // Delete the OG memberships.
  1485. og_membership_delete_multiple($ids);
  1486. }
  1487. /**
  1488. * Helper function to move orphan group-content to another group.
  1489. *
  1490. * @param $ids
  1491. * Array of OG membership IDs.
  1492. *
  1493. * @see og_membership_delete_by_group_worker()
  1494. */
  1495. function _og_orphans_move($ids, $group_type, $gid) {
  1496. if (!og_is_group($group_type, $gid)) {
  1497. $params = array(
  1498. '@group-type' => $group_type,
  1499. '@gid' => $gid,
  1500. );
  1501. throw new OgException(format_string('Cannot move orphan group-content to @group-type - @gid, as it is not a valid group.', $params));
  1502. }
  1503. $og_memberships = og_membership_load_multiple($ids);
  1504. foreach ($og_memberships as $og_membership) {
  1505. $entity_type = $og_membership->entity_type;
  1506. $id = $og_membership->etid;
  1507. if (count(og_get_entity_groups($entity_type, $id)) > 1) {
  1508. continue;
  1509. }
  1510. $og_membership->group_type = $group_type;
  1511. $og_membership->gid = $gid;
  1512. $og_membership->save();
  1513. }
  1514. }
  1515. /**
  1516. * Register memberships for deletion.
  1517. *
  1518. * if the property "skip_og_membership_delete_by_group" exists on the
  1519. * entity, this function will return early, and allow other implementing
  1520. * modules to deal with the deletion logic.
  1521. *
  1522. * @param $entity_type
  1523. * The group type.
  1524. * @param $entity
  1525. * The group entity object.
  1526. */
  1527. function og_membership_delete_by_group($entity_type, $entity) {
  1528. if (!empty($entity->skip_og_membership_delete_by_group)) {
  1529. return;
  1530. }
  1531. list($gid) = entity_extract_ids($entity_type, $entity);
  1532. $query = new EntityFieldQuery();
  1533. $result = $query
  1534. ->entityCondition('entity_type', 'og_membership')
  1535. ->propertyCondition('group_type', $entity_type, '=')
  1536. ->propertyCondition('gid', $gid, '=')
  1537. ->execute();
  1538. if (empty($result['og_membership'])) {
  1539. return;
  1540. }
  1541. if (variable_get('og_use_queue', FALSE)) {
  1542. $queue = DrupalQueue::get('og_membership_orphans');
  1543. // Add item to the queue.
  1544. $data = array(
  1545. 'group_type' => $entity_type,
  1546. 'gid' => $gid,
  1547. // Allow implementing modules to determine the disposition (e.g. delete
  1548. // orphan group content).
  1549. 'orphans' => array(
  1550. 'delete' => isset($entity->og_orphans['delete']) ? $entity->og_orphans['delete'] : variable_get('og_orphans_delete', FALSE),
  1551. 'move' => isset($entity->og_orphans['move']) ? $entity->og_orphans['move'] : array(),
  1552. ),
  1553. );
  1554. // Exit now, as the task will be processed via queue.
  1555. return $queue->createItem($data);
  1556. }
  1557. // No scalable solution was chosen, so just delete OG memberships.
  1558. og_membership_delete_multiple(array_keys($result['og_membership']));
  1559. }
  1560. /**
  1561. * Label callback; Return the label of OG membership entity.
  1562. */
  1563. function og_membership_label($og_membership) {
  1564. $wrapper = entity_metadata_wrapper('og_membership', $og_membership);
  1565. $params = array(
  1566. '@entity' => $wrapper->entity->label(),
  1567. '@group' => $wrapper->group->label(),
  1568. );
  1569. return t('@entity in group @group', $params);
  1570. }
  1571. /**
  1572. * Access callback for the group membership entity.
  1573. */
  1574. function og_membership_access($op, $entity, $account = NULL, $entity_type = 'og_membership') {
  1575. // No-end user needs access to this entity, so restrict it to admins.
  1576. return user_access('administer group');
  1577. }
  1578. /**
  1579. * Return TRUE if the entity is acting as a group.
  1580. *
  1581. * @param $entity_type
  1582. * The entity type.
  1583. * @param $entity
  1584. * The entity object, or the entity ID.
  1585. */
  1586. function og_is_group($entity_type, $entity) {
  1587. $wrapper = entity_metadata_wrapper($entity_type, $entity);
  1588. $bundle = $wrapper->getBundle();
  1589. if (!field_info_instance($entity_type, OG_GROUP_FIELD, $bundle)) {
  1590. return variable_get("og_is_group__{$entity_type}__{$bundle}", FALSE);
  1591. }
  1592. return !empty($wrapper->{OG_GROUP_FIELD}) && $wrapper->{OG_GROUP_FIELD}->value();
  1593. }
  1594. /**
  1595. * Invalidate cache.
  1596. *
  1597. * @param $gids
  1598. * Array with group IDs that their cache should be invalidated.
  1599. */
  1600. function og_invalidate_cache($gids = array()) {
  1601. // Reset static cache.
  1602. $caches = array(
  1603. 'og_user_access',
  1604. 'og_user_access_alter',
  1605. 'og_role_permissions',
  1606. 'og_get_user_roles',
  1607. 'og_get_permissions',
  1608. 'og_get_group_audience_fields',
  1609. );
  1610. foreach ($caches as $cache) {
  1611. drupal_static_reset($cache);
  1612. }
  1613. // Invalidate group membersihp cache.
  1614. og_membership_invalidate_cache();
  1615. // Let other OG modules know we invalidate cache.
  1616. module_invoke_all('og_invalidate_cache', $gids);
  1617. }
  1618. /**
  1619. * Return all existing groups of an entity type.
  1620. */
  1621. function og_get_all_group($group_type = 'node') {
  1622. if (!field_info_field(OG_GROUP_FIELD)) {
  1623. return array();
  1624. }
  1625. $query = new EntityFieldQuery();
  1626. $return = $query
  1627. ->entityCondition('entity_type', $group_type)
  1628. ->fieldCondition(OG_GROUP_FIELD, 'value', 1, '=')
  1629. ->execute();
  1630. return !empty($return[$group_type]) ? array_keys($return[$group_type]) : array();
  1631. }
  1632. /**
  1633. * Get the first best matching group-audience field.
  1634. *
  1635. * @param $entity_type
  1636. * The entity type.
  1637. * @param $entity
  1638. * The entity object.
  1639. * @param $group_type
  1640. * The group type.
  1641. * @param $group_bundle
  1642. * The group bundle.
  1643. * @param $skip_access
  1644. * TRUE, if current user access to the field, should be skipped.
  1645. * Defaults to FALSE.
  1646. */
  1647. function og_get_best_group_audience_field($entity_type, $entity, $group_type, $group_bundle, $skip_access = FALSE) {
  1648. list(,, $bundle) = entity_extract_ids($entity_type, $entity);
  1649. $field_names = og_get_group_audience_fields($entity_type, $bundle);
  1650. if (!$field_names) {
  1651. return;
  1652. }
  1653. foreach ($field_names as $field_name => $label) {
  1654. $field = field_info_field($field_name);
  1655. $settings = $field['settings'];
  1656. if ($settings['target_type'] != $group_type) {
  1657. // Group type doesn't match.
  1658. continue;
  1659. }
  1660. if (!empty($settings['handler_settings']['target_bundles']) && !in_array($group_bundle, $settings['handler_settings']['target_bundles'])) {
  1661. // Bundles don't match.
  1662. continue;
  1663. }
  1664. if (!og_check_field_cardinality($entity_type, $entity, $field_name)) {
  1665. // Field reached maximum.
  1666. continue;
  1667. }
  1668. if (!$skip_access && !field_access('view', $field, $entity_type, $entity)) {
  1669. // User can't access field.
  1670. continue;
  1671. }
  1672. return $field_name;
  1673. }
  1674. }
  1675. /**
  1676. * Return TRUE if a field can be used and has not reached maximum values.
  1677. *
  1678. * @param $entity_type
  1679. * The entity type.
  1680. * @param $entity
  1681. * The entity object or entity ID.
  1682. * @param $field_name
  1683. * The group audience field name.
  1684. */
  1685. function og_check_field_cardinality($entity_type, $entity, $field_name) {
  1686. $field = field_info_field($field_name);
  1687. if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) {
  1688. return TRUE;
  1689. }
  1690. $wrapper = entity_metadata_wrapper($entity_type, $entity);
  1691. return count($wrapper->{$field_name . '__og_membership'}->value(array('identifier' => TRUE))) < $field['cardinality'];
  1692. }
  1693. /**
  1694. * Set an association (e.g. subscribe) an entity to a group.
  1695. *
  1696. * @param $group_type
  1697. * The entity type of the group.
  1698. * @param $gid
  1699. * The group entity or ID.
  1700. * @param $values
  1701. * Array with the information to pass along, until it is processed in the
  1702. * field handlers.
  1703. * - "entity_type": (optional) The entity type (e.g. "node" or "user").
  1704. * Defaults to 'user'
  1705. * - "entity": (optional) The entity object or entity Id to set the
  1706. * association. Defaults to the current user if the $entity_type property is
  1707. * set to 'user'.
  1708. * - "field_name": The name of the field, the membership should be registered
  1709. * in. If no value given, a first field with the correct membership type
  1710. * will be used. If no field found, an execpetion will be thrown.
  1711. * @param $save_created
  1712. * (optional) If the OG membership is new, it determines whether the
  1713. * membership will be saved. Defaults to TRUE.
  1714. *
  1715. * @return
  1716. * The OG membership entity.
  1717. */
  1718. function og_group($group_type, $gid, $values = array(), $save_created = TRUE) {
  1719. global $user;
  1720. // Set default values.
  1721. $values += array(
  1722. 'entity_type' => 'user',
  1723. 'entity' => FALSE,
  1724. 'field_name' => FALSE,
  1725. 'state' => OG_STATE_ACTIVE,
  1726. );
  1727. $entity_type = $values['entity_type'];
  1728. $entity = $values['entity'];
  1729. $field_name = $values['field_name'];
  1730. $state = $values['state'];
  1731. if ($entity_type == 'user' && empty($entity)) {
  1732. // We don't pass the object, as we want entity_metadata_wrapper() to reload
  1733. // the user object.
  1734. $entity = $user->uid;
  1735. }
  1736. $wrapper = entity_metadata_wrapper($entity_type, $entity);
  1737. // If entity was an ID, get the object.
  1738. $entity = $wrapper->value();
  1739. $bundle = $wrapper->getBundle();
  1740. $id = $wrapper->getIdentifier();
  1741. if (is_object($gid)) {
  1742. $group = $gid;
  1743. }
  1744. else {
  1745. $group = entity_load_single($group_type, $gid);
  1746. }
  1747. // the group ID might be the entity, so re-popualte it.
  1748. list($gid,, $group_bundle) = entity_extract_ids($group_type, $group);
  1749. // Get membership if exists.
  1750. $og_membership = og_get_membership($group_type, $gid, $entity_type, $id);
  1751. if (!$og_membership && empty($field_name)) {
  1752. $params = array(
  1753. '%entity-type' => $entity_type,
  1754. '%bundle' => $bundle,
  1755. '%group-type' => $group_type,
  1756. '%group-bundle' => $group_bundle,
  1757. );
  1758. // Allow getting fields not accessible by the user.
  1759. $field_name = og_get_best_group_audience_field($entity_type, $entity, $group_type, $group_bundle, TRUE);
  1760. if (!$field_name) {
  1761. throw new OgException(format_string('There are no OG fields in entity %entity-type and bundle %bundle referencing %group-type - %group-bundle.', $params));
  1762. }
  1763. }
  1764. if ($og_membership) {
  1765. if (empty($og_membership->is_new) && $og_membership->field_name == $field_name && $og_membership->state == $state) {
  1766. // Entity is already associated with group.
  1767. return $og_membership;
  1768. }
  1769. elseif (!empty($field_name) && $og_membership->field_name != $field_name) {
  1770. // Ungroup the current association, as it needs to change field.
  1771. og_ungroup($group_type, $gid, $entity_type, $id);
  1772. $og_membership = FALSE;
  1773. }
  1774. elseif ($og_membership->state != $state){
  1775. // Change the state.
  1776. $og_membership->state = $state;
  1777. }
  1778. else {
  1779. // Nothing changed.
  1780. return $og_membership;
  1781. }
  1782. }
  1783. if (!$og_membership) {
  1784. // Unset the values, so we don't try to process them.
  1785. unset($values['entity_type'], $values['entity'], $values['field_name']);
  1786. // Create a new OG membership.
  1787. $og_membership = og_membership_create($group_type, $gid, $entity_type, $id, $field_name, $values);
  1788. }
  1789. if (empty($og_membership->is_new) || $save_created) {
  1790. // Save the membership for update, or if the OG membership is new when
  1791. // "save-created" is TRUE.
  1792. $og_membership->save();
  1793. }
  1794. return $og_membership;
  1795. }
  1796. /**
  1797. * Delete an association (e.g. unsubscribe) of an entity to a group.
  1798. *
  1799. * @param $group_type
  1800. * The entity type (e.g. "node").
  1801. * @param $gid
  1802. * The group entity object or ID, to ungroup.
  1803. * @param $entity_type
  1804. * (optional) The entity type (e.g. "node" or "user").
  1805. * @param $etid
  1806. * (optional) The entity object or ID, to ungroup.
  1807. *
  1808. * @return
  1809. * The entity with the fields updated.
  1810. */
  1811. function og_ungroup($group_type, $gid, $entity_type = 'user', $etid = NULL) {
  1812. if (is_object($gid)) {
  1813. list($gid) = entity_extract_ids($group_type, $gid);
  1814. }
  1815. if ($entity_type == 'user' && empty($etid)) {
  1816. global $user;
  1817. $etid = $user->uid;
  1818. }
  1819. elseif (is_object($etid)) {
  1820. list($etid) = entity_extract_ids($entity_type, $etid);
  1821. }
  1822. if ($og_membership = og_get_membership($group_type, $gid, $entity_type, $etid)) {
  1823. $og_membership->delete();
  1824. }
  1825. }
  1826. /**
  1827. * Determine whether a user has a given privilege.
  1828. *
  1829. * All permission checks in OG should go through this function. This
  1830. * way, we guarantee consistent behavior, and ensure that the superuser
  1831. * and group administrators can perform all actions.
  1832. *
  1833. * @param $group_type
  1834. * The entity type of the group.
  1835. * @param $gid
  1836. * The entity ID of the group.
  1837. * @param $string
  1838. * The permission, such as "administer group", being checked for.
  1839. * @param $account
  1840. * (optional) The account to check. Defaults to the current user.
  1841. * @param $skip_alter
  1842. * (optional) If TRUE then user access will not be sent to other modules
  1843. * using drupal_alter(). This can be used by modules implementing
  1844. * hook_og_user_access_alter() that still want to use og_user_access(), but
  1845. * without causing a recursion. Defaults to FALSE.
  1846. * @param $ignore_admin
  1847. * (optional) When TRUE the specific permission is checked, ignoring the
  1848. * "administer group" permission if the user has it. When FALSE, a user
  1849. * with "administer group" will be granted all permissions.
  1850. * Defaults to FALSE.
  1851. *
  1852. * @return
  1853. * TRUE or FALSE if the current user has the requested permission.
  1854. * NULL, if the given group isn't a valid group.
  1855. */
  1856. function og_user_access($group_type, $gid, $string, $account = NULL, $skip_alter = FALSE, $ignore_admin = FALSE) {
  1857. global $user;
  1858. $perm = &drupal_static(__FUNCTION__, array());
  1859. // Mark the group ID and permissions that invoked an alter.
  1860. $perm_alter = &drupal_static(__FUNCTION__ . '_alter', array());
  1861. if (!og_is_group($group_type, $gid)) {
  1862. // Not a group.
  1863. return NULL;
  1864. }
  1865. if (empty($account)) {
  1866. $account = clone $user;
  1867. }
  1868. // User #1 has all privileges.
  1869. if ($account->uid == 1) {
  1870. return TRUE;
  1871. }
  1872. // Administer group permission.
  1873. if (user_access('administer group', $account) && !$ignore_admin) {
  1874. return TRUE;
  1875. }
  1876. // Group manager has all privileges (if variable is TRUE).
  1877. if (!empty($account->uid) && variable_get('og_group_manager_full_access', TRUE)) {
  1878. $group = entity_load_single($group_type, $gid);
  1879. if (!empty($group->uid) && $group->uid == $account->uid) {
  1880. return TRUE;
  1881. }
  1882. }
  1883. $identifier = $group_type . ':' . $gid;
  1884. // To reduce the number of SQL queries, we cache the user's permissions
  1885. // in a static variable.
  1886. if (!isset($perm[$identifier][$account->uid])) {
  1887. $roles = og_get_user_roles($group_type, $gid, $account->uid);
  1888. $role_permissions = og_role_permissions($roles);
  1889. $perms = array();
  1890. foreach ($role_permissions as $one_role) {
  1891. $perms += $one_role;
  1892. }
  1893. $perm[$identifier][$account->uid] = $perms;
  1894. }
  1895. if (!$skip_alter && empty($perm_alter[$identifier][$account->uid][$string])) {
  1896. // Let modules alter the permissions. since $perm is static we create
  1897. // a clone of it.
  1898. $group = !empty($group) ? $group : entity_load_single($group_type, $gid);
  1899. $temp_perm = $perm[$identifier][$account->uid];
  1900. $context = array(
  1901. 'string' => $string,
  1902. 'group_type' => $group_type,
  1903. 'group' => $group,
  1904. 'account' => $account,
  1905. );
  1906. drupal_alter('og_user_access', $temp_perm, $context);
  1907. // Re-assing the altered permissions.
  1908. $perm[$identifier][$account->uid] = $temp_perm;
  1909. // Make sure alter isn't called for the same permissions.
  1910. $perm_alter[$identifier][$account->uid][$string] = TRUE;
  1911. }
  1912. return !empty($perm[$identifier][$account->uid][$string]) || (!empty($perm[$identifier][$account->uid]['administer group']) && !$ignore_admin);
  1913. }
  1914. /**
  1915. * Check if a user has access to a permission on a certain entity context.
  1916. *
  1917. * @param $perm
  1918. * The organic groups permission.
  1919. * @param $entity_type
  1920. * The entity type.
  1921. * @param $entity
  1922. * The entity object, or the entity ID.
  1923. * @param $account
  1924. * (optional) The user object. If empty the current user will be used.
  1925. *
  1926. * @return
  1927. * Returns TRUE if the user has access to the permission, otherwise FALSE, or
  1928. * if the entity is not in OG context, function will return NULL. This allows
  1929. * a distinction between FALSE - no access, and NULL - no access as no OG
  1930. * context found.
  1931. */
  1932. function og_user_access_entity($perm, $entity_type, $entity, $account = NULL) {
  1933. if (empty($account)) {
  1934. global $user;
  1935. $account = clone $user;
  1936. }
  1937. // Set the default for the case there is not a group or a group content.
  1938. $result = NULL;
  1939. if (empty($entity)) {
  1940. // $entity might be NULL, so return early.
  1941. // @see field_access().
  1942. return $result;
  1943. }
  1944. elseif (is_numeric($entity)) {
  1945. $entity = entity_load_single($entity_type, $entity);
  1946. }
  1947. list($id, $vid, $bundle_name) = entity_extract_ids($entity_type, $entity);
  1948. if (empty($id)) {
  1949. // Entity isn't saved yet.
  1950. return $result;
  1951. }
  1952. $is_group = og_is_group($entity_type, $entity);
  1953. $is_group_content = og_is_group_content_type($entity_type, $bundle_name);
  1954. if ($is_group) {
  1955. if (og_user_access($entity_type, $id, $perm, $account)) {
  1956. return TRUE;
  1957. }
  1958. else {
  1959. // An entity can be a group and group content in the same time. The group
  1960. // didn't return TRUE, but the user still might have access to the
  1961. // permission in group content context.
  1962. $result = FALSE;
  1963. }
  1964. }
  1965. if ($is_group_content && $groups = og_get_entity_groups($entity_type, $entity)) {
  1966. foreach ($groups as $group_type => $gids) {
  1967. foreach ($gids as $gid) {
  1968. if (og_user_access($group_type, $gid, $perm, $account)) {
  1969. return TRUE;
  1970. }
  1971. }
  1972. }
  1973. return FALSE;
  1974. }
  1975. // Either the user didn't have permission, or the entity might be a
  1976. // disabled group or an orphaned group content.
  1977. return $result;
  1978. }
  1979. /**
  1980. * Get the groups an entity is associated with.
  1981. *
  1982. * @param $entity_type
  1983. * The entity type. Defaults to 'user'
  1984. * @param $entity
  1985. * (optional) The entity object or entity ID. If empty, and $entity_type is
  1986. * "user", the current user will be used.
  1987. * @param $states
  1988. * (optional) Array with the state to return. Defaults to active.
  1989. * @param $field_name
  1990. * (optional) The field name associated with the group.
  1991. *
  1992. * @return
  1993. * An array with the group's entity type as the key, and array - keyed by
  1994. * the OG membership ID and the group ID as the value. If nothing found,
  1995. * then an empty array.
  1996. */
  1997. function og_get_entity_groups($entity_type = 'user', $entity = NULL, $states = array(OG_STATE_ACTIVE), $field_name = NULL) {
  1998. $cache = &drupal_static(__FUNCTION__, array());
  1999. if ($entity_type == 'user' && empty($entity)) {
  2000. global $user;
  2001. $entity = clone $user;
  2002. }
  2003. if (is_object($entity)) {
  2004. // Get the entity ID.
  2005. list($id) = entity_extract_ids($entity_type, $entity);
  2006. }
  2007. else {
  2008. $id = $entity;
  2009. }
  2010. // Get a string identifier of the states, so we can retrieve it from cache.
  2011. if ($states) {
  2012. sort($states);
  2013. $state_identifier = implode(':', $states);
  2014. }
  2015. else {
  2016. $state_identifier = FALSE;
  2017. }
  2018. $identifier = array(
  2019. $entity_type,
  2020. $id,
  2021. $state_identifier,
  2022. $field_name,
  2023. );
  2024. $identifier = implode(':', $identifier);
  2025. if (isset($cache[$identifier])) {
  2026. // Return cached values.
  2027. return $cache[$identifier];
  2028. }
  2029. $cache[$identifier] = array();
  2030. $query = db_select('og_membership', 'ogm')
  2031. ->fields('ogm', array('id', 'gid', 'group_type'))
  2032. ->condition('entity_type', $entity_type)
  2033. ->condition('etid', $id);
  2034. if ($states) {
  2035. $query->condition('state', $states, 'IN');
  2036. }
  2037. if ($field_name) {
  2038. $query->condition('field_name', $field_name);
  2039. }
  2040. $result = $query
  2041. ->execute()
  2042. ->fetchAll();
  2043. foreach ($result as $row) {
  2044. $cache[$identifier][$row->group_type][$row->id] = $row->gid;
  2045. }
  2046. return $cache[$identifier];
  2047. }
  2048. /**
  2049. * Return TRUE if field is a group audience type.
  2050. *
  2051. * @param $field_name
  2052. * The field name.
  2053. */
  2054. function og_is_group_audience_field($field_name) {
  2055. $field = field_info_field($field_name);
  2056. return $field['type'] == 'entityreference' && ($field['settings']['handler'] == 'og' || strpos($field['settings']['handler'], 'og_') === 0);
  2057. }
  2058. /**
  2059. * Get the name of the group-audience type field.
  2060. *
  2061. * @param $entity_type
  2062. * The entity type.
  2063. * @param $bundle_name
  2064. * The bundle name to be checked.
  2065. * @param $group_type
  2066. * Filter list to only include fields referencing a specific group type.
  2067. * @param $group_bundle
  2068. * Filter list to only include fields referencing a specific group bundle.
  2069. * Fields that do not specify any bundle restrictions at all are also
  2070. * included.
  2071. *
  2072. * @return
  2073. * Array keyed with the field name and the field label as the value.
  2074. */
  2075. function og_get_group_audience_fields($entity_type = 'user', $bundle_name = 'user', $group_type = NULL, $group_bundle = NULL) {
  2076. $return = &drupal_static(__FUNCTION__, array());
  2077. $identifier = $entity_type . ':' . $bundle_name . ':' . $group_type;
  2078. if (isset($return[$identifier])) {
  2079. return $return[$identifier];
  2080. }
  2081. $return[$identifier] = array();
  2082. foreach (field_info_instances($entity_type, $bundle_name) as $field_name => $instance) {
  2083. if (!og_is_group_audience_field($field_name)) {
  2084. continue;
  2085. }
  2086. $field_info = field_info_field($instance['field_name']);
  2087. if (isset($group_type) && $field_info['settings']['target_type'] != $group_type) {
  2088. continue;
  2089. }
  2090. if ($group_bundle && !empty($field_info['settings']['handler_settings']['target_bundles']) && !in_array($group_bundle, $field_info['settings']['handler_settings']['target_bundles'])) {
  2091. continue;
  2092. }
  2093. $return[$identifier][$field_name] = $instance['label'];
  2094. }
  2095. return $return[$identifier];
  2096. }
  2097. /**
  2098. * Return the group type (i.e. "group" or "group_content") of an entity.
  2099. *
  2100. * @param $entity_type
  2101. * The entity type.
  2102. * @param $bundle_name
  2103. * The bundle name to be checked.
  2104. * @param $type
  2105. * The group usage type. Must be "group" or "group content".
  2106. *
  2107. * @return
  2108. * The group type or an "omitted" if node type doesn't participate in
  2109. * Group.
  2110. */
  2111. function og_get_group_type($entity_type, $bundle_name, $type = 'group') {
  2112. if ($type == 'group') {
  2113. return (bool)field_info_instance($entity_type, OG_GROUP_FIELD, $bundle_name);
  2114. }
  2115. elseif ($type == 'group content') {
  2116. return (bool)og_get_group_audience_fields($entity_type, $bundle_name);
  2117. }
  2118. }
  2119. /**
  2120. * Return TRUE if the entity type is a "group" type.
  2121. *
  2122. * This is a wrapper function around og_get_group_type().
  2123. *
  2124. * @param $node_type
  2125. * The node type to be checked.
  2126. */
  2127. function og_is_group_type($entity_type, $bundle_name) {
  2128. return og_get_group_type($entity_type, $bundle_name);
  2129. }
  2130. /**
  2131. * Return TRUE if the entity type is a "group content" type.
  2132. *
  2133. * This is a wrapper function around og_get_group_type().
  2134. *
  2135. * @param $entity_type
  2136. * The entity type to be checked.
  2137. */
  2138. function og_is_group_content_type($entity_type, $bundle_name) {
  2139. return og_get_group_type($entity_type, $bundle_name, 'group content');
  2140. }
  2141. /**
  2142. * Return all entity types that have bundles that are a group type.
  2143. *
  2144. * @return
  2145. * Array keyed with the entity type machine name and the entity human readable
  2146. * name as the value, or an empty array if no entities are defined as group.
  2147. */
  2148. function og_get_all_group_entity() {
  2149. $return = array();
  2150. foreach (entity_get_info() as $entity_type => $entity_value) {
  2151. foreach ($entity_value['bundles'] as $bundle => $bundle_value) {
  2152. if (og_is_group_type($entity_type, $bundle)) {
  2153. $return[$entity_type] = check_plain($entity_value['label']);
  2154. // At least one bundle of the entity can be a group, so break.
  2155. break;
  2156. }
  2157. }
  2158. }
  2159. return $return;
  2160. }
  2161. /**
  2162. * Return all bundles that are a group type.
  2163. *
  2164. * @return
  2165. * An associative array whose keys are entity types, and whose values are
  2166. * arrays of bundles for that entity type. The array of bundles is keyed by
  2167. * bundle machine name, and the values are bundle labels.
  2168. */
  2169. function og_get_all_group_bundle() {
  2170. $return = array();
  2171. foreach (entity_get_info() as $entity_type => $entity_value) {
  2172. foreach ($entity_value['bundles'] as $bundle => $bundle_value) {
  2173. if (og_is_group_type($entity_type, $bundle)) {
  2174. $return[$entity_type][$bundle] = check_plain($bundle_value['label']);
  2175. }
  2176. }
  2177. }
  2178. return $return;
  2179. }
  2180. /**
  2181. * Return all the entities that are a group content.
  2182. *
  2183. * @return
  2184. * Array keyed with the entity type machine name and the entity human readable
  2185. * name as the value, or an empty array if no entities are defined as group
  2186. * content.
  2187. */
  2188. function og_get_all_group_content_entity() {
  2189. $return = array();
  2190. foreach (entity_get_info() as $entity_type => $entity_value) {
  2191. foreach ($entity_value['bundles'] as $bundle => $bundle_value) {
  2192. if (og_is_group_content_type($entity_type, $bundle)) {
  2193. $return[$entity_type] = check_plain($entity_value['label']);
  2194. // At least one bundle of the entity can be a group, so break.
  2195. break;
  2196. }
  2197. }
  2198. }
  2199. return $return;
  2200. }
  2201. /**
  2202. * Return all the entities that are a group content.
  2203. *
  2204. * @return
  2205. * Array keyed with the entity type machine name and the entity human readable
  2206. * name as the value, or an empty array if no entities are defined as group
  2207. * content.
  2208. */
  2209. function og_get_all_group_content_bundle() {
  2210. $return = array();
  2211. foreach (entity_get_info() as $entity_type => $entity_value) {
  2212. foreach ($entity_value['bundles'] as $bundle => $bundle_value) {
  2213. if (og_is_group_content_type($entity_type, $bundle)) {
  2214. $return[$entity_type][$bundle] = check_plain($bundle_value['label']);
  2215. }
  2216. }
  2217. }
  2218. return $return;
  2219. }
  2220. /**
  2221. * Return TRUE if entity belongs to a group.
  2222. *
  2223. * @param $group_type
  2224. * The entity type of the group.
  2225. * @param $gid
  2226. * The group ID.
  2227. * @param $entity_type
  2228. * The entity type.
  2229. * @param $entity
  2230. * The entity object. If empty the current user will be used.
  2231. * @param $states
  2232. * (optional) Array with the state to return. If empty groups of all state will
  2233. * return.
  2234. *
  2235. * @return
  2236. * TRUE if the entity (e.g. the user) belongs to a group and is not pending or
  2237. * blocked.
  2238. */
  2239. function og_is_member($group_type, $gid, $entity_type = 'user', $entity = NULL, $states = array(OG_STATE_ACTIVE)) {
  2240. $groups = og_get_entity_groups($entity_type, $entity, $states);
  2241. return !empty($groups[$group_type]) && in_array($gid, $groups[$group_type]);
  2242. }
  2243. /**
  2244. * Check if group should use default roles and permissions.
  2245. *
  2246. * @param $group_type
  2247. * The entity type of the group.
  2248. * @param $gid
  2249. * The group ID or the group entity.
  2250. *
  2251. * @return
  2252. * TRUE if group should use default roles and permissions.
  2253. */
  2254. function og_is_group_default_access($group_type, $gid) {
  2255. $wrapper = entity_metadata_wrapper($group_type, $gid);
  2256. $bundle = $wrapper->getBundle();
  2257. if (!field_info_instance($group_type, OG_DEFAULT_ACCESS_FIELD, $bundle)) {
  2258. return variable_get("og_is_group_default_access__{$group_type}__{$bundle}", TRUE);
  2259. }
  2260. if (empty($wrapper->{OG_DEFAULT_ACCESS_FIELD})) {
  2261. return TRUE;
  2262. }
  2263. return !$wrapper->{OG_DEFAULT_ACCESS_FIELD}->value();
  2264. }
  2265. /**
  2266. * Determine the permissions for one or more roles.
  2267. *
  2268. * @param $roles
  2269. * An array whose keys are the role IDs of interest.
  2270. *
  2271. * @return
  2272. * An array indexed by role ID. Each value is an array whose keys are the
  2273. * permission strings for the given role ID.
  2274. */
  2275. function og_role_permissions($roles = array()) {
  2276. $cache = &drupal_static(__FUNCTION__, array());
  2277. $role_permissions = $fetch = array();
  2278. if ($roles) {
  2279. foreach ($roles as $rid => $name) {
  2280. if (isset($cache[$rid])) {
  2281. $role_permissions[$rid] = $cache[$rid];
  2282. }
  2283. else {
  2284. // Add this rid to the list of those needing to be fetched.
  2285. $fetch[] = $rid;
  2286. // Prepare in case no permissions are returned.
  2287. $cache[$rid] = array();
  2288. }
  2289. }
  2290. if ($fetch) {
  2291. // Get from the database permissions that were not in the static variable.
  2292. // Only role IDs with at least one permission assigned will return rows.
  2293. $result = db_query("SELECT rid, permission FROM {og_role_permission} WHERE rid IN (:fetch)", array(':fetch' => $fetch));
  2294. foreach ($result as $row) {
  2295. $cache[$row->rid][$row->permission] = TRUE;
  2296. }
  2297. foreach ($fetch as $rid) {
  2298. // For every rid, we know we at least assigned an empty array.
  2299. $role_permissions[$rid] = $cache[$rid];
  2300. }
  2301. }
  2302. }
  2303. return $role_permissions;
  2304. }
  2305. /**
  2306. * Retrieve an array of roles matching specified conditions.
  2307. *
  2308. * @param $group_type
  2309. * The group type.
  2310. * @param $bundle
  2311. * The bundle type.
  2312. * @param $gid
  2313. * The group ID.
  2314. * @param $force_group
  2315. * (optional) If TRUE then the roles of the group will be retrieved by the
  2316. * group ID, even if the group is set to have default roles and permissions.
  2317. * The group might be set to "Default access" but infact there are inactive
  2318. * group roles. Thus, we are forcing the function to return the overriden
  2319. * roles. see og_delete_user_roles_by_group().
  2320. * @param $include_all
  2321. * (optional) If TRUE then the anonymous and authenticated default roles will
  2322. * be included.
  2323. *
  2324. * @return
  2325. * An associative array with the role id as the key and the role name as
  2326. * value. The anonymous and authenticated default roles are on the top of the
  2327. * array.
  2328. */
  2329. function og_roles($group_type, $bundle, $gid = 0, $force_group = FALSE, $include_all = TRUE) {
  2330. if ($gid && !$bundle) {
  2331. $wrapper = entity_metadata_wrapper($group_type, $gid);
  2332. $bundle = $wrapper->getBundle();
  2333. }
  2334. // Check if overriden access exists.
  2335. if ($gid && !$force_group) {
  2336. $query_gid = og_is_group_default_access($group_type, $gid) ? 0 : $gid;
  2337. }
  2338. else {
  2339. $query_gid = $gid;
  2340. }
  2341. $query = db_select('og_role', 'ogr')
  2342. ->fields('ogr', array('rid', 'name'))
  2343. ->condition('group_type', $group_type, '=')
  2344. ->condition('group_bundle', $bundle, '=')
  2345. ->condition('gid', $query_gid, '=')
  2346. ->orderBy('rid', 'ASC');
  2347. if (!$include_all) {
  2348. $query->condition('name', array(OG_ANONYMOUS_ROLE, OG_AUTHENTICATED_ROLE), 'NOT IN');
  2349. }
  2350. $rids = $query
  2351. ->execute()
  2352. ->fetchAllkeyed();
  2353. return $rids;
  2354. }
  2355. /**
  2356. * Get array of default roles, keyed by their declaring module.
  2357. *
  2358. * @param $include
  2359. * (optional) If TRUE also anonymous and authenticated roles will be returned.
  2360. * Defaults to TRUE.
  2361. *
  2362. * @return
  2363. * Array of default roles, grouped by module name.
  2364. */
  2365. function og_get_default_roles($include = TRUE) {
  2366. $roles = array();
  2367. foreach (module_implements('og_default_roles') as $module) {
  2368. $roles = array_merge($roles, module_invoke($module, 'og_default_roles'));
  2369. }
  2370. // Allow other modules to alter the defult roles, excpet of the anonymous and
  2371. // authenticated.
  2372. drupal_alter('og_default_roles', $roles);
  2373. if ($include) {
  2374. array_unshift($roles, OG_AUTHENTICATED_ROLE);
  2375. array_unshift($roles, OG_ANONYMOUS_ROLE);
  2376. }
  2377. return $roles;
  2378. }
  2379. /**
  2380. * Get all roles of a user in a certain group.
  2381. *
  2382. * @param $group_type
  2383. * The entity type of the group.
  2384. * @param $gid
  2385. * The group ID.
  2386. * @param $uid
  2387. * (optional) Integer specifying the user ID. By default an ID of current
  2388. * logged in user will be used.
  2389. * @param $include
  2390. * (optional) If TRUE also anonymous or authenticated role ID will be
  2391. * returned. Defaults to TRUE.
  2392. *
  2393. * @return
  2394. * Array with the role IDs of the user as the key, and the role name as
  2395. * the value.
  2396. */
  2397. function og_get_user_roles($group_type, $gid, $uid = NULL, $include = TRUE) {
  2398. $roles = &drupal_static(__FUNCTION__, array());
  2399. if (empty($uid)) {
  2400. global $user;
  2401. $uid = $user->uid;
  2402. }
  2403. $identifier = implode(':', array($group_type, $gid, $uid, $include));
  2404. if (isset($roles[$identifier])) {
  2405. return $roles[$identifier];
  2406. }
  2407. $group = entity_load_single($group_type, $gid);
  2408. // Get the bundle of the group.
  2409. list($id, $vid, $bundle) = entity_extract_ids($group_type, $group);
  2410. // Check if roles are overriden for the group.
  2411. $query_gid = og_is_group_default_access($group_type, $gid) ? 0 : $gid;
  2412. $query = db_select('og_users_roles', 'ogur');
  2413. $query->innerJoin('og_role', 'ogr', 'ogur.rid = ogr.rid');
  2414. $rids = $query
  2415. ->fields('ogur', array('rid'))
  2416. ->fields('ogr', array('name'))
  2417. ->condition('ogr.group_type', $group_type, '=')
  2418. ->condition('ogr.group_bundle', $bundle, '=')
  2419. ->condition('ogr.gid', $query_gid, '=')
  2420. ->condition('ogur.uid', $uid, '=')
  2421. ->condition('ogur.gid', $gid, '=')
  2422. ->orderBy('rid')
  2423. ->execute()
  2424. ->fetchAllkeyed();
  2425. if ($include) {
  2426. $account = user_load($uid);
  2427. $role_name = og_is_member($group_type, $gid, 'user', $account) ? OG_AUTHENTICATED_ROLE : OG_ANONYMOUS_ROLE;
  2428. $rids = db_select('og_role', 'ogr')
  2429. ->fields('ogr', array('rid', 'name'))
  2430. ->condition('group_type', $group_type, '=')
  2431. ->condition('group_bundle', $bundle, '=')
  2432. ->condition('gid', $query_gid, '=')
  2433. ->condition('name', $role_name, '=')
  2434. ->execute()
  2435. ->fetchAllkeyed() + $rids;
  2436. }
  2437. $roles[$identifier] = $rids;
  2438. return $rids;
  2439. }
  2440. /**
  2441. * Create a stub OG role object.
  2442. *
  2443. * @param $name
  2444. * A name of the role.
  2445. * @param $group_type
  2446. * (optional) The entity type of the group.
  2447. * @param $gid
  2448. * (optional) The group ID.
  2449. * @param $group_bundle
  2450. * (optional) The bundle of the group.
  2451. *
  2452. * @return
  2453. * A stub OG role object.
  2454. */
  2455. function og_role_create($name, $group_type = '', $gid = 0, $group_bundle = '') {
  2456. $role = new stdClass;
  2457. $role->name = $name;
  2458. $role->gid = $gid;
  2459. $role->group_type = $group_type;
  2460. $role->group_bundle = $group_bundle;
  2461. return $role;
  2462. }
  2463. /**
  2464. * Fetch a user role from database.
  2465. *
  2466. * @param $rid
  2467. * An integer with the role ID.
  2468. *
  2469. * @return
  2470. * A fully-loaded role object if a role with the given ID exists,
  2471. * FALSE otherwise.
  2472. */
  2473. function og_role_load($rid) {
  2474. return db_select('og_role', 'r')
  2475. ->fields('r')
  2476. ->condition('rid', $rid)
  2477. ->execute()
  2478. ->fetchObject();
  2479. }
  2480. /**
  2481. * Save a user role to the database.
  2482. *
  2483. * @param $role
  2484. * A role object to modify or add. If $role->rid is not specified, a new
  2485. * role will be created.
  2486. *
  2487. * @return
  2488. * Status constant indicating if role was created or updated.
  2489. * Failure to write the user role record will return FALSE. Otherwise.
  2490. * SAVED_NEW or SAVED_UPDATED is returned depending on the operation
  2491. * performed.
  2492. */
  2493. function og_role_save($role) {
  2494. if ($role->name) {
  2495. // Prevent leading and trailing spaces in role names.
  2496. $role->name = trim($role->name);
  2497. }
  2498. if (!empty($role->rid) && $role->name) {
  2499. $status = drupal_write_record('og_role', $role, 'rid');
  2500. module_invoke_all('og_role_update', $role);
  2501. }
  2502. else {
  2503. $status = drupal_write_record('og_role', $role);
  2504. module_invoke_all('og_role_insert', $role);
  2505. }
  2506. og_invalidate_cache();
  2507. return $status;
  2508. }
  2509. /**
  2510. * Delete a user role from database.
  2511. *
  2512. * @param $rid
  2513. * An integer with the role ID.
  2514. */
  2515. function og_role_delete($rid) {
  2516. $role = og_role_load($rid);
  2517. db_delete('og_role')
  2518. ->condition('rid', $rid)
  2519. ->execute();
  2520. db_delete('og_role_permission')
  2521. ->condition('rid', $rid)
  2522. ->execute();
  2523. // Update the users who have this role set.
  2524. db_delete('og_users_roles')
  2525. ->condition('rid', $rid)
  2526. ->execute();
  2527. module_invoke_all('og_role_delete', $role);
  2528. og_invalidate_cache();
  2529. }
  2530. /**
  2531. * Delete all roles belonging to a group.
  2532. *
  2533. * This will also maintain user roles when revertting an ovverriden group.
  2534. * For example, if in the overridden group users were assigned to the role
  2535. * "administrator", upon reverting back to default roles and
  2536. * permissions, OG will search for existing roles with that name, and re-assign
  2537. * the correct role ID, and the users that had "administrator" will still have
  2538. * it.
  2539. *
  2540. * @param $group_type
  2541. * The group type.
  2542. * @param $gid
  2543. * The group ID.
  2544. */
  2545. function og_delete_user_roles_by_group($group_type, $group) {
  2546. // Check if group has overriden roles defined.
  2547. list($gid, $vid,$bundle) = entity_extract_ids($group_type, $group);
  2548. $global_roles = array_flip(og_roles($group_type, $bundle));
  2549. if ($roles = og_roles($group_type, $bundle, $gid, TRUE)) {
  2550. foreach ($roles as $rid => $name) {
  2551. if (variable_get('og_maintain_overridden_roles', TRUE) && !empty($global_roles[$name])) {
  2552. // Role name exists in the global roles, update the role ID to the
  2553. // global one.
  2554. db_update('og_users_roles')
  2555. ->fields(array('rid' => $global_roles[$name]))
  2556. ->condition('rid', $rid)
  2557. ->condition('group_type', $group_type)
  2558. ->condition('gid', $gid)
  2559. ->execute();
  2560. }
  2561. og_role_delete($rid);
  2562. }
  2563. }
  2564. }
  2565. /**
  2566. * Get the role names of role IDs.
  2567. *
  2568. * @param $rids
  2569. * Array with role IDs.
  2570. * @return
  2571. * Array keyed by the role ID, and the role name as the value.
  2572. */
  2573. function og_get_user_roles_name($rids = array()) {
  2574. if ($rids) {
  2575. $query = db_query("SELECT rid, name FROM {og_role} WHERE rid IN (:rids)", array(':rids' => $rids));
  2576. }
  2577. else {
  2578. $query = db_query("SELECT rid, name FROM {og_role}");
  2579. }
  2580. return $query->fetchAllKeyed();
  2581. }
  2582. /**
  2583. * Delete all permissions defined by a module.
  2584. *
  2585. * @see og_modules_uninstalled()
  2586. *
  2587. * @param $modules
  2588. * Array with the module names.
  2589. */
  2590. function og_permissions_delete_by_module($modules = array()) {
  2591. db_delete('og_role_permission')
  2592. ->condition('module', $modules, 'IN')
  2593. ->execute();
  2594. }
  2595. /**
  2596. * Create new roles, based on the default roles and permissions.
  2597. *
  2598. * @param $group_type
  2599. * The group type.
  2600. * @param $bundle
  2601. * The bundle type.
  2602. * @param $gid
  2603. * The group ID.
  2604. *
  2605. * @return
  2606. * The newly created roles keyed by role ID and role name as the value. Or
  2607. * FALSE if no roles were created.
  2608. */
  2609. function og_roles_override($group_type, $bundle, $gid) {
  2610. // Check if roles aren't already overridden. We can't use
  2611. // og_is_group_default_access() as the field is already set, so we
  2612. // check to see if there are new roles in the database by setting
  2613. // "force group" parameter to TRUE.
  2614. if (og_roles($group_type, $bundle, $gid, TRUE)) {
  2615. return;
  2616. }
  2617. $rids = array();
  2618. if ($gid) {
  2619. // Copy roles from a specific group
  2620. $og_roles = og_roles($group_type, $bundle);
  2621. $perms = og_role_permissions($og_roles);
  2622. }
  2623. else {
  2624. // Copy the global default roles
  2625. $og_roles = og_get_default_roles();
  2626. $perms = og_get_default_permissions();
  2627. }
  2628. foreach ($og_roles as $rid => $name) {
  2629. $role = og_role_create($name, $group_type, $gid, $bundle);
  2630. og_role_save($role);
  2631. $rids[$role->rid] = $role->name;
  2632. og_role_change_permissions($role->rid, $perms[$rid]);
  2633. // Remap the default roles, to the newely created ones.
  2634. db_update('og_users_roles')
  2635. ->fields(array('rid' => $role->rid))
  2636. ->condition('rid', $rid)
  2637. ->condition('group_type', $group_type)
  2638. ->condition('gid', $gid)
  2639. ->execute();
  2640. }
  2641. return $rids;
  2642. }
  2643. /**
  2644. * Grant a group role to a user.
  2645. *
  2646. * @param $group_type
  2647. * The entity type of the group.
  2648. * @param $gid
  2649. * The group ID.
  2650. * @param $uid
  2651. * The user ID.
  2652. * @param $rid
  2653. * The role ID.
  2654. */
  2655. function og_role_grant($group_type, $gid, $uid, $rid) {
  2656. // Make sure the role is valid.
  2657. $group = entity_load_single($group_type, $gid);
  2658. list(,, $bundle) = entity_extract_ids($group_type, $group);
  2659. $og_roles = og_roles($group_type, $bundle, $gid, FALSE, FALSE);
  2660. if (empty($og_roles[$rid])) {
  2661. // Role isn't valid.
  2662. return;
  2663. }
  2664. // Get the existing user roles.
  2665. $user_roles = og_get_user_roles($group_type, $gid, $uid);
  2666. if (empty($user_roles[$rid])) {
  2667. $role = new stdClass();
  2668. $role->uid = $uid;
  2669. $role->rid = $rid;
  2670. $role->group_type = $group_type;
  2671. $role->gid = $gid;
  2672. drupal_write_record('og_users_roles', $role);
  2673. og_invalidate_cache();
  2674. module_invoke_all('og_role_grant', $group_type, $gid, $uid, $rid);
  2675. if (module_exists('rules')) {
  2676. rules_invoke_event('og_role_grant', og_get_membership($group_type, $gid, 'user', $uid), entity_metadata_wrapper('user', $uid), $rid);
  2677. }
  2678. }
  2679. }
  2680. /**
  2681. * Revoke a group role from a user.
  2682. *
  2683. * @param $group_type
  2684. * The entity type of the group.
  2685. * @param $gid
  2686. * The group ID.
  2687. * @param $uid
  2688. * The user ID.
  2689. * @param $rid
  2690. * The role ID.
  2691. */
  2692. function og_role_revoke($group_type, $gid, $uid, $rid) {
  2693. $og_roles = og_get_user_roles($group_type, $gid, $uid);
  2694. if (!empty($og_roles[$rid])) {
  2695. db_delete('og_users_roles')
  2696. ->condition('uid', $uid)
  2697. ->condition('rid', $rid)
  2698. ->condition('group_type', $group_type)
  2699. ->condition('gid', $gid)
  2700. ->execute();
  2701. module_invoke_all('og_role_revoke', $group_type, $gid, $uid, $rid);
  2702. if (module_exists('rules')) {
  2703. rules_invoke_event('og_role_revoke', og_get_membership($group_type, $gid, 'user', $uid), entity_metadata_wrapper('user', $uid), $rid);
  2704. }
  2705. }
  2706. }
  2707. /**
  2708. * Change permissions for a user role.
  2709. *
  2710. * This function may be used to grant and revoke multiple permissions at once.
  2711. * For example, when a form exposes checkboxes to configure permissions for a
  2712. * role, the submitted values may be directly passed on in a form submit
  2713. * handler.
  2714. *
  2715. * @param $rid
  2716. * The ID of a group user role to alter.
  2717. * @param $permissions
  2718. * An array of permissions, where the key holds the permission name and the
  2719. * value is an integer or boolean that determines whether to grant or revoke
  2720. * the permission:
  2721. * @code
  2722. * array(
  2723. * 'edit group' => 0,
  2724. * 'administer group' => 1,
  2725. * )
  2726. * @endcode
  2727. * Existing permissions are not changed, unless specified in $permissions.
  2728. *
  2729. * @see og_role_grant_permissions()
  2730. * @see og_role_revoke_permissions()
  2731. */
  2732. function og_role_change_permissions($rid, array $permissions = array()) {
  2733. // Grant new permissions for the role.
  2734. $grant = array_filter($permissions);
  2735. if (!empty($grant)) {
  2736. og_role_grant_permissions($rid, array_keys($grant));
  2737. }
  2738. // Revoke permissions for the role.
  2739. $revoke = array_diff_assoc($permissions, $grant);
  2740. if (!empty($revoke)) {
  2741. og_role_revoke_permissions($rid, array_keys($revoke));
  2742. }
  2743. if (!empty($grant) || !empty($revoke)) {
  2744. // Allow modules to be notified on permission changes.
  2745. $role = og_role_load($rid);
  2746. module_invoke_all('og_role_change_permissions', $role, $grant, $revoke);
  2747. }
  2748. }
  2749. /**
  2750. * Grant permissions to a user role.
  2751. *
  2752. * @param $rid
  2753. * The ID of a user role to alter.
  2754. * @param $permissions
  2755. * A list of permission names to grant.
  2756. *
  2757. * @see user_role_change_permissions()
  2758. * @see user_role_revoke_permissions()
  2759. */
  2760. function og_role_grant_permissions($rid, array $permissions = array()) {
  2761. $modules = array();
  2762. foreach (og_get_permissions() as $name => $value) {
  2763. $modules[$name] = $value['module'];
  2764. }
  2765. // Grant new permissions for the role.
  2766. foreach ($permissions as $name) {
  2767. // Prevent WSOD, if the permission name is wrong, and we can't find its
  2768. // module.
  2769. if (!empty($modules[$name])) {
  2770. db_merge('og_role_permission')
  2771. ->key(array(
  2772. 'rid' => $rid,
  2773. 'permission' => $name,
  2774. 'module' => $modules[$name],
  2775. ))
  2776. ->execute();
  2777. }
  2778. }
  2779. og_invalidate_cache();
  2780. }
  2781. /**
  2782. * Revoke permissions from a user role.
  2783. *
  2784. * @param $rid
  2785. * The ID of a user role to alter.
  2786. * @param $permissions
  2787. * A list of permission names to revoke.
  2788. *
  2789. * @see user_role_change_permissions()
  2790. * @see user_role_grant_permissions()
  2791. */
  2792. function og_role_revoke_permissions($rid, array $permissions = array()) {
  2793. // Revoke permissions for the role.
  2794. db_delete('og_role_permission')
  2795. ->condition('rid', $rid)
  2796. ->condition('permission', $permissions, 'IN')
  2797. ->execute();
  2798. og_invalidate_cache();
  2799. }
  2800. /**
  2801. * Get all permissions defined by implementing modules.
  2802. *
  2803. * @return
  2804. * Array keyed with the permissions name and the value of the permissions.
  2805. * TODO: Write the values.
  2806. */
  2807. function og_get_permissions() {
  2808. $perms = &drupal_static(__FUNCTION__, array());
  2809. if (!empty($perms)) {
  2810. return $perms;
  2811. }
  2812. foreach (module_implements('og_permission') as $module) {
  2813. if ($permissions = module_invoke($module, 'og_permission')) {
  2814. foreach ($permissions as $key => $perm) {
  2815. $permissions[$key] += array(
  2816. // Initialize the roles key, if other modules haven't set it
  2817. // explicetly. This means the permissions can apply to anonymous and
  2818. // authenticated members as-well.
  2819. 'roles' => array(OG_ANONYMOUS_ROLE, OG_AUTHENTICATED_ROLE),
  2820. 'default role' => array(),
  2821. 'module' => $module,
  2822. );
  2823. }
  2824. $perms = array_merge($perms, $permissions);
  2825. }
  2826. }
  2827. // Allow other modules to alter the permissions.
  2828. drupal_alter('og_permission', $perms);
  2829. return $perms;
  2830. }
  2831. /**
  2832. * Get default permissions.
  2833. *
  2834. * @return
  2835. * Array keyed with the anonymous, authenticated and administror and the
  2836. * permissions that should be enabled by default.
  2837. */
  2838. function og_get_default_permissions() {
  2839. $roles = og_get_default_roles();
  2840. $default_perms = og_get_permissions();
  2841. $perms = array();
  2842. foreach ($roles as $rid => $role_name) {
  2843. $perms[$rid] = array();
  2844. // For each default role, iterate default permissions and mark the
  2845. // permissions that set the role as default.
  2846. foreach ($default_perms as $perm_name => $perm) {
  2847. if (in_array($role_name, $perm['default role'])) {
  2848. $perms[$rid][$perm_name] = TRUE;
  2849. }
  2850. }
  2851. }
  2852. return $perms;
  2853. }
  2854. /**
  2855. * Get all the modules fields that can be assigned to fieldable entities.
  2856. *
  2857. * @param $field_name
  2858. * The field name that was registered for the definition.
  2859. *
  2860. * @return
  2861. * An array with the field and instance definitions, or FALSE if not
  2862. * found.
  2863. */
  2864. function og_fields_info($field_name = NULL) {
  2865. $return = &drupal_static(__FUNCTION__, array());
  2866. if (empty($return)) {
  2867. foreach (module_implements('og_fields_info') as $module) {
  2868. if ($fields = module_invoke($module, 'og_fields_info')) {
  2869. foreach ($fields as $key => $field) {
  2870. // Add default values.
  2871. $field += array(
  2872. 'entity type' => array(),
  2873. 'multiple' => FALSE,
  2874. 'description' => '',
  2875. );
  2876. // Add the module information.
  2877. $return[$key] = array_merge($field, array('module' => $module));
  2878. }
  2879. }
  2880. }
  2881. // Allow other modules to alter the field info.
  2882. drupal_alter('og_fields_info', $return);
  2883. }
  2884. if (!empty($field_name)) {
  2885. return !empty($return[$field_name]) ? $return[$field_name] : FALSE;
  2886. }
  2887. return $return;
  2888. }
  2889. /**
  2890. * Set breadcrumbs according to a given group.
  2891. *
  2892. * @param $entity_type
  2893. * The entity type.
  2894. * @param $etid
  2895. * The entity ID.
  2896. * @param $path
  2897. * (optional) The path to append to the breadcrumb.
  2898. */
  2899. function og_set_breadcrumb($entity_type, $etid, $path = array()) {
  2900. $entity = entity_load_single($entity_type, $etid);
  2901. $label = entity_label($entity_type, $entity);
  2902. $uri = entity_uri($entity_type, $entity);
  2903. drupal_set_breadcrumb(array_merge(array(l(t('Home'), '<front>')), array(l($label, $uri['path'])), $path));
  2904. }
  2905. /**
  2906. * Create an organic groups field in a bundle.
  2907. *
  2908. * @param $field_name
  2909. * The field name
  2910. * @param $entity_type
  2911. * The entity type
  2912. * @param $bundle
  2913. * The bundle name.
  2914. * @param $og_field
  2915. * (optional) Array with field definitions, to allow easier overriding by the
  2916. * caller. If empty, function will get the field info by calling
  2917. * og_fields_info() with the field name.
  2918. */
  2919. function og_create_field($field_name, $entity_type, $bundle, $og_field = array()) {
  2920. if (empty($og_field)) {
  2921. $og_field = og_fields_info($field_name);
  2922. }
  2923. $field = field_info_field($field_name);
  2924. // Allow overriding the field name.
  2925. $og_field['field']['field_name'] = $field_name;
  2926. if (empty($field)) {
  2927. $field = field_create_field($og_field['field']);
  2928. }
  2929. $instance = field_info_instance($entity_type, $field_name, $bundle);
  2930. if (empty($instance)) {
  2931. $instance = $og_field['instance'];
  2932. $instance += array(
  2933. 'field_name' => $field_name,
  2934. 'bundle' => $bundle,
  2935. 'entity_type' => $entity_type,
  2936. );
  2937. field_create_instance($instance);
  2938. // Clear the entity property info cache, as OG fields might add different
  2939. // entity property info.
  2940. og_invalidate_cache();
  2941. entity_property_info_cache_clear();
  2942. }
  2943. }
  2944. /**
  2945. * Return the states a group can be in.
  2946. */
  2947. function og_group_states() {
  2948. return array(
  2949. OG_STATE_ACTIVE => t('Active'),
  2950. OG_STATE_PENDING => t('Pending'),
  2951. );
  2952. }
  2953. /**
  2954. * Return the states a group content can be in.
  2955. */
  2956. function og_group_content_states() {
  2957. return array(
  2958. OG_STATE_ACTIVE => t('Active'),
  2959. OG_STATE_PENDING => t('Pending'),
  2960. OG_STATE_BLOCKED => t('Blocked'),
  2961. );
  2962. }
  2963. /**
  2964. * Return a list of fieldable entities.
  2965. *
  2966. * @return
  2967. * Array keyed with the entity machine name and the saniztized human name as
  2968. * the value.
  2969. */
  2970. function og_get_fieldable_entity_list() {
  2971. $return = array();
  2972. foreach (entity_get_info() as $name => $info) {
  2973. if (!empty($info['fieldable'])) {
  2974. $return[$name] = check_plain($info['label']);
  2975. }
  2976. }
  2977. return $return;
  2978. }
  2979. /**
  2980. * Helper function to generate standard node permission list for a given type.
  2981. *
  2982. * @param $type
  2983. * The machine-readable name of the node type.
  2984. *
  2985. * @return array
  2986. * An array of permission names and descriptions.
  2987. */
  2988. function og_list_permissions($type) {
  2989. $info = node_type_get_type($type);
  2990. $type = check_plain($info->type);
  2991. $perms = array();
  2992. // Check type is of group content.
  2993. if (og_is_group_content_type('node', $type)) {
  2994. // Build standard list of node permissions for this type.
  2995. $perms += array(
  2996. "create $type content" => array(
  2997. 'title' => t('Create %type_name content', array('%type_name' => $info->name)),
  2998. ),
  2999. "update own $type content" => array(
  3000. 'title' => t('Edit own %type_name content', array('%type_name' => $info->name)),
  3001. ),
  3002. "update any $type content" => array(
  3003. 'title' => t('Edit any %type_name content', array('%type_name' => $info->name)),
  3004. ),
  3005. "delete own $type content" => array(
  3006. 'title' => t('Delete own %type_name content', array('%type_name' => $info->name)),
  3007. ),
  3008. "delete any $type content" => array(
  3009. 'title' => t('Delete any %type_name content', array('%type_name' => $info->name)),
  3010. ),
  3011. );
  3012. if (!module_exists('entityreference_prepopulate')) {
  3013. // We allow the create permission only on members, as otherwise we would
  3014. // have to iterate over every single group to decide if the user has
  3015. // permissions for it.
  3016. $perms["create $type content"]['roles'] = array(OG_AUTHENTICATED_ROLE);
  3017. }
  3018. // Add default permissions.
  3019. foreach ($perms as $key => $value) {
  3020. $perms[$key]['default role'] = array(OG_AUTHENTICATED_ROLE);
  3021. }
  3022. }
  3023. return $perms;
  3024. }
  3025. /**
  3026. * Return a form element with crafted links to create nodes for a group.
  3027. *
  3028. * @param $group_type
  3029. * The entity type of the group.
  3030. * @param $gid
  3031. * The group ID.
  3032. * @param $field_name
  3033. * The group audience field name.
  3034. * @param $destination
  3035. * (optional) The destiantion after a node is created. Defaults to the
  3036. * destination passed in the URL if exists, otherwise back to the current
  3037. * page. FALSE to not append any destination to node create links.
  3038. * @param $types
  3039. * (optional) An array of type names. Restrict the created links to the given
  3040. * types.
  3041. */
  3042. function og_node_create_links($group_type, $gid, $field_name, $destination = NULL, $types = NULL) {
  3043. if (!og_is_group($group_type, $gid)) {
  3044. return;
  3045. }
  3046. $types = isset($types) ? $types : array_keys(node_type_get_types());
  3047. foreach ($types as $type_name) {
  3048. if (!og_is_group_content_type('node', $type_name) || !og_user_access($group_type, $gid, "create $type_name content")) {
  3049. continue;
  3050. }
  3051. $instance = field_info_instance('node', $field_name, $type_name);
  3052. if (empty($instance['settings']['behaviors']['prepopulate']['status'])) {
  3053. // Instance doesn't allow prepopulating.
  3054. continue;
  3055. }
  3056. $names[$type_name] = node_type_get_name($type_name);
  3057. }
  3058. if (empty($names)) {
  3059. return;
  3060. }
  3061. // Sort names.
  3062. asort($names);
  3063. // Build links.
  3064. $options = array(
  3065. 'query' => array($field_name => $gid),
  3066. );
  3067. if ($destination) {
  3068. $options['query']['destination'] = $destination;
  3069. }
  3070. elseif ($destination !== FALSE) {
  3071. $options['query'] += drupal_get_destination();
  3072. }
  3073. $items = array();
  3074. foreach ($names as $type => $name) {
  3075. // theme_item_list's 'data' items isn't a render element, so use l().
  3076. // http://drupal.org/node/891112
  3077. $items[] = array('data' => l($name, 'node/add/' . str_replace('_', '-', $type), $options));
  3078. }
  3079. $element = array();
  3080. $element['og_node_create_links'] = array(
  3081. '#theme' => 'item_list',
  3082. '#items' => $items,
  3083. );
  3084. return $element;
  3085. }
  3086. /**
  3087. * Get the group IDs of all the groups a user is an approved member of.
  3088. *
  3089. * @param $account
  3090. * (optional) The user object to fetch group memberships for. Defaults to the
  3091. * acting user.
  3092. * @param $group_type
  3093. * (optional) The entity type of the groups to fetch. By default all group
  3094. * types will be fetched.
  3095. *
  3096. * @return
  3097. * An array with the group IDs or an empty array.
  3098. */
  3099. function og_get_groups_by_user($account = NULL, $group_type = NULL) {
  3100. if (empty($account)) {
  3101. global $user;
  3102. $account = $user;
  3103. }
  3104. if (!og_get_group_audience_fields()) {
  3105. // User entity doesn't have group audience fields.
  3106. return;
  3107. }
  3108. $gids = array();
  3109. // Get all active OG membership that belong to the user.
  3110. $wrapper = entity_metadata_wrapper('user', $account->uid);
  3111. $og_memberships = $wrapper->{'og_membership__' . OG_STATE_ACTIVE}->value();
  3112. if (!$og_memberships) {
  3113. return;
  3114. }
  3115. foreach ($og_memberships as $og_membership) {
  3116. $gids[$og_membership->group_type][$og_membership->gid] = $og_membership->gid;
  3117. }
  3118. if (empty($group_type)) {
  3119. return $gids;
  3120. }
  3121. elseif (!empty($gids[$group_type])) {
  3122. return $gids[$group_type];
  3123. }
  3124. }
  3125. /**
  3126. * Implements hook_action_info().
  3127. *
  3128. * @see views_bulk_operations_action_info()
  3129. */
  3130. function og_action_info() {
  3131. $actions = array();
  3132. $files = og_operations_load_action_includes();
  3133. foreach ($files as $filename) {
  3134. $action_info_fn = 'og_'. str_replace('.', '_', basename($filename, '.inc')).'_info';
  3135. $action_info = call_user_func($action_info_fn);
  3136. if (is_array($action_info)) {
  3137. $actions += $action_info;
  3138. }
  3139. }
  3140. return $actions;
  3141. }
  3142. /**
  3143. * Loads the VBO actions placed in their own include files.
  3144. *
  3145. * @return
  3146. * An array of containing filenames of the included actions.
  3147. *
  3148. * @see views_bulk_operations_load_action_includes()
  3149. */
  3150. function og_operations_load_action_includes() {
  3151. static $loaded = FALSE;
  3152. $path = drupal_get_path('module', 'og') . '/includes/actions/';
  3153. $files = array(
  3154. 'user_roles.action.inc',
  3155. 'set_state.action.inc',
  3156. 'membership_delete.action.inc',
  3157. );
  3158. if (!$loaded) {
  3159. foreach ($files as $file) {
  3160. include_once $path . $file;
  3161. }
  3162. $loaded = TRUE;
  3163. }
  3164. return $files;
  3165. }
  3166. /**
  3167. * Implements hook_features_api().
  3168. */
  3169. function og_features_api() {
  3170. return array(
  3171. 'og_features_role' => array(
  3172. 'name' => t('OG Role'),
  3173. 'feature source' => TRUE,
  3174. 'default_hook' => 'og_features_default_roles',
  3175. 'default_file' => FEATURES_DEFAULTS_INCLUDED,
  3176. 'file' => drupal_get_path('module', 'og') . '/includes/og_features_role.features.inc',
  3177. ),
  3178. 'og_features_permission' => array(
  3179. 'name' => t('OG Permissions'),
  3180. 'feature_source' => TRUE,
  3181. 'default_hook' => 'og_features_default_permissions',
  3182. 'default_file' => FEATURES_DEFAULTS_INCLUDED,
  3183. 'file' => drupal_get_path('module', 'og') . '/includes/og_features_permission.features.inc',
  3184. ),
  3185. );
  3186. }
  3187. /**
  3188. * Implements hook_features_pipe_alter().
  3189. *
  3190. * Prevent OG related fields from being piped in features, when a content
  3191. * type that has them is selected.
  3192. *
  3193. * This if compatible with Features 1.x and 2.x
  3194. */
  3195. function og_features_pipe_alter(&$pipe, $data, $export) {
  3196. if (!variable_get('og_features_ignore_og_fields', FALSE)) {
  3197. return;
  3198. }
  3199. if (empty($pipe['field']) && empty($pipe['field_base']) && empty($pipe['field_instance'])) {
  3200. // The exported item is not a field.
  3201. return;
  3202. }
  3203. if (!empty($pipe['field_instance'])) {
  3204. $key = 'field_instance';
  3205. $explode = TRUE;
  3206. }
  3207. elseif (!empty($pipe['field_base'])) {
  3208. $key = 'field_base';
  3209. $explode = FALSE;
  3210. }
  3211. else {
  3212. $key = 'field';
  3213. $explode = TRUE;
  3214. }
  3215. foreach ($pipe[$key] as $delta => $value) {
  3216. if ($explode) {
  3217. // Get the field name from the [entity-type]-[bundle]-[field-name].
  3218. $args = explode('-', $value);
  3219. $field_name = $args[2];
  3220. }
  3221. else {
  3222. $field_name = $value;
  3223. }
  3224. if (og_fields_info($field_name) || og_is_group_audience_field($field_name)) {
  3225. unset($pipe[$key][$delta]);
  3226. }
  3227. }
  3228. }
  3229. /**
  3230. * Implements hook_migrate_api().
  3231. */
  3232. function og_migrate_api() {
  3233. $migrations = array();
  3234. if (db_table_exists('d6_og')) {
  3235. $migrations['OgMigrateAddFields'] = array('class_name' => 'OgMigrateAddFields');
  3236. $migrations['OgMigrateContent'] = array('class_name' => 'OgMigrateContent');
  3237. $migrations['OgMigrateUser'] = array('class_name' => 'OgMigrateUser');
  3238. foreach (node_type_get_names() as $bundle => $value) {
  3239. $machine_name = 'OgMigrateGroup' . ucfirst($bundle);
  3240. $migrations[$machine_name] = array(
  3241. 'class_name' => 'OgMigrateGroup',
  3242. 'bundle' => $bundle,
  3243. );
  3244. }
  3245. if (db_table_exists('d6_og_users_roles')) {
  3246. // OG user roles (OGUR) related migrations.
  3247. $migrations['OgMigrateOgurRoles'] = array('class_name' => 'OgMigrateOgurRoles');
  3248. $migrations['OgMigrateOgur'] = array('class_name' => 'OgMigrateOgur');
  3249. }
  3250. }
  3251. elseif (db_field_exists('og_membership', 'group_type') && db_table_exists('og') && !db_table_exists('d6_og')) {
  3252. $migrations['OgMigrateMembership'] = array('class_name' => 'OgMigrateMembership');
  3253. $migrations['OgMigrateRoles'] = array('class_name' => 'OgMigrateRoles');
  3254. $migrations['OgMigrateUserRoles'] = array('class_name' => 'OgMigrateUserRoles');
  3255. }
  3256. $api = array(
  3257. 'api' => 2,
  3258. 'migrations' => $migrations,
  3259. );
  3260. return $api;
  3261. }
  3262. /**
  3263. * Implements hook_flush_caches().
  3264. */
  3265. function og_flush_caches() {
  3266. $bins = array(
  3267. 'cache_entity_og_membership',
  3268. 'cache_entity_og_membership_type',
  3269. );
  3270. return $bins;
  3271. }
Error | ELMSLN API

Error

×

Error message

  • Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/elmsln_community/api.elmsln.org/includes/common.inc:2791) in drupal_send_headers() (line 1499 of /var/www/html/elmsln_community/api.elmsln.org/includes/bootstrap.inc).
  • Error: Call to undefined function apc_delete() in DrupalAPCCache->clear() (line 289 of /var/www/html/elmsln_community/api.elmsln.org/sites/all/modules/apc/drupal_apc_cache.inc).
The website encountered an unexpected error. Please try again later.