diff --git a/includes/og.membership.inc b/includes/og.membership.inc index 39e7bff..c7a52d3 100644 --- a/includes/og.membership.inc +++ b/includes/og.membership.inc @@ -43,35 +43,30 @@ class OgMembership extends Entity { $field = field_info_field($field_name); if (!$field || !field_info_instance($entity_type, $field_name, $bundle)) { - throw new OgException(t('OG membership can not be created in entity %entity-type and bundle %entity-bundle using the field %field-name as the field does not exist.', $params)); + throw new OgException(format_string('OG membership can not be created in entity %entity-type and bundle %entity-bundle using the field %field-name as the field does not exist.', $params)); } if (!og_is_group_audience_field($field_name)) { - throw new OgException(t('OG membership can not be created with %field-name as it is not a valid group-audience type.', $params)); + throw new OgException(format_string('OG membership can not be created with %field-name as it is not a valid group-audience type.', $params)); } if ($field['settings']['target_type'] != $group_type) { - throw new OgException(t('OG membership can not be created in entity %entity-type and bundle %entity-bundle using the field %field-name as the field does not reference %group-type entity type.', $params)); + throw new OgException(format_string('OG membership can not be created in entity %entity-type and bundle %entity-bundle using the field %field-name as the field does not reference %group-type entity type.', $params)); } if (!empty($field['settings']['handler_settings']['target_bundles']) && !in_array($group_bundle, $field['settings']['handler_settings']['target_bundles'])) { - throw new OgException(t('OG membership can not be created in entity %entity-type and bundle %entity-bundle using the field %field-name as the field does not reference %group-bundle bundle in %group-type entity type.', $params)); + throw new OgException(format_string('OG membership can not be created in entity %entity-type and bundle %entity-bundle using the field %field-name as the field does not reference %group-bundle bundle in %group-type entity type.', $params)); } $params += array('@cardinality' => $field['cardinality']); // Check field cardinality, that we may add another value, if we have a new // OG membership. if (empty($this->id) && !og_check_field_cardinality($entity_type, $etid, $field_name)) { - throw new OgException(t('OG membership can not be created in entity %entity-type and bundle %entity-bundle using the field %field-name as the field cardinality is set to @cardinality.', $params)); - } - - // Check field is not a secondary field. - if (!empty($field['settings']['handler_settings']['primary_field'])) { - throw new OgException(t('OG membership can not be created using the field %field-name as the field is defined as a secondary field.', $params)); + throw new OgException(format_string('OG membership can not be created in entity %entity-type and bundle %entity-bundle using the field %field-name as the field cardinality is set to @cardinality.', $params)); } if (empty($this->id) && $og_membership = og_get_membership($this->group_type, $this->gid, $this->entity_type, $this->etid)) { - throw new OgException(t('OG membership for %etid - %entity-type in group %gid - %group-type already exists.', $params)); + throw new OgException(format_string('OG membership for %etid - %entity-type in group %gid - %group-type already exists.', $params)); } // We can now safely save the entity. diff --git a/og.install b/og.install index 0c95421..907e974 100644 --- a/og.install +++ b/og.install @@ -1015,3 +1015,61 @@ function og_update_7202() { db_change_field('og_role_permission', 'permission', 'permission', $column); return t('Updated column definition for {og_role_permission} table.'); } + +/** + * Update group-audience field to use "OG group" widget type. + */ +function og_update_7203() { + if (!module_exists('field_sql_storage')) { + return; + } + + // List of secondary group-audience fields. + $secondary_fields = array(); + + foreach (field_info_fields() as $field_name => $field) { + if ($field['type'] != 'entityreference' || $field['settings']['handler'] != 'og') { + continue; + } + + if (!empty($field['settings']['handler_settings']['primary_field'])) { + field_delete_field($field_name); + $secondary_fields[] = $field_name; + continue; + } + + foreach ($field['bundles'] as $entity_type => $bundles) { + foreach ($bundles as $bundle) { + $og_widget = + $instance = field_info_instance($entity_type, $field_name, $bundle); + $instance['settings']['behaviors']['og_widget'] = array( + 'status' => TRUE, + 'default' => array( + 'widget_type' => 'options_select', + ), + 'admin' => array( + 'widget_type' => 'entityreference_autocomplete', + ), + ); + + $instance['widget'] = array( + 'type' => 'og_complex', + 'module' => 'og', + 'settings' => array(), + ); + + field_update_instance($instance); + } + } + } + + if ($secondary_fields) { + $output = t('The following "secondary" fields were deleted, as they are no longer in use:'); + $output .= theme('item_list', array('items' => $secondary_fields)); + } + else { + $output = t('All group-audience fields were updated'); + } + + return $output; +} diff --git a/og.module b/og.module index 5ae91c7..5b599d0 100644 --- a/og.module +++ b/og.module @@ -37,11 +37,6 @@ define('OG_STATE_BLOCKED', 3); define('OG_AUDIENCE_FIELD', 'og_group_ref'); /** - * Define the "other groups" (i.e. not "my groups") default field name. - */ -define('OG_AUDIENCE_OTHER_GROUPS_FIELD', 'og_group_ref_other_groups'); - -/** * Group field. */ define('OG_GROUP_FIELD', 'group_group'); @@ -104,6 +99,32 @@ function og_help($path, $arg) { } /** + * Implements hook_menu(). + */ +function og_menu() { + $items = array(); + + // Add our own autocomplete callback to pass also the group and + // vocabulary info. + $items['og/autocomplete/single/%/%/%/%'] = array( + 'title' => 'Entity Reference Autocomplete', + 'page callback' => 'og_entityreference_autocomplete_callback', + 'page arguments' => array(2, 3, 4, 5, 6), + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + $items['og/autocomplete/tags/%/%/%/%'] = array( + 'title' => 'Entity Reference Autocomplete', + 'page callback' => 'og_entityreference_autocomplete_callback', + 'page arguments' => array(2, 3, 4, 5, 6), + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + + return $items; +} + +/** * Implements hook_entity_info(). */ function og_entity_info() { @@ -495,23 +516,30 @@ function og_og_default_roles() { function og_node_access($node, $op, $account) { $type = is_string($node) ? $node : (is_array($node) ? $node['type'] : $node->type); - if ($op == 'create' && og_is_group_content_type('node', $type) && variable_get('og_node_access_strict', TRUE) && !user_access('administer group')) { + if ($op == 'create' && og_is_group_content_type('node', $type) && variable_get('og_node_access_strict', TRUE)) { + if (user_access('administer group')) { + return NODE_ACCESS_ALLOW; + } // We can't check if user has create permissions using og_user_access(), as // there is no group context. However, we can check if there are any groups // the user will be able to select, and if not, we don't allow access. // @see OgSelectionHandler::getReferencableEntities() $required = FALSE; - foreach (og_get_group_audience_fields('node', $type, FALSE) as $field_name => $label) { + foreach (og_get_group_audience_fields('node', $type) as $field_name => $label) { $field = field_info_field($field_name); $instance = field_info_instance('node', $field_name, $type); + // Set the "field mode" to default, before passing it to the + // selection handler. + $instance['field_mode'] = 'default'; + if (entityreference_get_selection_handler($field, $instance)->getReferencableEntities()) { + return NODE_ACCESS_ALLOW; + } + // Allow users to create content outside of groups, if none of the // audience fields is required. if ($instance['required']) { $required = TRUE; } - if (entityreference_get_selection_handler($field, $instance)->getReferencableEntities()) { - return NODE_ACCESS_ALLOW; - } } // If no group audience field is required, we igonre, otherwise we // deny node creation. @@ -594,9 +622,8 @@ function og_field_access($op, $field, $entity_type, $entity, $account) { $field = field_info_field($field_name); $settings = $field['settings']['handler_settings']; - // Check if we are editing the user entity, or need to hide a secondary - // field. - if ($entity_type == 'user' || (!empty($settings['primary_field']) && !empty($settings['hide_secondary_field']))) { + // Check if we are editing the user entity. + if ($entity_type == 'user') { return user_access('administer group', $account); } } @@ -613,6 +640,307 @@ function og_views_api() { } /** + * Implements hook_field_widget_info(). + */ +function og_field_widget_info() { + $widgets['og_complex'] = array( + 'label' => t('OG reference'), + 'description' => t('Complex widget to reference groups.'), + 'field types' => array('entityreference'), + ); + + return $widgets; +} + + +/** + * Implements hook_field_widget_form(). + */ +function og_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) { + $entity_type = $instance['entity_type']; + $entity = isset($element['#entity']) ? $element['#entity'] : NULL; + + if (!$entity) { + return; + } + + if ($field['settings']['handler'] != 'og') { + $params = array('%label' => $instance['label']); + form_error($form, t('Field %label is a group-audience but its Entity selection mode is not defined as "Organic groups" in the field settings page.', $params)); + return; + } + + // Cache the processed entity, to make sure we call the widget only once. + $cache = &drupal_static(__FUNCTION__, array()); + list($id,, $bundle) = entity_extract_ids($entity_type, $entity); + $field_name = $field['field_name']; + + $identifier = $field_name . ':' . $entity_type . ':' . $id; + if (isset($cache[$identifier])) { + return; + } + $cache[$identifier] = TRUE; + + ctools_include('fields'); + + $field_modes = array('default'); + $has_admin = FALSE; + + // The group IDs that might not be accessible by the user, but we need + // to keep even after saving. + $element['#other_groups_ids'] = array(); + $element['#element_validate'][] = 'og_complex_widget_element_validate'; + + if (user_access('administer group')) { + $has_admin = TRUE; + $field_modes[] = 'admin'; + } + + // Get the "Other group" group IDs. + $target_type = $field['settings']['target_type']; + $entity_gids = og_get_entity_groups($entity_type, $entity); + $entity_gids = !empty($entity_gids[$target_type]) ? $entity_gids[$target_type] : array(); + + $user_gids = og_get_entity_groups(); + $user_gids = !empty($user_gids[$target_type]) ? $user_gids[$target_type] : array(); + + $other_groups_ids = array(); + $other_groups_ids = array_values(array_diff($entity_gids, $user_gids)); + + foreach ($field_modes as $field_mode) { + $mocked_instance = og_get_mocked_instance($instance, $field_mode); + $dummy_entity = clone $entity; + + if ($has_admin) { + $mocked_instance['required'] = FALSE; + $mocked_instance['label'] = $field_mode == 'default' ? t('Default') : t('Administrator'); + + if ($id) { + // The field might be required, and it will throw an exception + // when we try to set an empty value, so change the wrapper's + // info. + $wrapper = entity_metadata_wrapper($entity_type, $dummy_entity, array('property info alter' => 'og_property_info_alter', 'field name' => $field_name)); + if ($field_mode == 'admin') { + // Keep only the hidden group IDs on the entity, so they won't + // appear again on the "admin" field, for example on an autocomplete + // widget type. + $valid_ids = $other_groups_ids ? entityreference_get_selection_handler($field, $mocked_instance, $entity_type, $dummy_entity)->validateReferencableEntities($other_groups_ids) : array(); + $valid_ids = $field['cardinality'] == 1 ? reset($valid_ids) : $valid_ids; + $wrapper->{$field_name}->set($valid_ids); + } + else { + // Keep only the groups that belong to the user and to the entity. + $my_group_ids = array_values(array_intersect($user_gids, $entity_gids)); + $valid_ids = $my_group_ids ? entityreference_get_selection_handler($field, $mocked_instance, $entity_type, $dummy_entity)->validateReferencableEntities($my_group_ids) : array(); + + $valid_ids = $field['cardinality'] == 1 ? reset($valid_ids) : $valid_ids; + $wrapper->{$field_name}->set($valid_ids); + } + } + } + else { + // Non-admin user. + $mocked_instance_other_groups = $mocked_instance; + $mocked_instance_other_groups['field_mode'] = 'admin'; + if ($other_groups_ids && $valid_ids = entityreference_get_selection_handler($field, $mocked_instance_other_groups, $entity_type, $dummy_entity)->validateReferencableEntities($other_groups_ids)) { + foreach ($valid_ids as $id) { + $element['#other_groups_ids'][] = array('target_id' => $id); + } + } + } + + $new_element = ctools_field_invoke_field($mocked_instance, 'form', $entity_type, $dummy_entity, $form, $form_state, array('default' => TRUE)); + $element[$field_mode] = $new_element[$field_name][LANGUAGE_NONE]; + + if (in_array($mocked_instance['widget']['type'], array('entityreference_autocomplete', 'entityreference_autocomplete_tags'))) { + // Change the "Add more" button name so it adds only the needed + // element. + if (!empty($element[$field_mode]['add_more']['#name'])) { + $element[$field_mode]['add_more']['#name'] .= '__' . $field_mode; + } + + foreach (array_keys($element[$field_mode]) as $delta) { + if (!is_numeric($delta)) { + continue; + } + + $sub_element = &$element[$field_mode][$delta]['target_id']; + + // Rebuild the autocomplete path. + $path = explode('/', $sub_element['#autocomplete_path']); + $sub_element['#autocomplete_path'] = 'og/autocomplete'; + + // Add autocomplete type + $sub_element['#autocomplete_path'] .= "/$path[2]/$path[3]/$path[4]/$path[5]"; + + // Add field mode. + $sub_element['#autocomplete_path'] .= "/$field_mode"; + + // Add the entity ID. + $sub_element['#autocomplete_path'] .= "/$path[6]"; + if (!empty($path[7])) { + // Add the text. + $sub_element['#autocomplete_path'] .= "/$path[7]"; + } + } + } + } + + $form['#after_build']['og'] = 'og_complex_widget_after_build'; + + return $element; +} + +/** + * Property info alter; Change mocked field to be non-required. + */ +function og_property_info_alter($wrapper, $info) { + $property_info = $wrapper->info(); + $field_name = $property_info['field name']; + $info['properties'][$field_name]['required'] = FALSE; + return $info; +} + +/** + * Helper function; Get the mocked instance. + */ +function og_get_mocked_instance($instance, $field_mode) { + $mocked_instance = $instance; + $widget_type = $instance['settings']['behaviors']['og_widget'][$field_mode]['widget_type']; + $mocked_instance['widget']['type'] = $widget_type; + + // Set the widget's module. + $widget_info = field_info_widget_types($widget_type); + $mocked_instance['widget']['module'] = $widget_info['module']; + $mocked_instance['widget']['settings'] = drupal_array_merge_deep($mocked_instance['widget']['settings'], $widget_info['settings']); + + // See OgSelectionHandler::buildEntityFieldQuery(). + $mocked_instance['field_mode'] = $field_mode; + + return $mocked_instance; +} + +/** + * Rebuild the element's values, using the default and admin if exists. + */ +function og_complex_widget_element_validate($element, &$form_state, $form) { + $field_name = $element['#field_name']; + $field = field_info_field($field_name); + $subform = $form_state['values'][$field_name][LANGUAGE_NONE][0]; + $ids = $element['#other_groups_ids']; + foreach (array('default', 'admin') as $type) { + if (empty($subform[$type])) { + continue; + } + + foreach ($subform[$type] as $delta => $value) { + if (!empty($value['target_id']) && is_numeric($value['target_id'])) { + $ids[] = array('target_id' => $value['target_id']); + } + } + } + form_set_value($form[$field_name][LANGUAGE_NONE], $ids, $form_state); +} + +/** + * After build; Remove the "Add more" button. + * + * @see field_multiple_value_form() + * @see theme_field_multiple_value_form() + */ +function og_complex_widget_after_build($form, &$form_state) { + foreach (og_get_group_audience_fields($form['#entity_type'], $form['#bundle']) as $field_name => $value) { + if (empty($form[$field_name])) { + continue; + } + $form[$field_name][LANGUAGE_NONE]['#theme'] = ''; + unset($form[$field_name][LANGUAGE_NONE]['add_more']); + unset($form[$field_name][LANGUAGE_NONE][0]['_weight']); + + if (!empty($form[$field_name][LANGUAGE_NONE][0]['admin'])) { + // Wrap both elements with a fieldset. + $form[$field_name][LANGUAGE_NONE]['#theme_wrappers'] = array('fieldset'); + } + } + + return $form; +} + +/** + * Menu callback: autocomplete the label of an entity. + * + * @param $type + * The widget type (i.e. 'single' or 'tags'). + * @param $field_name + * The name of the entity-reference field. + * @param $entity_type + * The entity type. + * @param $bundle_name + * The bundle name. + * @param $field_mode + * The field mode, "default" or "admin". + * @param $entity_id + * Optional; The entity ID the entity-reference field is attached to. + * Defaults to ''. + * @param $string + * The label of the entity to query by. + * + * @see entityreference_autocomplete_callback() + */ +function og_entityreference_autocomplete_callback($type, $field_name, $entity_type, $bundle_name, $field_mode, $entity_id = '', $string = '') { + $field = field_info_field($field_name); + $instance = field_info_instance($entity_type, $field_name, $bundle_name); + $instance = og_get_mocked_instance($instance, $field_mode); + $matches = array(); + + if (!$field || !$instance || $field['type'] != 'entityreference' || !field_access('edit', $field, $entity_type)) { + return MENU_ACCESS_DENIED; + } + + $entity = NULL; + if ($entity_id !== 'NULL') { + $entity = entity_load_single($entity_type, $entity_id); + if (!$entity || !entity_access('view', $entity_type, $entity)) { + return MENU_ACCESS_DENIED; + } + } + $handler = entityreference_get_selection_handler($field, $instance, $entity_type, $entity); + + if ($type == 'tags') { + // The user enters a comma-separated list of tags. We only autocomplete the last tag. + $tags_typed = drupal_explode_tags($string); + $tag_last = drupal_strtolower(array_pop($tags_typed)); + if (!empty($tag_last)) { + $prefix = count($tags_typed) ? implode(', ', $tags_typed) . ', ' : ''; + } + } + else { + // The user enters a single tag. + $prefix = ''; + $tag_last = $string; + } + + if (!empty($tag_last)) { + // Get an array of matching entities. + $entity_labels = $handler->getReferencableEntities($tag_last, $instance['widget']['settings']['match_operator'], 10); + + // Loop through the products and convert them into autocomplete output. + foreach ($entity_labels as $entity_id => $label) { + $key = "$label ($entity_id)"; + // Strip things like starting/trailing white spaces, line breaks and tags. + $key = preg_replace('/\s\s+/', ' ', str_replace("\n", '', trim(decode_entities(strip_tags($key))))); + // Names containing commas or quotes must be wrapped in quotes. + if (strpos($key, ',') !== FALSE || strpos($key, '"') !== FALSE) { + $key = '"' . str_replace('"', '""', $key) . '"'; + } + $matches[$prefix . $key] = '
' . $label . '
'; + } + } + + drupal_json_output($matches); +} + +/** * Implements hook_field_create_instance(). * * - Create default OG roles per entity-type and bundle. @@ -634,15 +962,6 @@ function og_field_create_instance($instance) { $og_field['field']['settings']['target_type'] = $instance['entity_type']; $og_field['instance']['label'] = t('Group membership'); og_create_field('og_user_group_ref', 'user', 'user', $og_field); - - // Create "Other groups" field. - $og_field['instance']['label'] = t('Other groups'); - $og_field['instance']['widget']['type'] = 'entityreference_autocomplete'; - $og_field['field']['settings']['handler_settings']['reference_type'] = 'other_groups'; - $og_field['field']['settings']['handler_settings']['primary_field'] = 'og_user_group_ref'; - $og_field['field']['settings']['handler_settings']['hide_secondary_field'] = TRUE; - $og_field['field']['settings']['handler_settings']['force_optional_primary'] = TRUE; - og_create_field('og_other_user_group_ref', 'user', 'user', $og_field); } } @@ -688,7 +1007,7 @@ function og_form_alter(&$form, $form_state, $form_id) { * Validate handler; Make sure a group can be created. * * We check if the group manager has a matching group-audience field for the - * OG membership do be created in. + * OG membership to be created in. */ function og_form_group_manager_validate($form, &$form_state) { $entity_type = $form['#entity_type']; @@ -752,243 +1071,6 @@ function og_form_group_manager_validate($form, &$form_state) { 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)))); } - -/** - * Implements hook_field_attach_form(). - * - * Inject values to a secondary field, based on the primary field. - */ -function og_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) { - list($id,, $bundle_name) = entity_extract_ids($entity_type, $entity); - if (!og_is_group_content_type($entity_type, $bundle_name)) { - return; - } - - $wrapper = entity_metadata_wrapper($entity_type, $entity); - $has_secondary = FALSE; - - // Get all the group-audience fields in the entity. - foreach (og_get_group_audience_fields($entity_type, $bundle_name) as $field_name => $label) { - $field = field_info_field($field_name); - - if (empty($field['settings']['handler_settings']['primary_field'])) { - continue; - } - - $primary_field = $field['settings']['handler_settings']['primary_field']; - if (!isset($wrapper->$primary_field)) { - // Settings are referencing a non-existing field. - return; - } - $primary_ids = $wrapper->$primary_field->value(array('identifier' => TRUE)); - - if (!empty($field['settings']['handler_settings']['force_optional_primary']) && user_access('administer group')) { - // Set required field to not required for administrator. - $form_primary = &$form[$primary_field][LANGUAGE_NONE]; - - if ($form_primary['#required']) { - $form_primary['#required'] = FALSE; - // Need to add a "None" option now that the field is not required. - $form_primary['#options'] = array('_none' => t('- None -')) + $form_primary['#options']; - } - } - - // Intersect the IDs from the primary field, with the referencable IDs - // from the secondary, by validating the IDs. - if (!is_array($primary_ids)) { - // If the field cardinality is 1, entity metadatwrapper, returns the - // value as integer, so turn it into an array. - $primary_ids = array($primary_ids); - } - $instance = field_info_instance($entity_type, $field['field_name'], $bundle_name); - $secondary_ids = entityreference_get_selection_handler($field, $instance)->validateReferencableEntities($primary_ids); - if (!$secondary_ids) { - continue; - } - $has_secondary = TRUE; - - // Rebuild the items array. - $items = array(); - foreach ($secondary_ids as $id) { - $items[] = array( - 'target_id' => $id, - ); - } - - if (empty($form_state['field'][$field_name])) { - continue; - } - - $key = key($form_state['field'][$field_name]); - - // We don't use field_form_set_state() as we just want to change the items - // count. We have to do it before calling field_default_form(). - $form_state['field'][$field_name][$key]['items_count'] = count($items); - - // Re-build the field, based on the injected values. - $result = field_default_form($entity_type, $entity, $field, $instance, $key, $items, $form, $form_state, NULL); - $form[$field_name] = $result[$field_name]; - } - - if ($has_secondary) { - $form['#validate'][] = 'og_form_secondary_field_validate'; - - if ($id && !field_access('edit', $field, $entity_type, $entity)) { - $group_type = $field['settings']['target_type']; - $gids = $primary_ids + $secondary_ids; - $hidden_gids = array(); - foreach ($gids as $gid) { - if (in_array($gid, $secondary_ids)) { - $hidden_gids[] = array('target_id' => $gid); - } - } - - if ($hidden_gids) { - $form[$field['field_name']][$langcode]['#element_validate'][] = 'og_form_keep_primary_field_validate'; - $form[$field['field_name']][$langcode]['#hidden_gids'] = $hidden_gids; - } - } - } -} - -/** - * Validate handler; Re-populate inaccessible values, to the secondary field. - */ -function og_form_keep_primary_field_validate($element, &$form_state) { - form_set_value($element, $element['#hidden_gids'], $form_state); -} - -/** - * Validate handler; Check field cardinality of primary field. - * - * We need to make sure that values pushed from a secondary field, don't exceed - * the allowed values of the primary field. - */ -function og_form_secondary_field_validate($form, &$form_state) { - // Get an keyed with the primary field, and an arrayof secoadry fields as the - // value. - $entity_type = $form['#entity_type']; - if (empty($form_state[$entity_type])) { - // Entity info isn't in the $form_state (e.g. when admin creates a new - // user). - return; - } - $entity = $form_state[$entity_type]; - $fields_info = array(); - foreach ($form_state['field'] as $field_name => $value) { - if (!og_is_group_audience_field($field_name)) { - continue; - } - $langcode = key($value); - // If there is no field info, it means the field isn't accessible. - $field = !empty($value[$langcode]['field']) ? $value[$langcode]['field'] : array(); - if (!empty($field['settings']['handler_settings']['primary_field'])) { - $fields_info[$field['settings']['handler_settings']['primary_field']][] = $field_name; - } - } - - foreach ($fields_info as $primary_field_name => $values) { - $langcode = key($form_state['field'][$primary_field_name]); - $primary_field = $form_state['field'][$primary_field_name][$langcode]['field']; - if ($primary_field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) { - continue; - } - $primary_instance = $form_state['field'][$primary_field_name][$langcode]['instance']; - // Get the items from the form state. - $count = 0; - $items = FALSE; - field_default_extract_form_values($entity_type, $entity, $primary_field, $primary_instance, $langcode, $items, $form, $form_state); - foreach ($items as $item) { - if (!empty($item['target_id']) && $item['target_id'] != '_none') { - ++$count; - } - } - - $secondary_labels = array(); - foreach ($values as $secondary_field_name) { - $langcode = key($form_state['field'][$secondary_field_name]); - $secondary_field = $form_state['field'][$secondary_field_name][$langcode]['field']; - $secondary_instance = $form_state['field'][$secondary_field_name][$langcode]['instance']; - $secondary_labels[] = $secondary_instance['label']; - // Get the items from the form state. - $items = FALSE; - field_default_extract_form_values($entity_type, $entity, $secondary_field, $secondary_instance, $langcode, $items, $form, $form_state); - foreach ($items as $item) { - if (!empty($item['target_id'])) { - ++$count; - // Set the field name that will invoke the error. - $element_error = $secondary_field_name; - } - } - } - - if ($count > $primary_field['cardinality']) { - $params = array( - '%primary' => $primary_instance['label'], - '%secondary' => implode(', ', $secondary_labels), - '@count' => $primary_field['cardinality'], - ); - form_error($form[$element_error], t('Values from the secondary field(s) %secondary can not be pushed into the primary field %primary as it is limited to @count values.', $params)); - } - } -} - -/** - * Implements hook_entity_presave(). - */ -function og_entity_presave($entity, $entity_type) { - list(,,$bundle) = entity_extract_ids($entity_type, $entity); - if (!og_is_group_content_type($entity_type, $bundle)) { - return; - } - - $wrapper = entity_metadata_wrapper($entity_type, $entity); - // Get secondary fields. - $fields_info = field_info_fields(); - foreach (field_info_instances($entity_type, $bundle) as $field_name => $field_instance) { - $field_info = $fields_info[$field_name]; - if ($field_info['type'] != 'entityreference' || $field_info['settings']['handler'] != 'og') { - // This is not an Entity reference field. - continue; - } - - if (empty($field_info['settings']['handler_settings']['primary_field'])) { - continue; - } - - if (!$new_ids = $wrapper->{$field_name}->value(array('identifier' => TRUE))) { - continue; - } - - if (!is_array($new_ids)) { - // Entity metadta returned a single ID or no ID. - $new_ids = array($new_ids); - } - - $primary_field = $fields_info[$field_name]['settings']['handler_settings']['primary_field']; - $primary_field_info = field_info_field($primary_field); - $existing_ids = $wrapper->{$primary_field}->value(array('identifier' => TRUE)); - if (!is_array($existing_ids)) { - // Entity metadta returned a single ID. - $existing_ids = array($existing_ids); - } - foreach ($new_ids as $id) { - // TODO: Move this check to Entity API. - if (!in_array($id, $existing_ids)) { - if ($primary_field_info['cardinality'] == 1) { - $wrapper->{$primary_field}->set($id); - } - else { - $wrapper->{$primary_field}[] = $id; - } - } - } - - // Remove the values from the secondary field. - $wrapper->{$field_name}->set(NULL); - } -} - /** * Implements hook_entity_insert(). */ @@ -1076,7 +1158,7 @@ function _og_update_entity_fields($entity_type, $entity) { } $wrapper = entity_metadata_wrapper($entity_type, $entity); - foreach (og_get_group_audience_fields($entity_type, $bundle, FALSE) as $field_name => $label) { + foreach (og_get_group_audience_fields($entity_type, $bundle) as $field_name => $label) { $field = field_info_field($field_name); $gids = array(); if ($field['cardinality'] == 1) { @@ -1255,8 +1337,6 @@ function og_og_fields_info() { ), 'target_bundles' => array(), 'membership_type' => OG_MEMBERSHIP_TYPE_DEFAULT, - 'reference_type' => 'my_groups', - 'primary_field' => FALSE, ), 'target_type' => 'node', ), @@ -1264,9 +1344,22 @@ function og_og_fields_info() { 'instance' => array( 'label' => t('Groups audience'), 'widget' => array( - 'module' => 'options', + 'type' => 'og_complex', + 'module' => 'og', 'settings' => array(), - 'type' => 'options_select', + ), + 'settings' => array( + 'behaviors' => array( + 'og_widget' => array( + 'status' => TRUE, + 'default' => array( + 'widget_type' => 'options_select', + ), + 'admin' => array( + 'widget_type' => 'entityreference_autocomplete', + ), + ), + ), ), 'view modes' => array( 'full' => array( @@ -1412,7 +1505,7 @@ function og_membership_create($group_type, $gid, $entity_type, $etid, $field_nam ); if (!og_is_group_audience_field($field_name)) { - throw new OgException(t('%field-name is not a valid group-audience field.', array('%field-name' => $field_name))); + throw new OgException(format_string('%field-name is not a valid group-audience field.', array('%field-name' => $field_name))); } // Get the type from the field. @@ -1659,11 +1752,6 @@ function og_get_best_group_audience_field($entity_type, $entity, $group_type, $g continue; } - if (!empty($settings['handler_settings']['primary_field'])) { - // Secondary field. - continue; - } - if (!og_check_field_cardinality($entity_type, $entity, $field_name)) { // Field reached maximum. continue; @@ -1762,7 +1850,7 @@ function og_group($group_type, $gid, $values = array()) { // Allow getting fields not accessible by the user. $field_name = og_get_best_group_audience_field($entity_type, $entity, $group_type, $group_bundle, TRUE); if (!$field_name) { - throw new OgException(t('There are no OG fields in entity %entity-type and bundle %bundle referencing %group-type - %group-bundle.', $params)); + throw new OgException(format_string('There are no OG fields in entity %entity-type and bundle %bundle referencing %group-type - %group-bundle.', $params)); } } @@ -2088,15 +2176,13 @@ function og_is_group_audience_field($field_name) { * The entity type. * @param $bundle_name * The bundle name to be checked. - * @param $include_secondary - * TRUE, if secondary group-audience field should be also returned. * * @return * Array keyed with the field name and the field label as the value. */ -function og_get_group_audience_fields($entity_type = 'user', $bundle_name = 'user', $include_secondary = TRUE) { +function og_get_group_audience_fields($entity_type = 'user', $bundle_name = 'user') { $return = &drupal_static(__FUNCTION__, array()); - $identifier = $entity_type . ':' . $bundle_name . ':' . $include_secondary; + $identifier = $entity_type . ':' . $bundle_name; if (isset($return[$identifier])) { return $return[$identifier]; } @@ -2112,10 +2198,6 @@ function og_get_group_audience_fields($entity_type = 'user', $bundle_name = 'use continue; } - if (!$include_secondary && !empty($field_info['settings']['handler_settings']['primary_field'])) { - continue; - } - foreach ($field_info['bundles'][$entity_type] as $field_bundle) { if ($field_bundle == $bundle_name) { $instance_info = field_info_instance($entity_type, $field_name, $bundle_name); diff --git a/og.test b/og.test index c5d6419..099e3fa 100644 --- a/og.test +++ b/og.test @@ -1,10 +1,13 @@ pass('Grouping with incorrect field name does not work.'); } - // Exception grouping using a secondary field. - $og_field = og_fields_info(OG_AUDIENCE_FIELD); - $og_field['field']['settings']['target_type'] = 'entity_test'; - $og_field['field']['settings']['handler_settings']['primary_field'] = OG_AUDIENCE_FIELD; - og_create_field('og_ref_secondary', 'node', 'article', $og_field); - $values['field_name'] = 'og_ref_secondary'; - try { - og_group('entity_test', $entity1->pid, $values); - $this->fail('Grouping with secondary field name works.'); - } - catch (OgException $e) { - $this->pass('Grouping with secondary field name does not work.'); - } - // Exception on audience field, referencing wrong target type. $og_field = og_fields_info(OG_AUDIENCE_FIELD); $og_field['field']['settings']['target_type'] = 'node'; @@ -886,322 +875,112 @@ class OgMigrate7000TestCase extends UpgradePathTestCase { /** - * Test primary/ second field in UI. + * Test the complex widget. */ -class OgPrimarySecondaryField extends OGAssertOptionsTestCase { +class OgComplexWidgetTestCase extends DrupalWebTestCase { + public static function getInfo() { return array( - 'name' => 'OG primary/ secondary field', - 'description' => 'Test primary/ secondary field in UI.', + 'name' => 'OG reference widget', + 'description' => 'Test the OG reference widget behavior.', 'group' => 'Organic groups', ); } - /** - * - Page content type as group type - * - Article content type as group content type - * - create 2 groups and one article which belongs to both group - * - Create an editor user who is a member of group1, and two group - * admins for each group - */ function setUp() { parent::setUp('og'); - // Add OG group field to a the node's "page" bundle. - og_create_field(OG_GROUP_FIELD, 'node', 'page'); + // Add OG group field to a the node's "group" bundle. + $this->drupalCreateContentType(array('type' => 'group')); + og_create_field(OG_GROUP_FIELD, 'node', 'group'); - // Add OG audience field to the node's "article" bundle. + // Add OG audience field to the node's "post" bundle. + $this->drupalCreateContentType(array('type' => 'post')); $og_field = og_fields_info(OG_AUDIENCE_FIELD); - $og_field['field']['settings']['target_type'] = 'node'; - og_create_field(OG_AUDIENCE_FIELD, 'node', 'article', $og_field); - - // Add a secondary field to the node's "article" bundle. - $og_field['instance']['label'] = t('Other groups'); - $og_field['instance']['widget']['type'] = 'entityreference_autocomplete'; - $og_field['field']['settings']['handler_settings']['reference_type'] = 'other_groups'; - $og_field['field']['settings']['handler_settings']['primary_field'] = OG_AUDIENCE_FIELD; - $og_field['field']['settings']['handler_settings']['hide_secondary_field'] = TRUE; - og_create_field(OG_AUDIENCE_OTHER_GROUPS_FIELD, 'node', 'article', $og_field); - - // Create an editor user. - $this->editor_user = $this->drupalCreateUser(array('access content', 'edit any article content')); - // Create group managers for these tests, need 'administer group' - // permission to see secondary field. - $this->group1_manager = $this->drupalCreateUser(array('administer group', 'access content', 'create page content', 'edit own article content', 'edit own page content')); - $this->group2_manager = $this->drupalCreateUser(array('access content', 'create page content', 'edit own article content', 'edit own page content')); - - // Create group nodes. - $settings = array( - 'type' => 'page', - OG_GROUP_FIELD . '[und][0][value]' => 1, - 'uid' => $this->group1_manager->uid - ); - $this->group1 = $this->drupalCreateNode($settings); - $settings['uid'] = $this->group2_manager->uid; - $this->group2 = $this->drupalCreateNode($settings); - - // Add editor user to group1. - og_group('node', $this->group1->nid, array('entity' => $this->editor_user->uid)); - - // Change permissions to authenticated member. - $roles = array_flip(og_roles('node', 'page', $this->group1->nid)); - $permissions = array( - 'create article content' => 1, - 'update any article content' => 1, - ); - og_role_change_permissions($roles[OG_AUTHENTICATED_ROLE], $permissions); - - // Create node to add to group. - $settings = array( - 'type' => 'article', - 'uid' => $this->group1_manager->uid, - ); - $this->group_content = $this->drupalCreateNode($settings); - - // Add node to group1 and group2. - $values = array( - 'entity_type' => 'node', - 'entity' => $this->group_content, - ); - og_group('node', $this->group1->nid, $values); - og_group('node', $this->group2->nid, $values); - - // Set Node access strict variable. - variable_set('og_node_access_strict', TRUE); + $og_field['instance']['required'] = TRUE; + og_create_field(OG_AUDIENCE_FIELD, 'node', 'post', $og_field); } - /** - * Test primary/secondary field on node edit for group admin. - * - * Primary field should display the groups the admin is a member of, - * while secondary field should display the groups the admin is not a - * member of. - */ - function testGroupAdminFields() { - // Login as a group manager and try to change group content. - $this->drupalLogin($this->group1_manager); - - $this->drupalGet('node/' . $this->group_content->nid . '/edit'); - - // Check primary field. - $instance = field_info_instance('node', OG_AUDIENCE_FIELD, 'article'); - $this->assertText($instance['label'], t('Primary field label exists.')); - $langcode = LANGUAGE_NONE; - $field_id = drupal_html_id("edit-".OG_AUDIENCE_FIELD."-$langcode"); - $this->assertOptionSelected($field_id, $this->group1->nid, t('Group1 appears in primary field and is selected.')); - $this->assertNoOption($field_id, $this->group2->nid, t("Group2 doesn't appear in primary field.")); - - // Check secondary field. - $instance = field_info_instance('node', OG_AUDIENCE_OTHER_GROUPS_FIELD, 'article'); - $this->assertText($instance['label'], t('Secondary field label exists.')); - $field_id = drupal_html_id("edit-".OG_AUDIENCE_OTHER_GROUPS_FIELD."-$langcode-0-target-id"); - $field_value = $this->group2->title . ' (' . $this->group2->nid . ')'; - $this->assertFieldById($field_id, $field_value, t('Group2 appears in secondary field.')); - - // Update group content, and assert group membership remains correct. - $edit = array('title' => 'Group Content'); - $this->drupalPost('node/' . $this->group_content->nid . '/edit', $edit, t('Save')); - $this->assertText(t('Article Group Content has been updated.'), t('Group manager edits group content node successfully.')); - $this->assertTrue(og_is_member('node', $this->group1->nid, 'node', $this->group_content->nid), t('Group content still belongs to group1')); - $this->assertTrue(og_is_member('node', $this->group2->nid, 'node', $this->group_content->nid), t('Group content still belongs to group2')); - } /** - * Test primary/ secondary field on node edit for editor. - * - * Primary field should display the groups the admin is a member of, - * while secondary field is invisible. + * Test "field modes" of the OG reference widget. */ - function testNonGroupAdminFields() { - // Login as a group member and try to change group content. - $this->drupalLogin($this->editor_user); - - $this->drupalGet('node/' . $this->group_content->nid . '/edit'); - - // Check primary field. - $instance = field_info_instance('node', OG_AUDIENCE_FIELD, 'article'); - $this->assertText($instance['label'], t('Primary field label exists.')); - $langcode = LANGUAGE_NONE; - $field_id = drupal_html_id("edit-".OG_AUDIENCE_FIELD."-$langcode"); - $this->assertOptionSelected($field_id, $this->group1->nid, t('Group1 appears in primary field and is selected.')); - $this->assertNoOption($field_id, $this->group2->nid, t("Group2 doesn't appear in primary field.")); - - // Check secondary field. - $instance = field_info_instance('node', OG_AUDIENCE_OTHER_GROUPS_FIELD, 'article'); - $this->assertNoText($instance['label'], t("Secondary field isn't accessible by user.")); - - // Update group content, and assert group membership remains correct. - $edit = array('title' => 'Group Content'); - $this->drupalPost('node/' . $this->group_content->nid . '/edit', $edit, t('Save')); - $this->assertText(t('Article Group Content has been updated.'), t('Group manager edits group content node successfully.')); - $this->assertTrue(og_is_member('node', $this->group1->nid, 'node', $this->group_content->nid), t('Group content still belongs to group1')); - $this->assertTrue(og_is_member('node', $this->group2->nid, 'node', $this->group_content->nid), t('Group content still belongs to group2')); - } + function testFieldModes() { + $user1 = $this->drupalCreateUser(array('administer group', 'access content', 'create post content')); + $user2 = $this->drupalCreateUser(array('access content', 'create post content')); - /** - * Test the group audience field when editing content; - * 1. Member with edit own content permission. - * 2. Member with edit any content permission. - */ - function testGroupAudienceField() { - // Test user with "Edit own article content" permission. - $own_editor_user = $this->drupalCreateUser(); - og_group('node', $this->group1->nid, array('entity' => $own_editor_user->uid)); + // Create group nodes. + $settings = array( + 'type' => 'group', + OG_GROUP_FIELD . '[und][0][value]' => 1, + ); + $settings['uid'] = $user1->uid; + $group1 = $this->drupalCreateNode($settings); - // Update group permissions. - og_create_field(OG_GROUP_FIELD, 'node', 'article'); - $roles = array_flip(og_roles('node', 'article')); - og_role_change_permissions($roles[OG_AUTHENTICATED_ROLE], array('update own article content' => TRUE)); + $settings['uid'] = $user2->uid; + $group2 = $this->drupalCreateNode($settings); - // Create content owned by own_editor_user and add it to group1. $settings = array( - 'type' => 'article', - 'uid' => $own_editor_user->uid, - ); - $node = $this->drupalCreateNode($settings); - // Add the content to group1. - $values = array( - 'entity_type' => 'node', - 'entity' => $node, + 'type' => 'post', ); - og_group('node', $this->group1->nid, $values); - // Login and check - $this->drupalLogin($own_editor_user); - $this->drupalGet('node/' . $node->nid . '/edit'); - $field_id = drupal_html_id('edit-' . OG_AUDIENCE_FIELD .'-' . LANGUAGE_NONE); - $this->assertOptionSelected($field_id, $this->group1->nid, t('Group1 is selected in group audience field (Edit own content).')); - - // Test user with "Edit any article content" permission. - // Update group permissions. - og_create_field(OG_GROUP_FIELD, 'node', 'article'); - $roles = array_flip(og_roles('node', 'article')); - og_role_change_permissions($roles[OG_AUTHENTICATED_ROLE], array('update own article content' => FALSE, 'update any article content' => TRUE)); + $settings['uid'] = $user1->uid; + $post1 = $this->drupalCreateNode($settings); + og_group('node', $group1->nid, array('entity_type' => 'node', 'entity' => $post1)); - $this->drupalLogin($this->editor_user); - $this->drupalGet('node/' . $node->nid . '/edit'); - $this->assertOptionSelected($field_id, $this->group1->nid, t('Group1 is selected in group audience field (Edit any content).')); - } + $settings['uid'] = $user2->uid; + $post2 = $this->drupalCreateNode($settings); + og_group('node', $group2->nid, array('entity_type' => 'node', 'entity' => $post2)); -} + $this->drupalLogin($user1); + $this->drupalGet("node/$post1->nid/edit"); + $fields = $this->xpath('//*[@id="edit-og-group-ref-und-0-default"]'); + $this->assertEqual($fields[0]->option['value'], '_none', '"Default" field mode is not required for administrator.'); + $fields = $this->xpath('//*[@id="edit-og-group-ref-und-0-admin-0-target-id"]'); + $this->assertTrue(strpos($fields[0]->attributes()->class[0], 'form-autocomplete'), '"Administrator field more is an autocomplete widget type."'); -/** - * Test second field forcing primary field to optional in UI. - */ -class OgSecondaryForcePrimaryOptField extends OGAssertOptionsTestCase { + $this->drupalLogin($user2); + $this->drupalGet("node/$post2->nid/edit"); - public static function getInfo() { - return array( - 'name' => 'OG secondary field force primary optional', - 'description' => 'Test secondary field forcing primary field optional in UI.', - 'group' => 'Organic groups', - ); + $fields = $this->xpath('//*[@id="edit-og-group-ref-und-0-default"]'); + $this->assertEqual($fields[0]->option['value'], $group2->nid, '"Default" field mode is required.'); } /** - * - Set Page content type as group type. - * - Set Article content type as group content type. - * - Set OG_AUDIENCE_FIELD on Article to be single select + required. - * - Set OG_AUDIENCE_OTHER_GROUPS_FIELD to use "force_optional_primary". - * - Create a group and one article which belongs to it. - * - Create an admin user who is NOT a member of group. + * Test non-accessible group IDs are saved, upon form submit. */ - function setUp() { - parent::setUp('og'); - - // Add OG group field to a the node's "page" bundle. - og_create_field(OG_GROUP_FIELD, 'node', 'page'); - - // Add OG audience field to the node's "article" bundle. - $og_field = og_fields_info(OG_AUDIENCE_FIELD); - $og_field['field']['settings']['target_type'] = 'node'; - $og_field['field']['cardinality'] = 1; - $og_field['field']['required'] = TRUE; - og_create_field(OG_AUDIENCE_FIELD, 'node', 'article', $og_field); - - // Add a secondary field to the node's "article" bundle. - $og_field['instance']['label'] = t('Other groups'); - $og_field['instance']['widget']['type'] = 'options_select'; - $og_field['field']['cardinality'] = 1; - $og_field['field']['required'] = TRUE; - $og_field['field']['settings']['handler_settings']['reference_type'] = 'other_groups'; - $og_field['field']['settings']['handler_settings']['primary_field'] = OG_AUDIENCE_FIELD; - $og_field['field']['settings']['handler_settings']['hide_secondary_field'] = TRUE; - $og_field['field']['settings']['handler_settings']['force_optional_primary'] = TRUE; - og_create_field(OG_AUDIENCE_OTHER_GROUPS_FIELD, 'node', 'article', $og_field); - - // Create a group manager. - $this->group_manager = $this->drupalCreateUser(array('access content', 'create page content', 'edit own page content', 'edit own article content')); - - // Create an admin user. - $this->admin_user = $this->drupalCreateUser(array('administer group', 'access content', 'create page content', 'edit any page content', 'edit own page content', 'edit any article content', 'edit own article content')); + function testHiddenGroupIds() { + $user1 = $this->drupalCreateUser(array('administer group', 'access content', 'create post content')); + $user2 = $this->drupalCreateUser(array('access content', 'create post content')); // Create group nodes. $settings = array( - 'type' => 'page', + 'type' => 'group', OG_GROUP_FIELD . '[und][0][value]' => 1, - 'uid' => $this->group_manager->uid - ); - $this->group = $this->drupalCreateNode($settings); - - // Change permissions to authenticated member. - $roles = array_flip(og_roles('node', 'page', $this->group->nid)); - $permissions = array( - 'create article content' => 1, - 'update any article content' => 1, ); - og_role_change_permissions($roles[OG_AUTHENTICATED_ROLE], $permissions); + $settings['uid'] = $user1->uid; + $group1 = $this->drupalCreateNode($settings); + $settings['uid'] = $user2->uid; + $group2 = $this->drupalCreateNode($settings); - // Create article node to add to group. $settings = array( - 'type' => 'article', - 'uid' => $this->group_manager->uid, + 'type' => 'post', ); - $this->group_content = $this->drupalCreateNode($settings); - - // Add node to group - $values = array( - 'entity_type' => 'node', - 'entity' => $this->group_content, - ); - og_group('node', $this->group->nid, $values); - - // Ensure Node access strict variable is FALSE, - // so we can test that an admin user who is not a member - // of the group can edit the article content. - variable_set('og_node_access_strict', FALSE); + $settings['uid'] = $user1->uid; + $post1 = $this->drupalCreateNode($settings); + og_group('node', $group1->nid, array('entity_type' => 'node', 'entity' => $post1)); + og_group('node', $group2->nid, array('entity_type' => 'node', 'entity' => $post1)); + + $this->drupalLogin($user2); + $this->drupalPost("node/$post1->nid/edit", array(), 'Save'); + + // Assert post still belongs to both groups, although user was able + // to select only one. + $gids = og_get_entity_groups('node', $post1); + $this->assertEqual(count($gids['node']), 2, 'Hidden groups remained.'); } - - /** - * Test primary/secondary fields on node edit for admin - * (non-member) user. - * - * Primary field should display no groups and only -None- option, - * since the admin user is not a member of any group. - * The secondary field should display the Page group we created. - * - */ - function testGroupFields() { - $this->drupalLogin($this->admin_user); - - $this->drupalGet('node/' . $this->group_content->nid . '/edit'); - - // Check primary field. - $instance = field_info_instance('node', OG_AUDIENCE_FIELD, 'article'); - $this->assertText($instance['label'], t('Primary field label exists.')); - $langcode = LANGUAGE_NONE; - $field_id = drupal_html_id("edit-" . OG_AUDIENCE_FIELD . "-$langcode"); - $this->assertOption($field_id, '_none', t('"None" option appears in primary field.')); - $this->assertNoOption($field_id, $this->group->nid, t("Group doesn't appear in primary field.")); - - // Check secondary field. - $instance = field_info_instance('node', OG_AUDIENCE_OTHER_GROUPS_FIELD, 'article'); - $this->assertText($instance['label'], t('Secondary field label exists.')); - $field_id = drupal_html_id("edit-".OG_AUDIENCE_OTHER_GROUPS_FIELD."-$langcode"); - $this->assertOptionSelected($field_id, $this->group->nid, t('Group appears in secondary field and is selected.')); - } } @@ -1266,3 +1045,4 @@ class OgRoleRevoke extends DrupalWebTestCase { $this->assertFalse($result->rowCount(), t('User is removed, so all roles of this user were revoked')); } } + diff --git a/og_context/og_context.module b/og_context/og_context.module index 2e98684..f39bf8f 100644 --- a/og_context/og_context.module +++ b/og_context/og_context.module @@ -320,12 +320,10 @@ function og_context_determine_context($group_type, $item = NULL) { $item = menu_get_item(); } - $providers = og_context_negotiation_info(); - foreach ($enabled_providers as $name) { - if (!in_array($name, $providers)) { + foreach (og_context_negotiation_info() as $name => $provider) { + if (!in_array($name, $enabled_providers)) { continue; } - $provider = $providers[$name]; $invoke = FALSE; if (!empty($provider['menu path'])) { foreach ($provider['menu path'] as $path) { @@ -380,7 +378,7 @@ function og_context_handler_url() { } $node_type = $item['map'][2]; - if (!$fields = og_get_group_audience_fields('node', $node_type, FALSE)) { + if (!$fields = og_get_group_audience_fields('node', $node_type)) { return; } $gids = array(); diff --git a/og_example/og_example.install b/og_example/og_example.install index 1bdbe1b..65560d3 100644 --- a/og_example/og_example.install +++ b/og_example/og_example.install @@ -22,12 +22,4 @@ function og_example_enable() { 'skip_perm' => FALSE, ); og_create_field(OG_AUDIENCE_FIELD, 'node', 'post', $og_field); - - // Create "Other groups" field. - $og_field['instance']['label'] = t('Other groups'); - $og_field['instance']['widget']['type'] = 'entityreference_autocomplete'; - $og_field['field']['settings']['handler_settings']['reference_type'] = 'other_groups'; - $og_field['field']['settings']['handler_settings']['primary_field'] = OG_AUDIENCE_FIELD; - $og_field['field']['settings']['handler_settings']['hide_secondary_field'] = TRUE; - og_create_field(OG_AUDIENCE_OTHER_GROUPS_FIELD, 'node', 'post', $og_field); } diff --git a/og_ui/og_ui.admin.inc b/og_ui/og_ui.admin.inc index d75494c..ecd19ae 100644 --- a/og_ui/og_ui.admin.inc +++ b/og_ui/og_ui.admin.inc @@ -121,7 +121,7 @@ function og_ui_add_users($form, &$form_state, $group_type, $gid) { '#description' => t('Select the state of the membership.'), ); - $field_names = og_get_group_audience_fields('user', 'user', FALSE); + $field_names = og_get_group_audience_fields(); $field_name = !empty($form_state['values']['field_name']) ? $form_state['values']['field_name'] : key($field_names); $form['og_user']['field_name'] = array( diff --git a/og_ui/og_ui.module b/og_ui/og_ui.module index ced80c6..9a064fe 100644 --- a/og_ui/og_ui.module +++ b/og_ui/og_ui.module @@ -725,7 +725,7 @@ function og_ui_field_formatter_settings_form($field, $instance, $view_mode, $for '#title' => t('Field name'), '#description' => t('Select the field that should register the user subscription.'), '#type' => 'select', - '#options' => array(0 => t('Automatic (best matching)')) + og_get_group_audience_fields('user', 'user', FALSE), + '#options' => array(0 => t('Automatic (best matching)')) + og_get_group_audience_fields('user', 'user'), '#default_value' => $settings['field_name'], ); } @@ -745,7 +745,7 @@ function og_ui_field_formatter_settings_summary($field, $instance, $view_mode) { } if ($settings['field_name']) { - $fields = og_get_group_audience_fields('user', 'user'); + $fields = og_get_group_audience_fields(); return t('Field %label', array('%label' => $fields[$settings['field_name']])); } else { @@ -960,15 +960,6 @@ function og_ui_node_type_save($bundle_name) { $og_field['field']['target_type'] = variable_get('target_type_' . $bundle_name); $og_field['field']['settings']['handler_settings']['target_bundles'] = variable_get('target_bundles_' . $bundle_name); og_create_field(OG_AUDIENCE_FIELD, 'node', $bundle_name, $og_field); - - // Create "Other groups" field. - $og_field['instance']['label'] = t('Other groups'); - $og_field['instance']['widget']['type'] = 'entityreference_autocomplete'; - $og_field['field']['settings']['handler_settings']['reference_type'] = 'other_groups'; - $og_field['field']['settings']['handler_settings']['primary_field'] = OG_AUDIENCE_FIELD; - $og_field['field']['settings']['handler_settings']['hide_secondary_field'] = TRUE; - $og_field['field']['settings']['handler_settings']['force_optional_primary'] = TRUE; - og_create_field(OG_AUDIENCE_OTHER_GROUPS_FIELD, 'node', $bundle_name, $og_field); } // Delete the variable, as we will rely on the presence of the field. diff --git a/plugins/entityreference/behavior/OgBehaviorHandler.class.php b/plugins/entityreference/behavior/OgBehaviorHandler.class.php index 40d3a58..e73b2d8 100644 --- a/plugins/entityreference/behavior/OgBehaviorHandler.class.php +++ b/plugins/entityreference/behavior/OgBehaviorHandler.class.php @@ -112,10 +112,6 @@ class OgBehaviorHandler extends EntityReference_BehaviorHandler_Abstract { public function groupAudiencegetDiff($entity_type, $entity, $field, $instance, $langcode, $items) { $return = FALSE; - if (!empty($field['settings']['handler_settings']['primary_field'])) { - return; - } - $field_name = $field['field_name']; $wrapper = entity_metadata_wrapper($entity_type, $entity); $og_memberships = $wrapper->{$field_name . '__og_membership'}->value(); diff --git a/plugins/entityreference/behavior/OgWidgetHandler.class.php b/plugins/entityreference/behavior/OgWidgetHandler.class.php new file mode 100644 index 0000000..8a47e3d --- /dev/null +++ b/plugins/entityreference/behavior/OgWidgetHandler.class.php @@ -0,0 +1,57 @@ + array( + 'widget_type' => 'options_select', + ), + 'admin' => array( + 'widget_type' => 'entityreference_autocomplete', + ), + ); + + $field_types = array( + 'default' => array( + 'title' => t('Default widget type'), + 'description' => t('The widget type of the field as it will appear to the user.'), + ), + 'admin' => array( + 'title' => t('Administrator widget type'), + 'description' => t('The widget type of the field that will appear only to a user with "Adminiser group" permission.'), + ), + ); + + module_load_include('inc', 'field_ui', 'field_ui.admin'); + $widget_types = field_ui_widget_type_options('entityreference'); + unset($widget_types['og_complex']); + + foreach ($field_types as $field_type => $value) { + $form[$field_type]['widget_type'] = array( + '#type' => 'select', + '#title' => $value['title'], + '#required' => TRUE, + '#options' => $widget_types, + '#default_value' => $settings[$field_type]['widget_type'], + '#description' => $value['description'], + ); + } + + return $form; + } + +} diff --git a/plugins/entityreference/behavior/og_widget.inc b/plugins/entityreference/behavior/og_widget.inc new file mode 100644 index 0000000..e7f2a3a --- /dev/null +++ b/plugins/entityreference/behavior/og_widget.inc @@ -0,0 +1,8 @@ + t('OG widget'), + 'class' => 'OgWidgetHandler', + 'behavior type' => 'instance', + 'force enabled' => TRUE, +); diff --git a/plugins/entityreference/selection/OgSelectionHandler.class.php b/plugins/entityreference/selection/OgSelectionHandler.class.php index 1af4156..5032141 100644 --- a/plugins/entityreference/selection/OgSelectionHandler.class.php +++ b/plugins/entityreference/selection/OgSelectionHandler.class.php @@ -13,8 +13,8 @@ class OgSelectionHandler extends EntityReference_SelectionHandler_Generic { return new OgSelectionHandler($field, $instance, $entity_type, $entity); } - /** - * Override settings form(). + /** + * Override EntityReferenceHandler::settingsForm(). */ public static function settingsForm($field, $instance) { $form = parent::settingsForm($field, $instance); @@ -36,15 +36,10 @@ class OgSelectionHandler extends EntityReference_SelectionHandler_Generic { ); } else { - $settings = $field['settings']['handler_settings']; $settings += array( 'target_bundles' => array(), 'membership_type' => OG_MEMBERSHIP_TYPE_DEFAULT, - 'reference_type' => 'my_groups', - 'primary_field' => FALSE, - 'hide_secondary_field' => TRUE, - 'force_optional_primary' => TRUE, ); $form['target_bundles'] = array( @@ -69,77 +64,6 @@ class OgSelectionHandler extends EntityReference_SelectionHandler_Generic { '#default_value' => $settings['membership_type'], '#required' => TRUE, ); - - $form['reference_type'] = array( - '#type' => 'select', - '#title' => t('Reference'), - '#options' => array( - 'my_groups' => t('My groups'), - 'other_groups' => t('Other groups'), - 'all_groups' => t('All groups'), - ), - '#description' => t('What groups should be referenced.'), - '#default_value' => $settings['reference_type'], - ); - - $options = array('0' => t('None')); - - // Get all the other group audience fields in this bundle. - $entity_type = $instance['entity_type']; - $bundle = $instance['bundle']; - $fields_info = field_info_fields(); - foreach (field_info_instances($entity_type, $bundle) as $field_name => $field_instance) { - if ($field_name == $field['field_name']) { - // This is the current field. - continue; - } - if ($fields_info[$field_name]['type'] != 'entityreference' || $fields_info[$field_name]['settings']['handler'] != 'og') { - // This is not an Entity reference field. - continue; - } - - if (!empty($fields_info[$field_name]['settings']['handler_settings']['primary_field'])) { - // Field is already a secondary field. - continue; - } - $options[$field_name] = $field_instance['label'] . ' (' . $field_name . ')'; - } - - $form['primary_field'] = array( - '#type' => 'select', - '#title' => t('Primary field'), - '#description' => t('Select a field that will be populated with the values of this field.'), - '#options' => $options, - '#default_value' => $settings['primary_field'], - '#required' => TRUE, - '#element_validate' => array('og_handler_primary_field_validate'), - ); - - $form['hide_secondary_field'] = array( - '#type' => 'checkbox', - '#title' => t('Hide secondary field'), - '#description' => t('Show the secondary field only to users with "administer group" permission.'), - '#default_value' => $settings['hide_secondary_field'], - '#states' => array( - 'invisible' => array( - ':input[name="field[settings][handler_settings][primary_field]"]' => array('value' => 0), - ), - ), - ); - - $form['force_optional_primary'] = array( - '#type' => 'checkbox', - '#title' => t('Force optional primary field'), - '#description' => t("Force the primary field to be optional when the secondary field is shown. If the primary field is requrired, then this will allow privileged users to edit group content for groups they're not members of -- i.e., they can leave the primary field blank."), - '#default_value' => $settings['force_optional_primary'], - '#states' => array( - 'invisible' => array( - ':input[name="field[settings][handler_settings][primary_field]"]' => array('value' => 0), - ), - ), - ); - - form_load_include($form_state, 'php', 'og', '/plugins/selection/og.class'); } return $form; @@ -175,10 +99,14 @@ class OgSelectionHandler extends EntityReference_SelectionHandler_Generic { // Show only the entities that are active groups. $query->fieldCondition(OG_GROUP_FIELD, 'value', 1, '='); + if (empty($this->instance['field_mode'])) { + return $query; + } + + $field_mode = $this->instance['field_mode']; $user_groups = og_get_groups_by_user(NULL, $group_type); - $reference_type = $this->field['settings']['handler_settings']['reference_type']; // Show the user only the groups they belong to. - if ($reference_type == 'my_groups') { + if ($field_mode == 'default') { if ($user_groups && !empty($this->instance) && $this->instance['entity_type'] == 'node') { // Determine which groups should be selectable. $node = $this->entity; @@ -206,7 +134,7 @@ class OgSelectionHandler extends EntityReference_SelectionHandler_Generic { $query->propertyCondition($entity_info['entity keys']['id'], -1, '='); } } - elseif ($reference_type == 'other_groups' && $user_groups) { + elseif ($field_mode == 'admin' && $user_groups) { // Show only groups the user doesn't belong to. if (!empty($this->instance) && $this->instance['entity_type'] == 'node') { // Don't include the groups, the user doesn't have create @@ -232,38 +160,3 @@ class OgSelectionHandler extends EntityReference_SelectionHandler_Generic { // $handler->entityFieldQueryAlter($query); } } - -/** - * Validate handler; Check primary field. - */ -function og_handler_primary_field_validate($element, $form_state) { - if (empty($form_state['values']['instance'])) { - // Field doesn't exist yet. - return; - } - - $field_name = $form_state['values']['field']['settings']['handler_settings']['primary_field']; - if (!$field_name) { - return; - } - - // Check the primary field has the same target type, bundle and membership - // type as the secondary one. - $primary_field = field_info_field($field_name); - $secondary_field = $form_state['values']['field']; - if ($primary_field['settings']['target_type'] != $secondary_field['settings']['target_type']) { - form_error($element, t('Primary field target type does not match the secondary field.')); - } - elseif (!empty($primary_field['settings']['handler_settings']['target_bundles']) && $primary_field['settings']['handler_settings']['target_bundles'] != $secondary_field['settings']['handler_settings']['target_bundles']) { - // Primary field defines bundles, but they are not the same as the - // secondary. - form_error($element, t('Primary field target bundles do not match the secondary field.')); - } - - if ($primary_field['settings']['handler_settings']['membership_type'] != $secondary_field['settings']['handler_settings']['membership_type']) { - form_error($element, t('Primary field membership type does not match the secondary field.')); - } - - $entity_type = $form_state['values']['instance']['entity_type']; - $bundle = $form_state['values']['instance']['bundle']; -}