diff --git i/conditional_fields.module w/conditional_fields.module index 56b65b5..ad6621e 100644 --- i/conditional_fields.module +++ w/conditional_fields.module @@ -210,6 +210,60 @@ function conditional_fields_element_info_alter(&$types) { } /** + * Implements hook_field_group_build_pre_render_alter() + * Have to wait for the group elements to be created - unfortunately this is after after_build + */ +function conditional_fields_field_group_build_pre_render_alter(&$element) { + // Have to re-process conditional fields over again for newly created + // fieldgroup elements (and existing elements moved to fieldgroup children) + + // $form_state is added to $form['#form_state'] via conditional_fields_form_after_build() + $form_state = $element['#form_state']; + $form_state['complete form'] = $element; + $form = &$form_state['complete form']; + // Loop through fieldgroups and fieldgroup children + $new_dependents = array(); + foreach ($form['#fieldgroups'] as $group_name => $group) { + // Call element_after_build for fieldgroup children + foreach($group->children as $field_name) { + $parents = array_merge($group->array_parents, array($field_name)); + $field_element = &drupal_array_get_nested_value($form, $parents); + conditional_fields_element_after_build($field_element, $form_state, TRUE); + } + // Call element_after_build for fieldgroup element + $group_element = &drupal_array_get_nested_value($form, $group->array_parents); + $group_element['#field_name'] = $group_name; + // Make sure group element has an ID to select in drupal_process_states + $group_element['#id'] = isset($group_element['#id']) ? $group_element['#id'] : $group_name; + // Need to wrap markup type with a div with the ID, unless ID already present in prefix or markup + if (isset($group_element['#type']) && $group_element['#type'] == 'markup') { + if ((!isset($group_element['#prefix']) || !strstr($group_element['#prefix'], '#' . $group_element['#id'])) + && (!isset($group_element['#markup']) || !strstr($group_element['#markup'], '#' . $group_element['#id'])) + ) { + $group_element['#prefix'] = '
' . (isset($group_element['#prefix']) ? $group_element['#prefix'] : ''); + $group_element['#suffix'] = (isset($group_element['#suffix']) ? $group_element['#suffix'] : '') . '
'; + } + } + conditional_fields_element_after_build($group_element, $form_state, TRUE); + if (isset($form['#conditional_fields'][$group_name], $form['#conditional_fields'][$group_name]['dependees'])) { + $new_dependents[$group_name] = &$group_element; + } + } + + // Call form_after_build + $form = conditional_fields_form_after_build($form, $form_state, TRUE); + + // Call validation for group dependents + foreach ($new_dependents as $dependent_name => &$dependent) { + conditional_fields_dependent_validate($dependent, $form_state, $form); + } + // Call form validation + conditional_fields_form_validate($form, $form_state); + + $element = $form; +} + +/** * Processes form elements with dependencies. * * Just adds a #conditional_fields property to the form with the needed @@ -217,7 +271,7 @@ function conditional_fields_element_info_alter(&$types) { * - The fields #parents property. * - Field dependencies data. */ -function conditional_fields_element_after_build($element, &$form_state) { +function conditional_fields_element_after_build($element, &$form_state, $reprocess = FALSE) { // Ensure that the element is a field. if (isset($element['#field_name'])) { $field = $element; @@ -237,6 +291,10 @@ function conditional_fields_element_after_build($element, &$form_state) { return $element; } + // Get fieldgroup name if field belongs to one + $group_name = isset($form['#group_children']) && isset($form['#group_children'][$field['#field_name']]) ? + $form['#group_children'][$field['#field_name']] : NULL; + // Some fields do not have entity type and bundle properties. In this case we // try to use the properties from the form. This is not an optimal solution, // since in case of fields in entities within entities they might not correspond, @@ -262,11 +320,24 @@ function conditional_fields_element_after_build($element, &$form_state) { // Attach dependent. if (isset($dependencies['dependents'][$field['#field_name']])) { foreach ($dependencies['dependents'][$field['#field_name']] as $id => $dependency) { - if (!isset($form['#conditional_fields'][$field['#field_name']]['dependees'][$id])) { + if ($reprocess || !isset($form['#conditional_fields'][$field['#field_name']]['dependees'][$id])) { conditional_fields_attach_dependency($form, array('#field_name' => $dependency['dependee']), $field, $dependency['options'], $id); } } } + // Also attach dependent if element is a (first) child in a dependent fieldgroup + // and the dependency state isn't 'visible' or 'hidden' + // (this is done on the fieldgroup element itself) + if ($group_name && isset($dependencies['dependents'][$group_name]) ) { + $group_dependent = $dependencies['dependents'][$group_name]; + if (!in_array($group_dependent[key($group_dependent)]['options']['state'], array('visible', 'hidden'))) { + foreach ($group_dependent as $id => $dependency) { + if ($reprocess || !isset($form['#conditional_fields'][$field['#field_name']]['dependees'][$id])) { + conditional_fields_attach_dependency($form, array('#field_name' => $dependency['dependee']), $field, $dependency['options'], $id); + } + } + } + } // Attach dependee. // TODO: collect information about every element of the dependee widget, not @@ -274,7 +345,7 @@ function conditional_fields_element_after_build($element, &$form_state) { // define per-element sets of dependency values. if (isset($dependencies['dependees'][$field['#field_name']])) { foreach ($dependencies['dependees'][$field['#field_name']] as $id => $dependency) { - if (!isset($form['#conditional_fields'][$field['#field_name']]['dependents'][$id])) { + if ($reprocess || !isset($form['#conditional_fields'][$field['#field_name']]['dependents'][$id])) { conditional_fields_attach_dependency($form, $field, array('#field_name' => $dependency['dependent']), $dependency['options'], $id); } } @@ -383,8 +454,10 @@ function conditional_fields_attach_dependency(&$form, $dependee, $dependent, $op // Attach dependee. // Use the #parents property of the dependee instead of #field_parents since // we will need access to the full structure of the widget. + // We also need #field_parents to get the field from $form if (isset($dependee['#parents'])) { $form['#conditional_fields'][$dependee['#field_name']]['parents'] = $dependee['#parents']; + $form['#conditional_fields'][$dependee['#field_name']]['array_parents'] = $dependee['#array_parents']; $form['#conditional_fields'][$dependee['#field_name']]['dependents'][$id] = array( 'dependent' => $dependent['#field_name'], 'options' => $options, @@ -400,6 +473,7 @@ function conditional_fields_attach_dependency(&$form, $dependee, $dependent, $op } if (isset($dependent_parents)) { $form['#conditional_fields'][$dependent['#field_name']]['field_parents'] = $dependent_parents; + $form['#conditional_fields'][$dependent['#field_name']]['array_parents'] = $dependent['#array_parents']; $form['#conditional_fields'][$dependent['#field_name']]['dependees'][$id] = array( 'dependee' => $dependee['#field_name'], 'options' => $options, @@ -424,6 +498,10 @@ function conditional_fields_form_after_build($form, &$form_state) { return $form; } + // Set $form_state in $form so hook_field_group_build_pre_render_alter has access to it + // when it is invoked after after_build (when fieldgroup elements are attached to form) + $form['#form_state'] =& $form_state; + $effects = array(); $state_handlers = conditional_fields_states_handlers(); @@ -435,7 +513,8 @@ function conditional_fields_form_after_build($form, &$form_state) { continue; } - $dependent_location = array_merge($dependent_info['field_parents'], array($dependent)); + // Here we use #array_parents to get field from $form + $dependent_location = $dependent_info['array_parents']; $dependent_form_field = drupal_array_get_nested_value($form, $dependent_location); // Cycle the dependant's dependees. @@ -445,9 +524,16 @@ function conditional_fields_form_after_build($form, &$form_state) { if (empty($form['#conditional_fields'][$dependee])) { continue; } + // Skip this dependency if it's a group element and state is not visible/hidden + // (dependencies for other states are attached to fieldgroup children elements) + if (in_array($dependent_form_field['#field_name'], array_keys($form['#fieldgroups'])) && !in_array($dependency['options']['state'], array('visible', 'hidden'))) { + continue; + } $dependee_info = $form['#conditional_fields'][$dependee]; - $dependee_form_field = drupal_array_get_nested_value($form, $dependee_info['parents']); + // Here we use #array_parents to get field from $form + $dependee_location = $dependee_info['array_parents']; + $dependee_form_field = drupal_array_get_nested_value($form, $dependee_location); $options = $dependency['options']; // Load field edit behaviors. @@ -669,7 +755,12 @@ function conditional_fields_form_after_build($form, &$form_state) { * @see conditional_fields_form_validate() */ function conditional_fields_dependent_validate($element, &$form_state, $form) { - $dependent = $element[$element['#language']]; + if (isset($element['#language'], $element[$element['#language']])) { + $dependent = $element[$element['#language']]; + } + else { + $dependent = $element; + } // Check if this field's dependencies were triggered. if (conditional_fields_evaluate_dependencies($dependent, $form, $form_state)) { @@ -691,7 +782,7 @@ function conditional_fields_dependent_validate($element, &$form_state, $form) { // conditional_fields_form_validate(). $errors = form_get_errors(); - if ($errors) { + if ($errors && isset($dependent['#parents'])) { // group elements have no #parents key $error_key = implode('][', $dependent['#parents']); foreach ($errors as $name => $error) { // An error triggered by this field might have been set on a descendant @@ -720,7 +811,9 @@ function conditional_fields_dependent_validate($element, &$form_state, $form) { */ function conditional_fields_form_field_get_values($element, $form_state) { // Fall back to #parents to support custom dependencies. - $parents = isset($element['#field_parents']) ? $element['#field_parents'] : $element['#parents']; + // $parents = isset($element['#field_parents']) ? $element['#field_parents'] : $element['#parents']; + // Should this be the other way around? Isn't #parents the parent keys in $form_state['values']? + $parents = isset($element['#parents']) ? $element['#parents'] : $element['#field_parents']; return drupal_array_get_nested_value($form_state['values'], $parents); } @@ -1001,7 +1094,7 @@ function conditional_fields_evaluate_dependencies($dependent, $form, $form_state foreach ($dependencies as $dependency_id => $dependency) { // Extract field values from submitted values. $dependee = $dependency['dependee']; - $dependee_parents = $form['#conditional_fields'][$dependee]['parents']; + $dependee_parents = $form['#conditional_fields'][$dependee]['array_parents']; // We have the parents of the field, but depending on the entity type and // the widget type, they may include additional elements that are actually @@ -1266,21 +1359,34 @@ function conditional_fields_load_dependencies($entity_type = NULL, $bundle = NUL $default_options = conditional_fields_dependency_default_options(); $select = db_select('conditional_fields', 'cf') - ->fields('cf', array('id', 'options')) - ->orderBy('cf.dependent'); + ->fields('cf', array('id', 'options')); $fci_depende = $select->join('field_config_instance', 'fci_dependee', 'cf.dependee = fci_dependee.id'); - $fci_dependent = $select->join('field_config_instance', 'fci_dependent', 'cf.dependent = fci_dependent.id'); $select->addField($fci_depende, 'field_name', 'dependee'); - $select->addField($fci_dependent, 'field_name', 'dependent'); $select->addField($fci_depende, 'entity_type'); $select->addField($fci_depende, 'bundle'); + // Clone query now to allow a union with fieldgroup results + $select_group = clone $select; + + // Join with field_config_instance + $fci_dependent = $select->join('field_config_instance', 'fci_dependent', 'cf.dependent = fci_dependent.id'); + $select->addField($fci_dependent, 'field_name', 'dependent'); + + // Join with field_group + $group_dependent = $select_group->join('field_group', 'fg_dependent', 'cf.dependent = fg_dependent.id'); + $select_group->addField($group_dependent, 'group_name', 'dependent'); + if ($entity_type) { $select->condition( db_and() ->condition('fci_dependee.entity_type', $entity_type) ->condition('fci_dependent.entity_type', $entity_type) ); + $select_group->condition( + db_and() + ->condition('fci_dependee.entity_type', $entity_type) + ->condition('fg_dependent.entity_type', $entity_type) + ); } if ($bundle) { @@ -1289,7 +1395,15 @@ function conditional_fields_load_dependencies($entity_type = NULL, $bundle = NUL ->condition('fci_dependee.bundle', $bundle) ->condition('fci_dependent.bundle', $bundle) ); + $select_group->condition( + db_and() + ->condition('fci_dependee.bundle', $bundle) + ->condition('fg_dependent.bundle', $bundle) + ); } + // Union of results + //$select->orderBy('cf.dependent'); + $select->union($select_group, 'UNION'); $result = $select->execute(); diff --git i/includes/conditional_fields.admin.inc w/includes/conditional_fields.admin.inc index bf790f0..308b475 100644 --- i/includes/conditional_fields.admin.inc +++ w/includes/conditional_fields.admin.inc @@ -106,6 +106,15 @@ function conditional_fields_dependencies_overview_page($bundle_name = NULL, $ent function conditional_fields_dependency_add_form($form, &$form_state, $entity_type, $bundle_name) { $form = array(); $instances = field_info_instances($entity_type, $bundle_name); + // Get field groups on entity + $groups = field_group_info_groups($entity_type, $bundle_name); + $groups = isset($groups['form']) ? $groups['form'] : array(); + foreach ($groups as $group_name => $group) { + $groups[$group_name] = (array)$group; + } + // New merged array of fields & groups for dependents + // Dependees should only be fields ($instances) + $instances_groups = $instances + $groups; if (count($instances) < 2) { $form['no_fields'] = array( @@ -163,7 +172,7 @@ function conditional_fields_dependency_add_form($form, &$form_state, $entity_typ // first row they will appear grouped. if ($first_row == TRUE) { $form['table']['dependencies'][$id]['dependent'] = array( - '#markup' => check_plain($instances[$dependent]['label']) . ' (' . $dependent . ')', + '#markup' => check_plain($instances_groups[$dependent]['label']) . ' (' . $dependent . ')', '#rowspan' => $dependee_count, ); @@ -191,7 +200,7 @@ function conditional_fields_dependency_add_form($form, &$form_state, $entity_typ $row['description']['#colspan'] = 2; } - $row['description']['#markup'] = conditional_fields_dependency_description($instances[$dependency['dependee']]['label'], $instances[$dependent]['label'], $dependency['options']); + $row['description']['#markup'] = conditional_fields_dependency_description($instances[$dependency['dependee']]['label'], $instances_groups[$dependent]['label'], $dependency['options']); $row['edit'] = array( '#type' => 'link', @@ -221,6 +230,14 @@ function conditional_fields_dependency_add_form($form, &$form_state, $entity_typ asort($fields); + // Build list of available groups. + $fieldgroups = array(); + foreach ($groups as $group_name => $group) { + $fieldgroups[$group['id']] = check_plain($group['label'] . ' (' . $group['group_name'] . ')'); + } + + asort($fieldgroups); + // Build list of states. $states = array_map('drupal_strtolower', conditional_fields_states()); @@ -236,7 +253,7 @@ function conditional_fields_dependency_add_form($form, &$form_state, $entity_typ '#title' => t('Dependent'), '#title_display' => 'invisible', '#description' => t('Dependent'), - '#options' => $fields, + '#options' => $fields + $fieldgroups, '#prefix' => '
' . t('Add new dependency') . '
', ), 'dependee' => array(