diff --git a/modules/data_dictionary_widget/css/dataDictionaryWidget.css b/modules/data_dictionary_widget/css/dataDictionaryWidget.css index 743ec03417..ae47ee749c 100644 --- a/modules/data_dictionary_widget/css/dataDictionaryWidget.css +++ b/modules/data_dictionary_widget/css/dataDictionaryWidget.css @@ -1,3 +1,8 @@ +.index-fields-form.error { + border-width: var(--input--error-border-size); + border-color: var(--input--error-border-color); +} + .table { display: table; width: auto; diff --git a/modules/data_dictionary_widget/data_dictionary_widget.module b/modules/data_dictionary_widget/data_dictionary_widget.module index f6a6f7a64a..717ddb66dd 100644 --- a/modules/data_dictionary_widget/data_dictionary_widget.module +++ b/modules/data_dictionary_widget/data_dictionary_widget.module @@ -25,6 +25,22 @@ function data_dictionary_widget_theme($existing, $type, $theme, $path) { ], 'template' => 'custom-table', ], + 'custom_index_fields_table' => [ + 'variables' => [ + 'header' => [], + 'rows' => [], + 'attributes' => [], + ], + 'template' => 'custom-index-fields-table', + ], + 'custom_index_table' => [ + 'variables' => [ + 'header' => [], + 'rows' => [], + 'attributes' => [], + ], + 'template' => 'custom-index-table', + ], ]; } @@ -96,21 +112,44 @@ function data_dictionary_widget_form_alter(&$form, &$form_state, $form_id) { } $form['#validate'][] = 'data_dictionary_widget_validate_unique_identifier'; - $current_fields = !empty($form["field_json_metadata"]["widget"][0]["dictionary_fields"]["current_fields"]) ? $form["field_json_metadata"]["widget"][0]["dictionary_fields"]["current_fields"] : NULL; + $current_dictionary_fields = !empty($form["field_json_metadata"]["widget"][0]["dictionary_fields"]["current_dictionary_fields"]) ? $form["field_json_metadata"]["widget"][0]["dictionary_fields"]["current_dictionary_fields"] : NULL; + $current_index_fields = !empty($form["field_json_metadata"]["widget"][0]["indexes"]["current_index"]) ? $form["field_json_metadata"]["widget"][0]["indexes"]["current_index"] : NULL; // The form element render array prefers child keys to be stored as arrays with a #value property. - if ($current_fields) { - foreach ($current_fields as $key => $value) { - $keys = array_keys($value); - $formatted_current_fields[$key] = []; - - foreach ($keys as $attr) { - $formatted_current_fields[$key][$attr] = [ - '#value' => $value[$attr] - ]; + if ($current_dictionary_fields) { + foreach ($current_dictionary_fields as $key => $value) { + $keys = array_keys($value); + $formatted_current_fields[$key] = []; + + foreach ($keys as $attr) { + $formatted_current_fields[$key][$attr] = [ + '#value' => $value[$attr] + ]; + } + } + + $form["field_json_metadata"]["widget"][0]["dictionary_fields"]["current_dictionary_fields"] = $formatted_current_fields; + } + + // The form element render array prefers child keys to be stored as arrays with a #value property. + if ($current_index_fields) { + foreach ($current_index_fields as &$item) { + foreach ($item as $key => &$value) { + if ($key === 'fields' && is_array($value)) { + foreach ($value as &$field) { + foreach ($field as $fieldKey => &$fieldValue) { + // Add '#value' key to each field + $fieldValue = ['#value' => $fieldValue]; + } + } + } else { + // For non-'fields' keys, add '#value' key to the value + $value = ['#value' => $value]; } + } } - $form["field_json_metadata"]["widget"][0]["dictionary_fields"]["current_fields"] = $formatted_current_fields; + + $form["field_json_metadata"]["widget"][0]["indexes"]["current_index"] = $current_index_fields; } // Set the default value of the identifier field to a randomly generated uuid. diff --git a/modules/data_dictionary_widget/src/Fields/FieldCallbacks.php b/modules/data_dictionary_widget/src/Fields/FieldCallbacks.php index a22bf5f1fe..1d608a7860 100644 --- a/modules/data_dictionary_widget/src/Fields/FieldCallbacks.php +++ b/modules/data_dictionary_widget/src/Fields/FieldCallbacks.php @@ -39,37 +39,58 @@ public static function updateFormatOptions(array &$form, FormStateInterface $for * Submit callback for the Edit button. */ public static function editSubformCallback(array &$form, FormStateInterface $form_state) { - $current_fields = $form["field_json_metadata"]["widget"][0]["dictionary_fields"]["data"]["#rows"]; + // Get the current fields data + $current_dictionary_fields = $form["field_json_metadata"]["widget"][0]["dictionary_fields"]["data"]["#rows"]; + $current_index_fields = $form["field_json_metadata"]["widget"][0]["indexes"]["fields"]["data"]["#rows"]; + // Get the field index from the triggering op attribute + // so we can use it to store the respective field later $op_index = explode("_", $form_state->getTriggeringElement()['#op']); - $currently_modifying = $form_state->get('fields_being_modified') != NULL ? $form_state->get('fields_being_modified') : []; - + // Get the fields we're currently modifying + $dictionary_fields_being_modified = $form_state->get('dictionary_fields_being_modified') != NULL ? $form_state->get('dictionary_fields_being_modified') : []; + $index_fields_being_modified = $form_state->get('index_fields_being_modified') != NULL ? $form_state->get('index_fields_being_modified') : []; + // If the op (trigger) containes abort, + // we're canceling the field we're currently modifying so unset it. if (str_contains($form_state->getTriggeringElement()['#op'], 'abort')) { - unset($currently_modifying[$op_index[1]]); + unset($dictionary_fields_being_modified[$op_index[1]]); } - + // If the op (trigger) contains delete, + // we're deleting the field we're editing so... if (str_contains($form_state->getTriggeringElement()['#op'], 'delete')) { - unset($currently_modifying[$op_index[1]]); - unset($current_fields[$op_index[1]]); + // Unset it from being currently modified. + unset($dictionary_fields_being_modified[$op_index[1]]); + // Remove the respective field/data from the form. + unset($current_dictionary_fields[$op_index[1]]); } - + // If the op (trigger) contains update, + // We're saving the field we're editing so... if (str_contains($form_state->getTriggeringElement()['#op'], 'update')) { - unset($currently_modifying[$op_index[1]]); - unset($current_fields[$op_index[1]]); - $current_fields[$op_index[1]] = FieldValues::updateValues($op_index[1], $form_state->getUserInput(), $current_fields); - ksort($current_fields); + // Unset the respective currently modifying field. + unset($dictionary_fields_being_modified[$op_index[1]]); + // Unset the respective field/data from the form. + unset($current_dictionary_fields[$op_index[1]]); + // Update the respective current field data with our new input data. + $current_dictionary_fields[$op_index[1]] = FieldValues::updateValues($op_index[1], $form_state->getUserInput(), $current_dictionary_fields); + // Sort the current fields data. + ksort($current_dictionary_fields); } - + // If the op (trigger) contains edit + // We're editing a specific field so... if (str_contains($form_state->getTriggeringElement()['#op'], 'edit')) { - $currently_modifying[$op_index[1]] = $current_fields[$op_index[1]]; + // Set the field we're modifying to that field. + $dictionary_fields_being_modified[$op_index[1]] = $current_dictionary_fields[$op_index[1]]; } - - // Re-index the current_fields array. - if ($current_fields) { - $current_fields = array_values($current_fields); + // Reindex the current_dictionary_fields array. + if ($current_dictionary_fields) { + $current_dictionary_fields = array_values($current_dictionary_fields); } - - $form_state->set('fields_being_modified', $currently_modifying); - $form_state->set('current_fields', $current_fields); + // Let's retain the fields that are being modified. + $form_state->set('index_fields_being_modified', $index_fields_being_modified); + $form_state->set('dictionary_fields_being_modified', $dictionary_fields_being_modified); + // Let's retain the fields that are already stored on the form, + // but aren't currently being modified. + $form_state->set('current_dictionary_fields', $current_dictionary_fields); + $form_state->set('current_index_fields', $current_index_fields ); + // Let's rebuild the form. $form_state->setRebuild(); } @@ -80,9 +101,12 @@ public static function addSubformCallback(array &$form, FormStateInterface $form $trigger = $form_state->getTriggeringElement(); $op = $trigger['#op']; $form_state->set('add_new_field', ''); - $current_fields = $form["field_json_metadata"]["widget"][0]["dictionary_fields"]["data"]["#rows"]; - if ($current_fields) { - $form_state->set('current_fields', $current_fields); + $current_dictionary_fields = $form["field_json_metadata"]["widget"][0]["dictionary_fields"]["data"]["#rows"]; + $current_index = $form["field_json_metadata"]["widget"][0]['indexes']["data"]["#rows"]; + $current_index_fields = $form["field_json_metadata"]["widget"][0]['indexes']["fields"]["data"]["#rows"]; + + if ($current_dictionary_fields) { + $form_state->set('current_dictionary_fields', $current_dictionary_fields); } if ($op === 'cancel') { @@ -95,11 +119,12 @@ public static function addSubformCallback(array &$form, FormStateInterface $form } if ($op === 'add') { - $form_state->set('new_fields', $form_state->getUserInput()); + $form_state->set('new_dictionary_fields', $form_state->getUserInput()); $form_state->set('add', TRUE); $form_state->set('cancel', FALSE); } - + $form_state->set('current_index_fields', $current_index_fields); + $form_state->set('current_index', $current_index); $form_state->setRebuild(); } diff --git a/modules/data_dictionary_widget/src/Fields/FieldCreation.php b/modules/data_dictionary_widget/src/Fields/FieldCreation.php index 14113aa497..2805d44f11 100644 --- a/modules/data_dictionary_widget/src/Fields/FieldCreation.php +++ b/modules/data_dictionary_widget/src/Fields/FieldCreation.php @@ -12,10 +12,8 @@ class FieldCreation { /** * Create basic widget. */ - public static function createGeneralFields($element, $field_json_metadata, $current_fields, $form_state) { - + public static function createGeneralFields($element, $field_json_metadata, $current_dictionary_fields, $form_state) { $element['identifier'] = self::createField('identifier', $field_json_metadata, $form_state); - $element['title'] = self::createField('title', $field_json_metadata, $form_state); $element['dictionary_fields'] = [ @@ -25,8 +23,7 @@ public static function createGeneralFields($element, $field_json_metadata, $curr '#suffix' => '', '#markup' => t('
A data dictionary for this resource, compliant with the Table Schema specification.
'), ]; - - $element['dictionary_fields']['current_fields'] = $current_fields; + $element['dictionary_fields']['current_dictionary_fields'] = $current_dictionary_fields; if (isset($field_json_metadata['data']['indexes'])) { $element['indexes'] = self::createField('indexes', $field_json_metadata, $form_state); @@ -84,13 +81,13 @@ protected static function createField(string $field, array $field_json_metadata, /** * Create data dictionary data rows. */ - public static function createDictionaryDataRows($current_fields, $data_results, $form_state) { + public static function createDictionaryDataRows($current_dictionary_fields, $data_results, $form_state) { return [ - '#access' => ((bool) $current_fields || (bool) $data_results), + '#access' => ((bool) $current_dictionary_fields || (bool) $data_results), '#type' => 'table', '#header' => ['NAME', 'TITLE', 'DETAILS'], - '#rows' => $form_state->get('cancel') ? $current_fields : ($data_results ?? []), + '#rows' => $form_state->get('cancel') ? $current_dictionary_fields : ($data_results ?? []), '#tree' => TRUE, '#theme' => 'custom_table', ]; diff --git a/modules/data_dictionary_widget/src/Fields/FieldEditCreation.php b/modules/data_dictionary_widget/src/Fields/FieldEditCreation.php index 78fee533bc..b20e6927f0 100644 --- a/modules/data_dictionary_widget/src/Fields/FieldEditCreation.php +++ b/modules/data_dictionary_widget/src/Fields/FieldEditCreation.php @@ -10,12 +10,12 @@ class FieldEditCreation { /** * Create edit fields for Data Dictionary Widget. */ - public static function editFields($key, $current_fields) { + public static function editFields($key, $current_dictionary_fields) { $edit_fields['name'] = [ '#name' => 'field_json_metadata[0][dictionary_fields][data][' . $key . '][field_collection][name]', '#type' => 'textfield', - '#value' => $current_fields[$key]['name'], + '#value' => $current_dictionary_fields[$key]['name'], '#required' => TRUE, '#title' => 'Name', '#description' => t('Machine name of the field/column in the data table.'), @@ -23,15 +23,15 @@ public static function editFields($key, $current_fields) { $edit_fields['title'] = [ '#name' => 'field_json_metadata[0][dictionary_fields][data][' . $key . '][field_collection][title]', '#type' => 'textfield', - '#value' => $current_fields[$key]['title'], + '#value' => $current_dictionary_fields[$key]['title'], '#required' => TRUE, '#title' => 'Title', '#description' => t('A human-readable title.'), ]; - $edit_fields['type'] = self::createType($key, $current_fields); - $edit_fields['format'] = self::createFormat($key, $current_fields); - $edit_fields['format_other'] = self::createFormatOther($key, $current_fields); - $edit_fields['description'] = self::createDescriptionField($key, $current_fields); + $edit_fields['type'] = self::createType($key, $current_dictionary_fields); + $edit_fields['format'] = self::createFormat($key, $current_dictionary_fields); + $edit_fields['format_other'] = self::createFormatOther($key, $current_dictionary_fields); + $edit_fields['description'] = self::createDescriptionField($key, $current_dictionary_fields); $edit_fields['update_field']['actions'] = self::createActionFields($key); return $edit_fields; @@ -41,14 +41,14 @@ public static function editFields($key, $current_fields) { /** * Create Type field. */ - private static function createType($key, $current_fields) { + private static function createType($key, $current_dictionary_fields) { return [ '#name' => 'field_json_metadata[0][dictionary_fields][data][' . $key . '][field_collection][type]', '#type' => 'select', '#required' => TRUE, '#title' => 'Data type', '#default_value' => 'string', - '#value' => $current_fields[$key]['type'], + '#value' => $current_dictionary_fields[$key]['type'], '#op' => 'format_' . $key, '#options' => FieldOperations::setTypeOptions(), '#ajax' => [ @@ -62,16 +62,16 @@ private static function createType($key, $current_fields) { /** * Create Format field. */ - private static function createFormat($key, $current_fields) { - $format_options = FieldOperations::generateFormats($current_fields[$key]['type'], "options"); - $value = in_array($current_fields[$key]['format'], $format_options, TRUE) ? $current_fields[$key]['format'] : 'other'; + private static function createFormat($key, $current_dictionary_fields) { + $format_options = FieldOperations::generateFormats($current_dictionary_fields[$key]['type'], "options"); + $value = in_array($current_dictionary_fields[$key]['format'], $format_options) ? $current_dictionary_fields[$key]['format'] : 'other'; return [ '#name' => 'field_json_metadata[0][dictionary_fields][data][' . $key . '][field_collection][format]', '#type' => 'select', '#required' => TRUE, '#title' => 'Format', '#default_value' => 'default', - '#description' => FieldOperations::generateFormats($current_fields[$key]['type'], "description"), + '#description' => FieldOperations::generateFormats($current_dictionary_fields[$key]['type'], "description"), '#value' => $value, '#prefix' => '
', '#suffix' => '
', @@ -83,9 +83,9 @@ private static function createFormat($key, $current_fields) { /** * Create Format Other field. */ - private static function createFormatOther($key, $current_fields) { - $format_options = FieldOperations::generateFormats($current_fields[$key]['type'], "options"); - $value = !in_array($current_fields[$key]['format'], $format_options) ? $current_fields[$key]['format'] : NULL; + private static function createFormatOther($key, $current_dictionary_fields) { + $format_options = FieldOperations::generateFormats($current_dictionary_fields[$key]['type'], "options"); + $value = !in_array($current_dictionary_fields[$key]['format'], $format_options) ? $current_dictionary_fields[$key]['format'] : NULL; return [ '#name' => 'field_json_metadata[0][dictionary_fields][data][' . $key . '][field_collection][format_other]', @@ -119,11 +119,11 @@ private static function createActionFields($key) { /** * Create Description field. */ - private static function createDescriptionField($key, $current_fields) { + private static function createDescriptionField($key, $current_dictionary_fields) { return [ '#name' => 'field_json_metadata[0][dictionary_fields][data][' . $key . '][field_collection][description]', '#type' => 'textfield', - '#value' => $current_fields[$key]['description'], + '#value' => $current_dictionary_fields[$key]['description'], '#required' => TRUE, '#title' => 'Description', '#description' => t('Information about the field data.'), diff --git a/modules/data_dictionary_widget/src/Fields/FieldOperations.php b/modules/data_dictionary_widget/src/Fields/FieldOperations.php index f084842636..523f296a63 100644 --- a/modules/data_dictionary_widget/src/Fields/FieldOperations.php +++ b/modules/data_dictionary_widget/src/Fields/FieldOperations.php @@ -211,7 +211,7 @@ public static function setAddFormState($add_new_field, $element) { * Create edit and update fields where needed. */ public static function createDictionaryFieldOptions($op_index, $data_results, $fields_being_modified, $element) { - $current_fields = $element['current_fields']; + $current_fields = $element['current_dictionary_fields']; // Creating ajax buttons/fields to be placed in correct location later. foreach ($data_results as $key => $data) { if (self::checkEditingField($key, $op_index, $fields_being_modified)) { @@ -367,4 +367,4 @@ public static function resetFieldValues(array &$form, FormStateInterface $form_s } } -} +} \ No newline at end of file diff --git a/modules/data_dictionary_widget/src/Fields/FieldValues.php b/modules/data_dictionary_widget/src/Fields/FieldValues.php index f3207c12de..1122733966 100644 --- a/modules/data_dictionary_widget/src/Fields/FieldValues.php +++ b/modules/data_dictionary_widget/src/Fields/FieldValues.php @@ -10,7 +10,7 @@ class FieldValues { /** * Return updated field values after edit. */ - public static function updateValues($field_index, $update_values, $current_fields) { + public static function updateValues($field_index, $update_values, $current_dictionary_fields) { $format = $update_values['field_json_metadata'][0]['dictionary_fields']['data'][$field_index]['field_collection']['format']; $format_other = $update_values['field_json_metadata'][0]['dictionary_fields']['data'][$field_index]['field_collection']['format_other']; $name = $update_values['field_json_metadata'][0]['dictionary_fields']['data'][$field_index]['field_collection']['name']; diff --git a/modules/data_dictionary_widget/src/Indexes/IndexAddCreation.php b/modules/data_dictionary_widget/src/Indexes/IndexAddCreation.php new file mode 100644 index 0000000000..631486af71 --- /dev/null +++ b/modules/data_dictionary_widget/src/Indexes/IndexAddCreation.php @@ -0,0 +1,117 @@ + 'fieldset', + '#title' => t('Index'), + '#open' => TRUE, + '#prefix' => '
', + '#suffix' => '
', + '#element_validate' => [ + ['\Drupal\data_dictionary_widget\Indexes\IndexValidation', 'indexFieldsValidation'] + ], + ]; + + $add_index['group']['index']['description'] = [ + '#name' => 'field_json_metadata[0][indexes][field_collection][group][index][description]', + '#description' => t('Description of index purpose or functionality.'), + '#type' => 'textfield', + '#title' => 'Name', + '#required' => TRUE, + ]; + + $add_index['group']['index']['type'] = [ + '#name' => 'field_json_metadata[0][indexes][field_collection][group][index][type]', + '#type' => 'select', + '#description' => t('Index type.'), + '#title' => 'Index Type', + '#default_value' => 'index', + '#op' => 'index_type', + '#required' => TRUE, + '#options' => [ + 'index' => t('index'), + 'fulltext' => t('fulltext'), + ], + ]; + + $add_index['group']['index']['fields'] = [ + '#type' => 'fieldset', + '#title' => t('Fields'), + '#required' => TRUE, + '#prefix' => '
', + '#suffix' => '
', + '#markup' => t('
One or more fields included in index. Must be keys from the fields object.
'), + '#attributes' => [ + 'class' => ['index-fields-form'], + ], + ]; + + $add_index['group']['index']['fields']['add_row_button'] = IndexButtons::addIndexFieldButton(); + + $add_index['group']['index']['save_index'] = IndexButtons::submitIndexButton('add_index', NULL); + $add_index['group']['index']['cancel_index'] = IndexButtons::cancelIndexButton('cancel_index', NULL); + + return $add_index; + } + + /** + * Create add fields for Data Dictionary Widget. + */ + public static function addIndexFields($current_index_fields) { + $id = $current_index_fields ? "field-json-metadata-dictionary-index-fields-new" : "field-json-metadata-dictionary-index-fields"; + $add_index_fields['#access'] = FALSE; + $add_index_fields['group'] = [ + '#type' => 'fieldset', + '#title' => t('Add new field'), + '#prefix' => "
", + '#suffix' => '
', + '#markup' => t('
Add a single index field. Must be keys from the fields object.
'), + ]; + + $add_index_fields['group']['index']['fields']['name'] = [ + '#name' => 'field_json_metadata[0][indexes][fields][field_collection][group][index][fields][name]', + '#type' => 'textfield', + '#title' => 'Name', + '#required' => TRUE, + ]; + + $add_index_fields['group']['index']['fields']['length'] = self::createIndexFieldLengthField(); + $add_index_fields['group']['index']['fields']['actions'] = self::createIndexActionFields($id); + + return $add_index_fields; + } + + /** + * Create Description field. + */ + private static function createIndexFieldLengthField() { + return [ + '#name' => 'field_json_metadata[0][indexes][fields][field_collection][group][index][fields][length]', + '#type' => 'number', + '#title' => 'Length', + '#required' => TRUE, + ]; + } + + /** + * Create Action buttons. + */ + private static function createIndexActionFields($id) { + return [ + '#type' => 'actions', + 'save_index_settings' => IndexButtons::submitIndexFieldButton('add', NULL), + 'cancel_index_settings' => IndexButtons::cancelIndexFieldButton('cancel', NULL, $id), + ]; + } +} \ No newline at end of file diff --git a/modules/data_dictionary_widget/src/Indexes/IndexButtons.php b/modules/data_dictionary_widget/src/Indexes/IndexButtons.php new file mode 100644 index 0000000000..9e701cf2e2 --- /dev/null +++ b/modules/data_dictionary_widget/src/Indexes/IndexButtons.php @@ -0,0 +1,302 @@ + 'submit', + '#value' => 'Add field', + '#access' => TRUE, + '#op' => 'add_new_index_field', + '#submit' => [ + [ + '\Drupal\data_dictionary_widget\Indexes\IndexCallbacks', + 'indexFieldAddSubformCallback', + ], + ], + '#ajax' => [ + 'callback' => '\Drupal\data_dictionary_widget\Indexes\IndexCallbacks::subIndexFormAjax', + 'wrapper' => 'field-json-metadata-dictionary-index-fields', + 'effect' => 'fade', + ], + '#limit_validation_errors' => [], + ]; + } + + /** + * Returns the add index button. + */ + public static function addIndexButton() { + return [ + '#type' => 'submit', + '#value' => 'Add index', + '#access' => TRUE, + '#op' => 'add_new_index', + '#submit' => [ + [ + '\Drupal\data_dictionary_widget\Indexes\IndexCallbacks', + 'indexAddCallback', + ], + ], + '#ajax' => [ + 'callback' => '\Drupal\data_dictionary_widget\Indexes\IndexCallbacks::indexFormAjax', + 'wrapper' => 'field-json-metadata-dictionary-indexes', + 'effect' => 'fade', + ], + '#limit_validation_errors' => [], + ]; + } + + /** + * Returns the edit buttons. + */ + public static function editIndexButtons($indexKey) { + return [ + '#type' => 'image_button', + '#name' => 'edit_index_' . $indexKey, + '#id' => 'edit_index_' . $indexKey, + '#access' => TRUE, + '#op' => 'edit_' . $indexKey, + '#src' => 'core/misc/icons/787878/cog.svg', + '#attributes' => [ + 'class' => ['index-field-plugin-settings-edit'], + 'alt' => t('Edit index'), + ], + '#submit' => [ + [ + '\Drupal\data_dictionary_widget\Indexes\IndexCallbacks', + 'indexEditSubformCallback', + ], + ], + '#ajax' => [ + 'callback' => '\Drupal\data_dictionary_widget\Indexes\IndexCallbacks::subIndexFormAjax', + 'wrapper' => 'field-json-metadata-dictionary-index-fields', + 'effect' => 'fade', + ], + '#limit_validation_errors' => [ + ['field_json_metadata', 0, 'indexes', 'field_collection', 'group', 'index', 'type'], + ], + ]; + } + + /** + * Returns the edit Index Field Buttons. + */ + public static function editIndexFieldButtons($indexFieldKey) { + return [ + '#type' => 'image_button', + // '#name' => 'edit_index_field' . $indexKey . '_' . $indexFieldKey, + // '#id' => 'edit_index_field' . $indexKey . '_' . $indexFieldKey, + // '#access' => TRUE, + // '#op' => 'index_field_edit_' . $indexKey . '_' . $indexFieldKey, + '#name' => 'edit_index_field' . $indexFieldKey, + '#id' => 'edit_index_field' . $indexFieldKey, + '#access' => TRUE, + '#op' => 'index_field_edit_' . $indexFieldKey, + '#src' => 'core/misc/icons/787878/cog.svg', + '#attributes' => [ + 'class' => ['index-field-plugin-settings-edit'], + 'alt' => t('Edit index field'), + ], + '#submit' => [ + [ + '\Drupal\data_dictionary_widget\Indexes\IndexCallbacks', + 'indexFieldEditSubformCallback', + ], + ], + '#ajax' => [ + 'callback' => '\Drupal\data_dictionary_widget\Indexes\IndexCallbacks::subIndexformAjax', + 'wrapper' => 'field-json-metadata-dictionary-index-fields', + 'effect' => 'fade', + ], + '#limit_validation_errors' => [], + ]; + } + + /** + * Create Submit buttons. + */ + public static function submitIndexFieldButton($location, $indexFieldKey) { + $callbackClass = $location == 'edit' ? 'indexEditSubformCallback' : 'indexAddSubformCallback'; + $op = !empty($indexFieldKey) ? 'update_' . $indexFieldKey : 'add_index_field'; + $value = $location == 'edit' ? 'Save' : 'Add '; + $edit_index_field_button = [ + '#type' => 'submit', + '#value' => $value, + '#op' => $op, + '#submit' => [ + [ + '\Drupal\data_dictionary_widget\Indexes\IndexCallbacks', + $callbackClass, + ], + ], + '#ajax' => [ + 'callback' => 'Drupal\data_dictionary_widget\Indexes\IndexCallbacks::subIndexFormAjax', + 'wrapper' => 'field-json-metadata-dictionary-index-fields', + 'effect' => 'fade', + ], + '#limit_validation_errors' => [ + ['field_json_metadata', 0, 'indexes', 'fields', 'field_collection', 'group', 'index', 'fields', 'name'], + ['field_json_metadata', 0, 'indexes', 'fields', 'field_collection', 'group', 'index', 'fields', 'length'], + ], + ]; + + if ($location == 'edit') { + $edit_index_button['#name'] = 'update_' . $indexFieldKey; + } + return $edit_index__field_button; + } + + /** + * Create Submit buttons. + */ + public static function submitIndexButton($location, $indexKey) { + $class = static::class; + $callbackClass = $location == 'edit' ? 'indexEditCallback' : 'indexAddCallback'; + $op = !empty($indexKey) ? 'update_' . $indexKey : 'add_index'; + $value = $location == 'edit' ? 'Save' : 'Submit Index'; + $edit_index_button = [ + '#type' => 'submit', + '#value' => $value, + '#op' => $op, + '#submit' => [ + [ + '\Drupal\data_dictionary_widget\Indexes\IndexCallbacks', + $callbackClass, + ], + ], + '#ajax' => [ + 'callback' => 'Drupal\data_dictionary_widget\Indexes\IndexCallbacks::indexFormAjax', + 'wrapper' => 'field-json-metadata-dictionary-indexes', + 'effect' => 'fade', + ], + '#limit_validation_errors' => [ + ['field_json_metadata', 0, 'indexes', 'field_collection', 'group', 'index', 'description'], + ['field_json_metadata', 0, 'indexes', 'field_collection', 'group', 'index', 'fields'], + ], + ]; + + if ($location == 'edit') { + $edit_index_button['#name'] = 'update_' . $indexKey; + } + return $edit_index_button; + } + + /** + * Create Cancel button. + */ + public static function cancelIndexFieldButton($location, $indexFieldKey, $id) { + $callbackId = ($id === 'field-json-metadata-dictionary-index-fields-new') ? 'subIndexFormExistingFieldAjax' : 'subIndexFormFieldAjax'; + $callbackClass = $location == 'edit' ? 'indexFieldEditSubformCallback' : 'indexFieldAddSubformCallback'; + $op = $location == 'edit' && $indexFieldKey ? 'abort_' . $indexFieldKey : 'cancel_index_field'; + $cancel_index_button = [ + '#type' => 'submit', + '#value' => t('Cancel'), + '#op' => $op, + '#submit' => [ + [ + '\Drupal\data_dictionary_widget\Indexes\IndexCallbacks', + $callbackClass, + ], + ], + '#ajax' => [ + 'callback' => "Drupal\data_dictionary_widget\Indexes\IndexCallbacks::$callbackId", + 'wrapper' => $id, + 'effect' => 'fade', + ], + '#limit_validation_errors' => [], + ]; + + if ($location == 'edit') { + $cancel_index_button['#name'] = 'cancel_update_' . $indexFieldKey; + } + return $cancel_index_button; + } + + /** + * Create Cancel button. + */ + public static function cancelIndexButton($location, $indexKey) { + $callbackClass = $location == 'edit' ? 'indexEditCallback' : 'indexAddCallback'; + $op = $location == 'edit' && $indexKey ? 'abort_' . $indexKey : 'cancel_index'; + $cancel_index_button = [ + '#type' => 'submit', + '#value' => t('Cancel Index'), + '#op' => $op, + '#submit' => [ + [ + '\Drupal\data_dictionary_widget\Indexes\IndexCallbacks', + $callbackClass, + ], + ], + '#ajax' => [ + 'callback' => 'Drupal\data_dictionary_widget\Indexes\IndexCallbacks::indexFormAjax', + 'wrapper' => 'field-json-metadata-dictionary-indexes', + 'effect' => 'fade', + ], + '#limit_validation_errors' => [], + ]; + + if ($location == 'edit') { + $cancel_index_button['#name'] = 'cancel_update_' . $indexKey; + } + return $cancel_index_button; + } + + /** + * Create Delete button. + */ + public static function deleteIndexButton($indexKey) { + return [ + '#type' => 'submit', + '#name' => 'index_delete_' . $indexKey, + '#value' => t('Delete index field'), + '#op' => 'delete_' . $indexKey, + '#submit' => [ + [ + '\Drupal\data_dictionary_widget\Indexes\IndexCallbacks', + 'indexEditSubformCallback', + ], + ], + '#ajax' => [ + 'callback' => 'Drupal\data_dictionary_widget\Indexes\IndexCallbacks::subIndexFormAjax', + 'wrapper' => 'field-json-metadata-dictionary-index-fields', + 'effect' => 'fade', + ], + '#limit_validation_errors' => [], + ]; + } + + /** + * Create Delete Index Field button. + */ + public static function deleteIndexFieldButton($indexFieldKey) { + return [ + '#type' => 'submit', + '#name' => 'index_delete_' . $indexFieldKey, + '#value' => t('Delete index field'), + '#op' => 'delete_' . $indexFieldKey, + '#submit' => [ + [ + '\Drupal\data_dictionary_widget\Indexes\IndexCallbacks', + 'indexFieldEditSubformCallback', + ], + ], + '#ajax' => [ + 'callback' => 'Drupal\data_dictionary_widget\Indexes\IndexCallbacks::subIndexformAjax', + 'wrapper' => 'field-json-metadata-dictionary-index-fields', + 'effect' => 'fade', + ], + '#limit_validation_errors' => [], + ]; + } +} \ No newline at end of file diff --git a/modules/data_dictionary_widget/src/Indexes/IndexCallbacks.php b/modules/data_dictionary_widget/src/Indexes/IndexCallbacks.php new file mode 100644 index 0000000000..5ef0ec2c14 --- /dev/null +++ b/modules/data_dictionary_widget/src/Indexes/IndexCallbacks.php @@ -0,0 +1,218 @@ +getTriggeringElement(); + $op = $trigger['#op']; + $current_dictionary_fields = $form["field_json_metadata"]["widget"][0]["dictionary_fields"]["data"]["#rows"]; + $current_index = $form["field_json_metadata"]["widget"][0]['indexes']["data"]["#rows"]; + $current_index_fields = $form["field_json_metadata"]["widget"][0]['indexes']["fields"]["data"]["#rows"]; + + if ($current_index_fields) { + $form_state->set('current_index_fields', $current_index_fields); + } + + if ($op === 'cancel_index_field') { + $form_state->set('cancel_index_field', TRUE); + } + + if ($op === 'add_new_index_field') { + $form_state->set('add_index_field', ''); + $add_index_fields = IndexAddCreation::addIndexFields($current_index_fields); + $form_state->set('add_new_index_field', $add_index_fields); + $form_state->set('index_added', FALSE); + $form_state->set('adding_new_index_fields', TRUE); + } + + if ($op === 'add_index_field') { + $form_state->set('add_new_index_field', ''); + $form_state->set('new_index_fields', $form_state->getUserInput()); + $form_state->set('add', TRUE); + $form_state->set('cancel_index_field', FALSE); + $form_state->set('adding_new_index_fields', FALSE); + } + + $form_state->set('current_dictionary_fields', $current_dictionary_fields); + $form_state->set('current_index', $current_index); + $form_state->set('current_index_fields', $current_index_fields); + $form_state->setRebuild(); + } + + /** + * Submit callback for the Index Add button. + */ + public static function indexAddCallback(array &$form, FormStateInterface $form_state) { + $trigger = $form_state->getTriggeringElement(); + $op = $trigger['#op']; + $current_dictionary_fields = $form["field_json_metadata"]["widget"][0]["dictionary_fields"]["data"]["#rows"]; + $form_state->set('add_new_index_field', ''); + $form_state->set('new_index_fields', ''); + $form_state->set('add_new_index', ''); + $form_state->set('adding_new_index_fields', FALSE); + $current_index = $form["field_json_metadata"]["widget"][0]["indexes"]["data"]["#rows"]; + $current_index_fields = $form["field_json_metadata"]["widget"][0]['indexes']["fields"]["data"]["#rows"] ?? NULL; + + if ($current_index) { + $form_state->set('current_index', $current_index); + } + + if ($op === 'cancel_index') { + $form_state->set('cancel_index', TRUE); + } + + if ($op === 'add_new_index') { + $add_new_index = IndexAddCreation::addIndex(); + $form_state->set('new_index', ''); + $form_state->set('add_new_index', $add_new_index); + } + + if ($op === 'add_index') { + $form_state->set('add_new_index', ''); + $form_state->set('new_index', $form_state->getUserInput()); + $form_state->set('add', TRUE); + $form_state->set('index_added', TRUE); + $form_state->set('cancel_index', FALSE); + } + + $form_state->set('current_dictionary_fields', $current_dictionary_fields); + $form_state->set('current_index', $current_index); + $form_state->set('current_index_fields', $current_index_fields); + $form_state->setRebuild(); + } + + /** + * Submit callback for the Index Edit button. + */ + public static function indexEditSubformCallback(array &$form, FormStateInterface $form_state) { + $trigger = $form_state->getTriggeringElement(); + $current_index_fields = $form["field_json_metadata"]["widget"][0]["indexes"]["fields"]["data"]["#rows"]; + $current_dictionary_fields = $form["field_json_metadata"]["widget"][0]["dictionary_fields"]["data"]["#rows"]; + $op = $trigger['#op']; + $op_index = explode("_", $trigger['#op']); + $currently_modifying_index_fields = $form_state->get('index_fields_being_modified') != NULL ? $form_state->get('index_fields_being_modified') : []; + $currently_modifying = $form_state->get('dictionary_fields_being_modified') != NULL ? $form_state->get('dictionary_fields_being_modified') : []; + + if (str_contains($op, 'abort')) { + unset($currently_modifying_index_fields[$op_index[4]]); + } + + if (str_contains($op, 'delete')) { + unset($currently_modifying_index_fields[$op_index[4]]); + unset($current_index_fields[$op_index[4]]); + } + + if (str_contains($op, 'update')) { + $update_values = $form_state->getUserInput(); + unset($currently_modifying_index_fields[$op_index[4]]); + unset($current_index_fields[$op_index[4]]); + $current_index_fields[$op_index[4]] = IndexValues::updateIndexFieldValues($op_index[4], $update_values, $current_index_fields ); + ksort($current_index_fields ); + } + + if (str_contains($op, 'edit')) { + $currently_modifying_index_fields[$op_index[4]] = $current_index_fields[$op_index[4]]; + } + + $form_state->set('dictionary_fields_being_modified', $currently_modifying); + $form_state->set('index_fields_being_modified', $currently_modifying_index_fields); + $form_state->set('current_index_fields', $current_index_fields ); + $form_state->set('current_dictionary_fields', $current_dictionary_fields ); + $form_state->setRebuild(); + } + + /** + * Submit callback for the Index Field Edit button. + */ + public static function indexFieldEditSubformCallback(array &$form, FormStateInterface $form_state) { + // What button was clicked? + $trigger = $form_state->getTriggeringElement(); + // Set the 'operation' of the actioned button to a var + $op = $trigger['#op']; + // Get the portion of the operation string that's relevent + // so we can action on it + $op_index = explode("_", $trigger['#op']); + // Get our current (soft saved) data on the form for each main element + $current_index_fields = $form["field_json_metadata"]["widget"][0]["indexes"]["fields"]["data"]["#rows"]; + $current_dictionary_fields = $form["field_json_metadata"]["widget"][0]["dictionary_fields"]["data"]["#rows"]; + // Get the data that we're currently modifying (temporary) + // This differs from the current fields in that + // this is the data we are immediately editing + $currently_modifying = $form_state->get('dictionary_fields_being_modified') != NULL ? $form_state->get('dictionary_fields_being_modified') : []; + $currently_modifying_index_fields = $form_state->get('index_fields_being_modified') != NULL ? $form_state->get('index_fields_being_modified') : []; + + + if (str_contains($op, 'abort')) { + unset($currently_modifying_index_fields[$op_index[4]]); + } + + if (str_contains($op, 'delete')) { + unset($currently_modifying_index_fields[$op_index[4]]); + unset($current_index_fields[$op_index[4]]); + } + + if (str_contains($op, 'update')) { + $update_values = $form_state->getUserInput(); + unset($currently_modifying_index_fields[$op_index[4]]); + unset($current_index_fields[$op_index[4]]); + $current_index_fields[$op_index[4]] = IndexValues::updateIndexFieldValues($op_index[4], $update_values, $current_index_fields ); + ksort($current_index_fields ); + } + + if (str_contains($op, 'edit')) { + $currently_modifying_index_fields[$op_index[4]] = $current_index_fields[$op_index[4]]; + } + + $form_state->set('dictionary_fields_being_modified', $currently_modifying); + $form_state->set('index_fields_being_modified', $currently_modifying_index_fields); + $form_state->set('current_index_fields', $current_index_fields ); + $form_state->set('current_dictionary_fields', $current_dictionary_fields ); + $form_state->setRebuild(); + } + + /** + * Ajax callback to return index fields. + */ + public static function subIndexFormAjax(array &$form, FormStateInterface $form_state) { + return $form["field_json_metadata"]["widget"][0]["indexes"]["fields"]; + } + + /** + * Ajax callback to return indexes. + */ + public static function indexFormAjax(array &$form, FormStateInterface $form_state) { + $index_fields = $form["field_json_metadata"]["widget"][0]["indexes"]["fields"]; + + // Validation errors skip submit callbacks, this will set the index fields in the correct location. + if ($index_fields["data"]) { + $form["field_json_metadata"]["widget"][0]["indexes"]["field_collection"]["group"]["index"]["fields"] = $index_fields; + $form["field_json_metadata"]["widget"][0]["indexes"]["fields"]['#access'] = FALSE; + } + + return $form["field_json_metadata"]["widget"][0]["indexes"]; + } + + /** + * Ajax callback to return index fields fieldset with Add Field button. + */ + public static function subIndexFormFieldAjax(array &$form, FormStateInterface $form_state) { + return $form["field_json_metadata"]["widget"][0]["indexes"]["field_collection"]["group"]["index"]["fields"]; + } + + /** + * Ajax callback to return index fields fieldset with existing fields and Add Field button. + */ + public static function subIndexFormExistingFieldAjax(array &$form, FormStateInterface $form_state) { + $form["field_json_metadata"]["widget"][0]["indexes"]["field_collection"]["group"]["index"]["fields"]["add_row_button"]['#access'] = TRUE; + return $form["field_json_metadata"]["widget"][0]["indexes"]["field_collection"]["group"]["index"]["fields"]["add_row_button"]; + } +} \ No newline at end of file diff --git a/modules/data_dictionary_widget/src/Indexes/IndexCreation.php b/modules/data_dictionary_widget/src/Indexes/IndexCreation.php new file mode 100644 index 0000000000..2bc766d5ec --- /dev/null +++ b/modules/data_dictionary_widget/src/Indexes/IndexCreation.php @@ -0,0 +1,73 @@ + 'fieldset', + '#title' => t('Fields'), + '#prefix' => '
', + '#suffix' => '
', + '#markup' => t('
One or more fields included in index. Must be keys from the fields object.
'), + '#required' => TRUE, + ]; + + return $element; + } + + /** + * Create basic widget. + */ + public static function createGeneralIndex($element, $current_indexes) { + $element['indexes'] = [ + '#type' => 'fieldset', + '#title' => t('Data Dictionary Indexes'), + '#prefix' => '
', + '#suffix' => '
', + '#markup' => t('
Adding indexes to your datastore tables can improve response times from common queries.
'), + ]; + + $element['indexes']['current_index'] = $current_indexes; + + return $element; + } + + /** + * Create data index data rows. + */ + public static function createIndexFieldsDataRows($index_field_values, $current_index_fields, $index_fields_data_results, $form_state) { + if ($index_field_values) { + return [ + '#access' => ((bool) $current_index_fields || (bool) $index_fields_data_results), + '#type' => 'table', + '#header' => ['NAME', 'LENGTH'], + '#rows' => $form_state->get('cancel_index_field') ? $current_index_fields : ($index_fields_data_results ?? []), + '#tree' => TRUE, + '#theme' => 'custom_index_fields_table', + ]; + } + } + + /** + * Create data index data rows. + */ + public static function createIndexDataRows($current_indexes, $index_data_results, $form_state) { + return [ + '#access' => ((bool) $current_indexes || (bool) $index_data_results), + '#type' => 'table', + '#header' => ['NAME', 'TYPE', 'FIELDS'], + '#prefix' => '
', + '#suffix' => '
', + '#rows' => $form_state->get('cancel_index') ? $current_indexes : ($index_data_results ?? []), + '#tree' => TRUE, + '#theme' => 'custom_index_table', + ]; + } +} \ No newline at end of file diff --git a/modules/data_dictionary_widget/src/Indexes/IndexEditCreation.php b/modules/data_dictionary_widget/src/Indexes/IndexEditCreation.php new file mode 100644 index 0000000000..7cd2f3c804 --- /dev/null +++ b/modules/data_dictionary_widget/src/Indexes/IndexEditCreation.php @@ -0,0 +1,82 @@ + 'field_json_metadata[0][fields][data][' . $indexFieldKeyExplode[3] . '][field_collection][name]', + '#type' => 'textfield', + '#value' => $current_index_fields[$indexFieldKeyExplode[3]]['name'], + '#title' => 'Name', + ]; + $edit_index_fields['length'] = [ + '#name' => 'field_json_metadata[0][fields][data]['. $indexFieldKeyExplode[3] .'][field_collection][length]', + '#type' => 'number', + '#value' => $current_index_fields[$indexFieldKeyExplode[3]]['length'], + '#title' => 'Length', + ]; + + $edit_index_fields['update_index_field']['actions'] = self::createIndexActionFields($indexFieldKey, $id); + return $edit_index_fields; + + } + + /** + * Create edit fields for Data Dictionary Widget. + */ + public static function editIndex($indexKey, $current_index) { + $id = $current_index ? "field-json-metadata-dictionary-index-fields-new" : "field-json-metadata-dictionary-index-fields"; + $indexKeyExplode = explode("_", $indexKey); + $edit_index['name'] = [ + '#name' => 'field_json_metadata[0][index][data][' . $indexKeyExplode[3] . '][field_collection][name]', + '#type' => 'textfield', + '#value' => $current_index[$indexKeyExplode[3]]['name'], + '#title' => 'Name', + ]; + $edit_index['length'] = [ + '#name' => 'field_json_metadata[0][index][data]['. $indexKeyExplode[3] .'][field_collection][length]', + '#type' => 'number', + '#value' => $current_index[$indexKeyExplode[3]]['length'], + '#title' => 'Length', + ]; + + $edit_index['update_index_field']['actions'] = self::createIndexActionFields($indexKey, $id ); + return $edit_index; + + } + + /** + * Create Action buttons. + */ + private static function createIndexActionFields($indexKey, $id) { + return [ + '#type' => 'actions', + 'save_update' => IndexButtons::submitIndexFieldButton('edit', $indexKey), + 'cancel_updates' => IndexButtons::cancelIndexFieldButton('edit', $indexKey, $id), + 'delete_field' => IndexButtons::deleteIndexButton($indexKey), + ]; + } + + /** + * Create Index Field Action buttons. + */ + private static function createIndexFieldActionFields($indexFieldKey) { + return [ + '#type' => 'actions', + 'save_update_index_field' => IndexButtons::submitIndexFieldButton('edit', $indexFieldKey), + 'cancel_update_index_field' => IndexButtons::cancelIndexFieldButton('edit', $indexFieldKey), + 'delete_index_field' => IndexButtons::deleteIndexFieldButton($indexFieldKey), + ]; + } + +} \ No newline at end of file diff --git a/modules/data_dictionary_widget/src/Indexes/IndexOperations.php b/modules/data_dictionary_widget/src/Indexes/IndexOperations.php new file mode 100644 index 0000000000..f12cc8c630 --- /dev/null +++ b/modules/data_dictionary_widget/src/Indexes/IndexOperations.php @@ -0,0 +1,225 @@ + $data) { + $edit_index_field_button = $dictionaryIndexFields['edit_index__field_buttons']['index_field_key_' . $row] ?? NULL; + $edit_index_fields = $dictionaryIndexFields['edit_index_fields']['index_field_key_' . $row] ?? NULL; + // Setting the ajax fields if they exsist. + if ($edit_index_field_button) { + $dictionaryIndexFields['data']['#rows'][$row] = array_merge($data, $edit_index_field_button); + unset($dictionaryIndexFields['edit_index_field_buttons']['index_field_key_' . $row]); + } + elseif ($edit_index_fields) { + unset($dictionaryIndexFields['data']['#rows']['index_field_key_' . $row]); + $dictionaryIndexFields['data']['#rows'][$row]['field_collection'] = $edit_index_fields; + // Remove the buttons so they don't show up twice. + unset($dictionaryIndexFields['edit_index_fields']['index_field_key_' . $row]); + ksort($dictionaryIndexFields['data']['#rows']); + } + } + } + + return $dictionaryIndexFields; + } + + /** + * Setting ajax elements. + */ + public static function setIndexAjaxElements(array $dictionaryIndexes) { + foreach ($dictionaryIndexes['data']['#rows'] as $row => $data) { + $edit_index_button = $dictionaryIndexes['edit_index_buttons']['index_key_' . $row] ?? NULL; + $edit_index_fields = $dictionaryIndexes['edit_index_fields']['index_key_' . $row] ?? NULL; + // Setting the ajax fields if they exsist. + if ($edit_index_button) { + $dictionaryIndexes['data']['#rows'][$row] = array_merge($data, $edit_index_button); + unset($dictionaryIndexes['edit_index_buttons']['index_key_' . $row]); + } + elseif ($edit_index_fields) { + unset($dictionaryIndexes['data']['#rows']['index_key_' . $row]); + $dictionaryIndexes['data']['#rows'][$row]['field_collection'] = $edit_index_fields; + // Remove the buttons so they don't show up twice. + unset($dictionaryIndexes['edit_index_fields']['index_key_' . $row]); + ksort($dictionaryIndexes['data']['#rows']); + } + + } + + return $dictionaryIndexes; + } + + /** + * Cleaning the data up. + */ + public static function processIndexFieldsDataResults($index_data_results, $current_index_fields, $index_field_values, $op) { + if (isset($current_index_fields)) { + $index_data_results = $current_index_fields; + } + + if (isset($index_field_values["field_json_metadata"][0]["indexes"]["fields"]["field_collection"])) { + $index_field_group = $index_field_values["field_json_metadata"][0]["indexes"]["fields"]["field_collection"]["group"]; + + $data_index_fields_pre = [ + [ + "name" => $index_field_group['index']['fields']["name"], + "length" => (int)$index_field_group['index']['fields']["length"], + ], + ]; + } + + if (isset($data_index_fields_pre) && $op === "add_index_field") { + $index_data_results = isset($current_index_fields) ? array_merge($current_index_fields, $data_index_fields_pre) : $data_index_fields_pre; + } + + return $index_data_results; + } + + /** + * Cleaning the data up. + */ + public static function processIndexDataResults($index_results, $current_indexes, $index_values, $index_fields_data_results, $op) { + if (isset($current_indexes)) { + $index_results = $current_indexes; + } + + if (isset($index_values["field_json_metadata"][0]["indexes"]["field_collection"])) { + $index_group = $index_values["field_json_metadata"][0]["indexes"]["field_collection"]["group"]; + + $data_index_pre = [ + [ + "description" => $index_group['index']["description"], + "type" => $index_group['index']["type"], + "fields" => $index_fields_data_results, + ], + ]; + } + + if (isset($data_index_pre) && $op === "add_index") { + $index_results = isset($current_indexes) ? array_merge($current_indexes, $data_index_pre) : $data_index_pre; + } + + return $index_results; + } + + /** + * Return acceptable edit actions. + */ + public static function editIndexActions() { + return [ + 'format', + 'edit', + 'update', + 'abort', + 'delete', + ]; + } + + /** + * Set the elements associated with adding a new field. + */ + public static function setAddIndexFieldFormState($add_new_index_field, $element) { + if ($add_new_index_field) { + + $element['indexes']['fields']['#access'] = FALSE; + $element['indexes']['fields']['field_collection'] = $add_new_index_field; + $element['indexes']['fields']['field_collection']['#access'] = TRUE; + $element['indexes']['fields']['add_row_button']['#access'] = FALSE; + $element['identifier']['#required'] = FALSE; + $element['title']['#required'] = FALSE; + //$element["indexes"]["field_collection"]["group"]["index"]["description"]['#required'] = FALSE; + } + + return $element; + } + + /** + * Set the elements associated with adding a new field. + */ + public static function setAddIndexFormState($add_new_index, $element) { + if ($add_new_index) { + $element['indexes']['field_collection'] = $add_new_index; + $element['indexes']['field_collection']['#access'] = TRUE; + $element['indexes']['add_row_button']['#access'] = FALSE; + $element['identifier']['#required'] = FALSE; + $element['title']['#required'] = FALSE; + //$element["indexes"]["field_collection"]["group"]["index"]["description"]['#required'] = FALSE; + } + + return $element; + } + + /** + * Create edit and update fields where needed. + */ + public static function createDictionaryIndexOptions($op_index, $index_data_results, $index_fields_being_modified, $element) { + $current_indexes = $element['current_index']; + // Creating ajax buttons/fields to be placed in correct location later. + foreach ($index_data_results as $indexKey => $data) { + if (self::checkIndexEditingField('index_key_' . $indexKey, $op_index, $index_fields_being_modified)) { + $element['edit_index']['index_key_' . $indexKey] = IndexEditCreation::editIndex('index_key_' . $indexKey, $current_indexes, $index_fields_being_modified); + } + else { + $element['edit_index_buttons']['index_key_' . $indexKey]['edit_index_button'] = IndexButtons::editIndexButtons('index_key_' . $indexKey); + } + } + $element['add_row_button'] = IndexButtons::addIndexButton(); + + return $element; + } + + /** + * Create edit and update fields for index fields (children) where needed. + */ + public static function createDictionaryIndexFieldOptions($op_index, $index_data_results, $index_fields_being_modified, $element) { + $current_index_fields = $element['current_index_fields'] ?? NULL; + // Creating ajax buttons/fields to be placed in correct location later. + foreach ($index_data_results as $indexFieldKey => $data) { + if (self::checkIndexFieldEditingField('index_field_key_' . $indexFieldKey, $op_index, $index_fields_being_modified)) { + $element['edit_index_fields']['index_field_key_' . $indexFieldKey] = IndexEditCreation::editIndexFields('index_field_key_' . $indexFieldKey, $current_index_fields, $index_fields_being_modified); + } + else { + $element['edit_index_field_buttons']['index_field_key_' . $indexFieldKey]['edit_index_field_button'] = IndexButtons::editIndexFieldButtons('index_field_key_' . $indexFieldKey); + } + } + $element['add_row_button'] = IndexButtons::addIndexFieldButton(); + + return $element; + } + + /** + * Return true if field is being edited. + */ + public static function checkIndexEditingField($indexKey, $op_index, $index_fields_being_modified) { + $action_list = IndexOperations::editIndexActions(); + $indexKeyExplode = explode("_", $indexKey); + if (isset($op_index[0]) && in_array($op_index[0], $action_list) && array_key_exists($indexKeyExplode[3], $index_fields_being_modified)) { + return TRUE; + } + else { + return FALSE; + } + } + + /** + * Return true if field is being edited. + */ + public static function checkIndexFieldEditingField($indexFieldKey, $op_index, $index_fields_being_modified) { + $action_list = IndexOperations::editIndexActions(); + $indexFieldKeyExplode = explode("_", $indexFieldKey); + if (isset($op_index[0]) && in_array($op_index[0], $action_list) && array_key_exists($indexFieldKeyExplode[3], $index_fields_being_modified)) { + return TRUE; + } + else { + return FALSE; + } + } +} \ No newline at end of file diff --git a/modules/data_dictionary_widget/src/Indexes/IndexValidation.php b/modules/data_dictionary_widget/src/Indexes/IndexValidation.php new file mode 100644 index 0000000000..169461116f --- /dev/null +++ b/modules/data_dictionary_widget/src/Indexes/IndexValidation.php @@ -0,0 +1,33 @@ +setError($index_fields_fieldset, t('At least one index field is required.')); + } + } + +} diff --git a/modules/data_dictionary_widget/src/Indexes/IndexValues.php b/modules/data_dictionary_widget/src/Indexes/IndexValues.php new file mode 100644 index 0000000000..01ecd16011 --- /dev/null +++ b/modules/data_dictionary_widget/src/Indexes/IndexValues.php @@ -0,0 +1,21 @@ + $name, + 'length' => $length, + ]; + } +} \ No newline at end of file diff --git a/modules/data_dictionary_widget/src/Plugin/Field/FieldWidget/DataDictionaryWidget.php b/modules/data_dictionary_widget/src/Plugin/Field/FieldWidget/DataDictionaryWidget.php index ddf02d2771..e8f963de32 100644 --- a/modules/data_dictionary_widget/src/Plugin/Field/FieldWidget/DataDictionaryWidget.php +++ b/modules/data_dictionary_widget/src/Plugin/Field/FieldWidget/DataDictionaryWidget.php @@ -10,6 +10,8 @@ use Drupal\data_dictionary_widget\Fields\FieldCreation; use Drupal\data_dictionary_widget\Fields\FieldOperations; use Drupal\Core\Entity\EntityFormInterface; +use Drupal\data_dictionary_widget\Indexes\IndexCreation; +use Drupal\data_dictionary_widget\Indexes\IndexOperations; /** * A data-dictionary widget. @@ -28,39 +30,82 @@ class DataDictionaryWidget extends WidgetBase implements TrustedCallbackInterfac * {@inheritdoc} */ public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) { - $field_values = $form_state->get("new_fields"); - $current_fields = $form_state->get('current_fields'); - $fields_being_modified = $form_state->get("fields_being_modified") ?? NULL; + // Retrieve values from form state + $dictionary_field_values = $form_state->get("new_dictionary_fields"); + $index_values = $form_state->get('new_index'); + $index_field_values = $form_state->get("new_index_fields"); + $add_index_field = $form_state->get('add_new_index_field'); + $add_new_index = $form_state->get('add_new_index'); + $add_new_dictionary_field = $form_state->get('add_new_field'); + $current_dictionary_fields = $form_state->get('current_dictionary_fields'); + $current_indexes = $form_state->get('current_index'); + $current_index_fields = $form_state->get('current_index_fields'); + $dictionary_fields_being_modified = $form_state->get("dictionary_fields_being_modified") ?? NULL; + $index_fields_being_modified = $form_state->get("index_fields_being_modified") ?? NULL; + $op = $form_state->getTriggeringElement()['#op'] ?? NULL; $field_json_metadata = !empty($items[0]->value) ? json_decode($items[0]->value, TRUE) : []; $op_index = isset($form_state->getTriggeringElement()['#op']) ? explode("_", $form_state->getTriggeringElement()['#op']) : NULL; - $data_results = $field_json_metadata ? $field_json_metadata["data"]["fields"] : []; - - // Build the data_results array to display the rows in the data table. - $data_results = FieldOperations::processDataResults($data_results, $current_fields, $field_values, $op); - - $element = FieldCreation::createGeneralFields($element, $field_json_metadata, $current_fields, $form_state); - - $element['dictionary_fields']['#pre_render'] = [ - [$this, 'preRenderForm'], - ]; - - $element['dictionary_fields']['data'] = FieldCreation::createDictionaryDataRows($current_fields, $data_results, $form_state); - - // Creating ajax buttons/fields to be placed in correct location later. - $element['dictionary_fields'] = FieldOperations::createDictionaryFieldOptions($op_index, $data_results, $fields_being_modified, $element['dictionary_fields']); - $element['dictionary_fields']['add_row_button']['#access'] = $fields_being_modified == NULL ? TRUE : FALSE; + // Retrieve initial data results from field JSON metadata + $data_results = $field_json_metadata["data"]["fields"] ?? []; + $index_fields_results = $field_json_metadata["data"]["indexes"][0]["fields"] ?? []; + $index_results = $field_json_metadata["data"]["indexes"] ?? []; + + // Process data results + $data_results = FieldOperations::processDataResults($data_results, $current_dictionary_fields, $dictionary_field_values, $op); + $index_fields_data_results = IndexOperations::processIndexFieldsDataResults($index_fields_results, $current_index_fields, $index_field_values, $op); + $index_data_results = IndexOperations::processIndexDataResults($index_results, $current_indexes, $index_values, $index_fields_data_results, $op); + + // Create form elements + $element = FieldCreation::createGeneralFields($element, $field_json_metadata, $current_dictionary_fields, $form_state); + $element = IndexCreation::createGeneralIndex($element, $current_indexes); + $element = IndexCreation::createGeneralIndexFields($element); + + // Add pre-render functions + $element['dictionary_fields']['#pre_render'] = [[$this, 'preRenderForm']]; + $element['indexes']['#pre_render'] = [[$this, 'preRenderIndexForm']]; + $element['indexes']['fields']['#pre_render'] = [[$this, 'preRenderIndexFieldForm']]; + + // Add data rows to display in tables + $element['dictionary_fields']['data'] = FieldCreation::createDictionaryDataRows($current_dictionary_fields, $data_results, $form_state); + $element['indexes']['data'] = IndexCreation::createIndexDataRows($current_indexes, $index_data_results, $form_state); + $element['indexes']['fields']['data'] = IndexCreation::createIndexFieldsDataRows($index_field_values, $current_index_fields, $index_fields_data_results, $form_state); + + // Create dictionary fields/buttons for editing + $element['dictionary_fields'] = FieldOperations::createDictionaryFieldOptions($op_index, $data_results, $dictionary_fields_being_modified, $element['dictionary_fields']); + $element['dictionary_fields']['add_row_button']['#access'] = $dictionary_fields_being_modified == NULL ? TRUE : FALSE; + + // Create index fields/buttons for editing + $element['indexes'] = IndexOperations::createDictionaryIndexOptions($op_index, $index_data_results, $index_fields_being_modified, $element['indexes']); + if ($index_field_values || $current_index_fields) { + $element["indexes"]["fields"] = IndexOperations::createDictionaryIndexFieldOptions($op_index, $index_fields_data_results, $index_fields_being_modified, $element['indexes']['fields']); + } + $element['indexes']['fields']['add_row_button']['#access'] = $index_field_values ? TRUE : FALSE; + + // Get form entity $form_object = $form_state->getFormObject(); if (!($form_object instanceof EntityFormInterface)) { return; } $form_entity = $form_object->getEntity(); + // Set form entity data type if ($form_entity instanceof FieldableEntityInterface) { $form_entity->set('field_data_type', 'data-dictionary'); } - $element = FieldOperations::setAddFormState($form_state->get('add_new_field'), $element); + + // Set form state for adding fields and indexes + $element = FieldOperations::setAddFormState($add_new_dictionary_field, $element); + $element = IndexOperations::setAddIndexFormState($add_new_index, $element); + $element = IndexOperations::setAddIndexFieldFormState($add_index_field, $element); + + // Display index fields only when new index fields are being created. + if ($add_index_field || $index_field_values) { + $element['indexes']['fields']['#access'] = TRUE; + } else { + $element['indexes']['fields']['#access'] = FALSE; + } return $element; } @@ -69,11 +114,12 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen * {@inheritdoc} */ public function massageFormValues(array $values, array $form, FormStateInterface $form_state) { - $current_fields = $form["field_json_metadata"]["widget"][0]["dictionary_fields"]["data"]["#rows"]; + $current_dictionary_fields = $form["field_json_metadata"]["widget"][0]["dictionary_fields"]["data"]["#rows"]; + $current_indexes = $form["field_json_metadata"]["widget"][0]["indexes"]["data"]["#rows"]; $field_collection = $values[0]['dictionary_fields']["field_collection"]["group"] ?? []; - $indexes = isset($values[0]["indexes"]) ? json_decode($values[0]["indexes"]) : NULL; + $indexes_collection = $values[0]["indexes"]["fields"]["field_collection"]["group"] ?? []; - $data_results = !empty($field_collection) ? [ + $fields_input = !empty($field_collection) ? [ [ "name" => $field_collection["name"], "title" => $field_collection["title"], @@ -83,14 +129,28 @@ public function massageFormValues(array $values, array $form, FormStateInterface ], ] : []; - $updated = array_merge($current_fields ?? [], $data_results); + $index_inputs = !empty($indexes_collection) ? [ + [ + "name" => $indexes_collection["indexes"]["fields"]["name"], + "length" => (int)$indexes_collection["indexes"]["fields"]["length"], + ], + ] : []; + + if (isset($fields_input)) { + $fields = array_merge($current_dictionary_fields ?? [], $fields_input); + } + else { + $fields = $current_dictionary_fields ?? []; + } + + $indexes = array_merge($current_indexes ?? [], $index_inputs); $json_data = [ 'identifier' => $values[0]['identifier'] ?? '', 'data' => [ 'title' => $values[0]['title'] ?? '', - 'fields' => $updated, - 'indexes' => $indexes ?? [], + 'fields' => $fields, + 'indexes' => $indexes, ], ]; @@ -98,7 +158,7 @@ public function massageFormValues(array $values, array $form, FormStateInterface } /** - * Prerender callback for the form. + * Prerender callback for the dictionary form. * * Moves the buttons into the table. */ @@ -106,11 +166,29 @@ public function preRenderForm(array $dictionaryFields) { return FieldOperations::setAjaxElements($dictionaryFields); } + /** + * Prerender callback for the index field form. + * + * Moves the buttons into the table. + */ + public function preRenderIndexFieldForm(array $indexFields) { + return IndexOperations::setIndexFieldsAjaxElements($indexFields); + } + + /** + * Prerender callback for the index form. + * + * Moves the buttons into the table. + */ + public function preRenderIndexForm(array $indexes) { + return IndexOperations::setIndexAjaxElements($indexes); + } + /** * {@inheritdoc} */ public static function trustedCallbacks() { - return ['preRenderForm']; + return ['preRenderForm', 'preRenderIndexFieldForm', 'preRenderIndexForm']; } } diff --git a/modules/data_dictionary_widget/templates/custom-index-fields-table.html.twig b/modules/data_dictionary_widget/templates/custom-index-fields-table.html.twig new file mode 100644 index 0000000000..1b401daf01 --- /dev/null +++ b/modules/data_dictionary_widget/templates/custom-index-fields-table.html.twig @@ -0,0 +1,28 @@ + + + + + + + + + + {% for row in rows %} + {% if row.field_collection %} + + + + {% elseif row.name %} + + + + + + {% endif %} + {% endfor %} + +
{{ header[0] }}{{ header[1] }}{{ header[2] }}
+ {{ row.field_collection }} +
{{ row.name }}{{ row.length }} + {{ row.edit_index_button }} +
diff --git a/modules/data_dictionary_widget/templates/custom-index-table.html.twig b/modules/data_dictionary_widget/templates/custom-index-table.html.twig new file mode 100644 index 0000000000..fe13096e3f --- /dev/null +++ b/modules/data_dictionary_widget/templates/custom-index-table.html.twig @@ -0,0 +1,36 @@ + + + + + + + + + + {% for row in rows %} + {% if row.field_collection %} + + + + {% elseif row.description %} + + + + + + + {% endif %} + {% endfor %} + +
{{ header[0] }}{{ header[1] }}{{ header[2] }}
+ {{ row.field_collection }} +
{{ row.description }}{{ row.type }} + {% for field in row.fields %} +
    +
  • Field Name: {{ field.name }}
    +
    Field Length: {{ field.length }}
  • +
