diff --git a/src/Element/CheckboxTree.php b/src/Element/CheckboxTree.php index e822e6c..e0f222e 100644 --- a/src/Element/CheckboxTree.php +++ b/src/Element/CheckboxTree.php @@ -24,11 +24,13 @@ class CheckboxTree extends FormElement { '#input' => TRUE, '#tree' => TRUE, '#process' => [ - [$class, 'processCheckboxes'], + [$class, 'processCheckboxTree'], ], '#pre_render' => [ [$class, 'preRenderCompositeFormElement'], ], + '#default_value' => [], + '#attached' => ['library' => ['term_reference_tree/term_reference_tree']], '#theme' => 'checkbox_tree', ]; } @@ -36,7 +38,7 @@ class CheckboxTree extends FormElement { /** * Processes a checkboxes form element. */ - public static function processCheckboxes(&$element, FormStateInterface $form_state, &$complete_form) { + public static function processCheckboxTree(&$element, FormStateInterface $form_state, &$complete_form) { $value = is_array($element['#value']) ? $element['#value'] : []; $allowed = []; if (!empty($element['#max_choices']) && $element['#max_choices'] != '-1') { @@ -65,8 +67,8 @@ class CheckboxTree extends FormElement { $tree = new \stdClass(); $tree->children = $terms; + unset($element['#needs_validation']); $element[] = _term_reference_tree_build_level($element, $tree, $form_state, $value, $element['#max_choices'], [], 1); - return $element; } @@ -74,25 +76,12 @@ class CheckboxTree extends FormElement { * {@inheritdoc} */ public static function valueCallback(&$element, $input, FormStateInterface $form_state) { - if ($input === FALSE) { - $value = []; - $element += ['#default_value' => []]; - foreach ($element['#default_value'] as $key) { - $value[$key] = $key; - } - return $value; - } - elseif (is_array($input)) { - foreach ($input as $key => $value) { - if (!isset($value)) { - unset($input[$key]); - } - } - return array_combine($input, $input); - } - else { - return []; + $value = []; + $element += ['#default_value' => []]; + foreach ($element['#default_value'] as $key) { + $value[$key['target_id']] = $key['target_id']; } + return $value; } } diff --git a/src/Plugin/Field/FieldWidget/TermReferenceTree.php b/src/Plugin/Field/FieldWidget/TermReferenceTree.php index a4984ed..c02181c 100644 --- a/src/Plugin/Field/FieldWidget/TermReferenceTree.php +++ b/src/Plugin/Field/FieldWidget/TermReferenceTree.php @@ -41,19 +41,55 @@ class TermReferenceTree extends WidgetBase { $handler_settings = $this->getFieldSetting('handler_settings'); $vocabularies = Vocabulary::loadMultiple($handler_settings['target_bundles']); - if (!array_key_exists('#value', $element)) { - $element['#value'] = array(); - } - - $element['#attached']['library'][] = 'term_reference_tree/term_reference_tree'; $element['#type'] = 'checkbox_tree'; - $element['#default_value'] = (is_object($items[$delta])) ? $items[$delta]->value : []; + $element['#default_value'] = $items->getValue(); $element['#vocabularies'] = $vocabularies; $element['#max_choices'] = $this->fieldDefinition->getFieldStorageDefinition()->getCardinality(); $element['#leaves_only'] = FALSE; + $element['#value_key'] = 'target_id'; $element['#max_depth'] = 0; $element['#start_minimized'] = TRUE; + $element['#element_validate'] = [[get_class($this), 'validateTermReferenceTreeElement']]; return $element; } + /** + * Form element validation handler for term reference form widget. + */ + public static function validateTermReferenceTreeElement(&$element, FormStateInterface $form_state) { + $items = _term_reference_tree_flatten($element, $form_state); + $value = []; + if ($element['#max_choices'] != 1) { + foreach ($items as $child) { + if (!empty($child['#value'])) { + array_push($value, array($element['#value_key'] => $child['#value'])); + + // If the element is leaves only and select parents is on, then automatically + // add all the parents of each selected value. + if ($element['#select_parents'] && $element['#leaves_only']) { + foreach ($child['#parent_values'] as $parent_tid) { + if (!in_array(array($element['#value_key'] => $parent_tid), $value)) { + array_push($value, array($element['#value_key'] => $parent_tid)); + } + } + } + } + } + } + else { + // If it's a tree of radio buttons, they all have the same value, so we can just + // grab the value of the first one. + if (count($items) > 0) { + $child = reset($items); + if (!empty($child['#value'])) { + array_push($value, array($element['#value_key'] => $child['#value'])); + } + } + } + if ($element['#required'] && empty($value)) { + $form_state->setError($element, t('%name field is required.', array('%name' => $element['#title']))); + } + $form_state->setValueForElement($element, $value); + } + }