+ {% endfor %} +
+ {{ row.edit_index_button }} +
diff --git a/modules/data_dictionary_widget/tests/src/Unit/DataDictionaryWidgetBuildTest.php b/modules/data_dictionary_widget/tests/src/Unit/DataDictionaryWidgetBuildTest.php index 45106113ad..de230f0622 100644 --- a/modules/data_dictionary_widget/tests/src/Unit/DataDictionaryWidgetBuildTest.php +++ b/modules/data_dictionary_widget/tests/src/Unit/DataDictionaryWidgetBuildTest.php @@ -151,6 +151,16 @@ public function testAddNewFieldDictionaryWidget() { 'data' => [ '#rows' => null ] + ], + 'indexes' => [ + 'data' => [ + '#rows' => null + ], + 'fields' => [ + 'data' => [ + '#rows' => null + ] + ] ] ] ] @@ -209,8 +219,6 @@ public function testAddNewFieldDictionaryWidget() { ] ]; - - $dataDictionaryWidget = new DataDictionaryWidget ( $plugin_id, $plugin_definition, @@ -240,13 +248,15 @@ public function testAddNewFieldDictionaryWidget() { ->method('getTriggeringElement') ->willReturn($trigger); - $formState->expects($this->exactly(4)) + $formState->expects($this->exactly(6)) ->method('set') ->willReturnOnConsecutiveCalls ( '', $this->equalTo($user_input), TRUE, - FALSE + FALSE, + '', + '' ); FieldCallbacks::addSubformCallback($form, $formState); @@ -310,9 +320,9 @@ public function testEditButtonsCreation() { ->method('set') ->with('field_data_type', 'data-dictionary'); - $formState->expects($this->exactly(5)) + $formState->expects($this->exactly(13)) ->method('get') - ->willReturnOnConsecutiveCalls([], $current_fields, NULL, FALSE, NULL); + ->willReturnOnConsecutiveCalls(NULL, NULL, NULL, FALSE, NULL, NULL, $current_fields); $dataDictionaryWidget = new DataDictionaryWidget ( $plugin_id, @@ -394,7 +404,29 @@ public function testEditDataDictionaryField() { 'identifier' => 'test_identifier', 'title' => 'test_title', 'dictionary_fields' => [ - 'data' => [ + 'field_collection' => [ + 'group' => [ + 'name' => 'test_edit', + 'title' => 'test_edit', + 'type' => 'string', + 'format' => 'default', + 'format_other' => '', + 'description' => 'test_edit', + ] + ], + "data" => [ + '#rows' => [ + 0 => [ + 'field_collection' => [ + 'name' => 'test_edit', + 'title' => 'test_edit', + 'type' => 'string', + 'format' => 'default', + 'format_other' => '', + 'description' => 'test_edit', + ], + ], + ], 0 => [ 'field_collection' => [ 'name' => 'test_edit', @@ -403,10 +435,15 @@ public function testEditDataDictionaryField() { 'format' => 'default', 'format_other' => '', 'description' => 'test_edit', - ] - ] + ], + ], + ], + ], + 'indexes' => [ + 'data' => [ + 0 => [], ] - ] + ], ] ] ]; @@ -423,9 +460,9 @@ public function testEditDataDictionaryField() { ->method('set') ->with('field_data_type', 'data-dictionary'); - $formState->expects($this->exactly(12)) + $formState->expects($this->exactly(28)) ->method('get') - ->willReturnOnConsecutiveCalls([], $current_fields, $fields_being_modified, FALSE, NULL, $fields_being_modified, $fields_being_modified, [], $updated_current_fields, $fields_being_modified, FALSE, NULL); + ->willReturnOnConsecutiveCalls($user_input, [], [], [], [], $updated_current_fields, $current_fields, [], [], $fields_being_modified, [], FALSE, FALSE); $formState->expects($this->exactly(11)) ->method('getTriggeringElement') @@ -461,15 +498,33 @@ public function testEditDataDictionaryField() { $this->assertArrayHasKey('description', $element["dictionary_fields"]["edit_fields"][0]); $this->assertArrayHasKey('update_field', $element["dictionary_fields"]["edit_fields"][0]); - $form["field_json_metadata"]["widget"][0]["dictionary_fields"]["data"]["#rows"][0] = [ - 'name' => 'test_edit', - 'title' => 'test_edit', - 'type' => 'string', - 'format' => 'default', - 'format_other' => '', - 'description' => 'test_edit', + $form["field_json_metadata"]["widget"][0] = [ + "dictionary_fields" => [ + "data" => [ + "#rows" => [ + 0 => [ + 'name' => 'test_edit', + 'title' => 'test_edit', + 'type' => 'string', + 'format' => 'default', + 'format_other' => '', + 'description' => 'test_edit', + ], + ], + ], + ], + 'indexes' => [ + 'fields' => [ + 'data' => [ + "#rows" => [ + 0 => [], + ], + ], + ] + ], ]; + // Trigger callback function to save the edited fields. FieldCallbacks::editSubformCallback($form, $formState);