fieldTypePluginManager = $plugin_manager; $this->diffBuilderManager = $diff_builder_manager; $this->entityTypeManager = $entity_type_manager; $this->entityFieldManager = $entity_field_manager; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( $container->get('config.factory'), $container->get('plugin.manager.field.field_type'), $container->get('plugin.manager.diff.builder'), $container->get('entity_type.manager'), $container->get('entity_field.manager') ); } /** * {@inheritdoc} */ public function getFormId() { return 'diff_admin_plugins'; } /** * {@inheritdoc} */ protected function getEditableConfigNames() { return ['diff.plugins']; } /** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { $form = parent::buildForm($form, $form_state); // The table containing all the field types discovered in the system. $form['fields'] = array( '#type' => 'table', '#tree' => TRUE, '#header' => $this->getTableHeader(), '#empty' => $this->t('No field types found.'), '#prefix' => '
', '#suffix' => '
', '#attributes' => array( 'class' => array('field-ui-overview'), 'id' => 'field-display-overview', ), ); // Build a row in the table for each field of each entity type. Get all the // field plugins. foreach ($this->entityTypeManager->getDefinitions() as $entity_type_name => $entity_type) { // Exclude non-revisionable entities. if (!$entity_type->isRevisionable()) { continue; } $field_definitions = $this->entityFieldManager->getFieldStorageDefinitions($entity_type_name); foreach ($field_definitions as $field_name => $field_definition) { $show_diff = $this->diffBuilderManager->showDiff($field_definition); if (!$show_diff) { continue; } $key = $entity_type_name . '.' . $field_name; // Build a row in the table for this field. $form['fields'][$key] = $this->buildFieldRow($entity_type, $field_definition, $form_state); } } $this->diffBuilderManager->clearCachedDefinitions(); // Submit button for the form. $form['actions'] = array('#type' => 'actions'); $form['actions']['submit'] = array( '#type' => 'submit', '#button_type' => 'primary', '#value' => $this->t('Save'), ); $form['#attached']['library'][] = 'field_ui/drupal.field_ui'; $form['#attached']['library'][] = 'diff/diff.general'; return $form; } /** * Builds a row for the table. Each row corresponds to a field type. * * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type * The entity type. * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $field_definition * Definition the field type. * @param FormStateInterface $form_state * THe form state object. * * @return array * A table row for the field type listing table. */ protected function buildFieldRow(EntityTypeInterface $entity_type, FieldStorageDefinitionInterface $field_definition, FormStateInterface $form_state) { $entity_type_label = $entity_type->getLabel(); $field_name = $field_definition->getName(); $field_type = $field_definition->getType(); $field_key = $entity_type->id() . '.' . $field_name; $display_options = $this->diffBuilderManager->getSelectedPluginForFieldStorageDefinition($field_definition); $plugin_options = $this->diffBuilderManager->getApplicablePluginOptions($field_definition); // Base button element for the various plugin settings actions. $base_button = [ '#submit' => [[$this, 'multiStepSubmit']], '#ajax' => [ 'callback' => [$this, 'multiStepAjax'], 'wrapper' => 'field-display-overview-wrapper', 'effect' => 'fade', ], '#field_key' => $field_key, ]; $field_row['entity_type'] = [ '#markup' => $entity_type_label, ]; $labels = _diff_field_label($entity_type->id(), $field_name); $field_row['field_label'] = [ '#markup' => array_shift($labels), ]; $field_type_label = $this->fieldTypePluginManager->getDefinitions()[$field_type]['label']; $field_row['field_type'] = [ '#markup' => $field_type_label, ]; // Check the currently selected plugin, and merge persisted values for its // settings. if ($type = $form_state->getValue(['fields', $field_key, 'plugin', 'type'])) { $display_options['type'] = $type; } $plugin_settings = $form_state->get('plugin_settings'); if (isset($plugin_settings[$field_key]['settings'])) { $modified = FALSE; if (!empty($display_options['settings'])) { foreach ($display_options['settings'] as $key => $value) { if ($plugin_settings[$field_key]['settings'][$key] != $value) { $modified = TRUE; break; } } } // In case settings are not identical to the ones in the config display // a warning message. Don't display it twice. if ($modified && empty($_SESSION['messages']['warning'])) { drupal_set_message($this->t('You have unsaved changes.'), 'warning'); } $display_options['settings'] = $plugin_settings[$field_key]['settings']; } $field_row['plugin'] = array( 'type' => array( '#type' => 'select', '#options' => $plugin_options, '#empty_option' => $this->t("- Don't compare -"), '#empty_value' => 'hidden', '#title_display' => 'invisible', '#attributes' => array( 'class' => array('field-plugin-type'), ), '#default_value' => $display_options, '#ajax' => array( 'callback' => [$this, 'multiStepAjax'], 'method' => 'replace', 'wrapper' => 'field-display-overview-wrapper', 'effect' => 'fade', ), '#field_key' => $field_key, ), 'settings_edit_form' => array(), ); // Get a configured instance of the plugin. $plugin = $this->getPlugin($display_options); // We are currently editing this field's plugin settings. Display the // settings form and submit buttons. if ($form_state->get('plugin_settings_edit') == $field_key) { $field_row['plugin']['settings_edit_form'] = array( '#type' => 'container', '#attributes' => array('class' => array('field-plugin-settings-edit-form')), '#parents' => ['fields', $field_key, 'settings_edit_form'], 'label' => array( '#markup' => $this->t('Plugin settings:' . ' ' . $plugin_options[$display_options['type']] . ''), ), 'settings' => $plugin->buildConfigurationForm(array(), $form_state), 'actions' => array( '#type' => 'actions', 'save_settings' => $base_button + [ '#type' => 'submit', '#button_type' => 'primary', '#name' => $field_key . '_plugin_settings_update', '#value' => $this->t('Update'), '#op' => 'update', ], 'cancel_settings' => $base_button + [ '#type' => 'submit', '#name' => $field_key . '_plugin_settings_cancel', '#value' => $this->t('Cancel'), '#op' => 'cancel', // Do not check errors for the 'Cancel' button, but make sure we // get the value of the 'plugin type' select. '#limit_validation_errors' => [['fields', $field_key, 'plugin', 'type']], ], ), ); $field_row['settings_edit'] = array(); $field_row['#attributes']['class'][] = 'field-plugin-settings-editing'; } else { $field_row['settings_edit'] = []; // Display the configure settings button only if a plugin is selected. if ($plugin) { $field_row['settings_edit'] = $base_button + array( '#type' => 'image_button', '#name' => $field_key . '_settings_edit', '#src' => 'core/misc/icons/787878/cog.svg', '#attributes' => ['class' => ['field-plugin-settings-edit'], 'alt' => $this->t('Edit')], '#op' => 'edit', // Do not check errors for the 'Edit' button, but make sure we get // the value of the 'plugin type' select. '#limit_validation_errors' => [['fields', $field_key, 'plugin', 'type']], '#prefix' => '
', '#suffix' => '
', ); } } return $field_row; } /** * Form submission handler for multi-step buttons. * * @param array $form * The form array. * @param \Drupal\Core\Form\FormStateInterface $form_state * The form state object. */ public function multiStepSubmit(array $form, FormStateInterface $form_state) { $trigger = $form_state->getTriggeringElement(); $op = $trigger['#op']; switch ($op) { case 'edit': // Store the field whose settings are currently being edited. $field_key = $trigger['#field_key']; $form_state->set('plugin_settings_edit', $field_key); break; case 'update': // Store the saved settings, and set the field back to 'non edit' mode. $field_key = $trigger['#field_key']; if ($plugin_settings = $form_state->getValue(['fields', $field_key, 'settings_edit_form', 'settings'])) { $form_state->set(['plugin_settings', $field_key, 'settings'], $plugin_settings); } $form_state->set('plugin_settings_edit', NULL); break; case 'cancel': // Set the field back to 'non edit' mode. $form_state->set('plugin_settings_edit', NULL); break; } $form_state->setRebuild(); } /** * Ajax handler for multi-step buttons. * * @param array $form * The form array. * @param \Drupal\Core\Form\FormStateInterface $form_state * The form state object. * * @return array * The fields form for a plugin. */ public function multiStepAjax(array $form, FormStateInterface $form_state) { $trigger = $form_state->getTriggeringElement(); if (isset($trigger['#op'])) { $op = $trigger['#op']; // Pick the elements that need to receive the ajax-new-content effect. $updated_rows = []; $updated_columns = []; switch ($op) { case 'edit': $updated_rows = [$trigger['#field_key']]; $updated_columns = array('plugin'); break; case 'update': case 'cancel': $updated_rows = [$trigger['#field_key']]; $updated_columns = array('plugin', 'settings_edit'); break; } foreach ($updated_rows as $name) { foreach ($updated_columns as $key) { $element = &$form['fields'][$name][$key]; $element['#prefix'] = '
' . (isset($element['#prefix']) ? $element['#prefix'] : ''); $element['#suffix'] = (isset($element['#suffix']) ? $element['#suffix'] : '') . '
'; } } } // Return the whole table. return $form['fields']; } /** * {@inheritdoc} */ public function validateForm(array &$form, FormStateInterface $form_state) { $form_values = $form_state->getValues(); $plugin_settings = $form_state->get('plugin_settings'); $fields = $form_values['fields']; foreach ($fields as $field_key => $field_values) { // Validate only non-null plugins. if ($field_values['plugin']['type'] != 'hidden') { $settings = array(); $key = NULL; // Form submitted without pressing update button on plugin settings form. if (isset($field_values['settings_edit_form']['settings'])) { $settings = $field_values['settings_edit_form']['settings']; $key = 1; } // Form submitted after settings were updated. elseif (isset($plugin_settings[$field_key]['settings'])) { $settings = $plugin_settings[$field_key]['settings']; $key = 2; } if (!empty($settings)) { // Build a new Form State object and populate it with values. $state = new FormState(); $state->setValues($settings); $state->set('fields', $field_key); $plugin = $this->diffBuilderManager->createInstance($field_values['plugin']['type'], []); // Send the values to the plugins form validate handler. $plugin->validateConfigurationForm($form, $state); // Assign the validation messages back to the big table. if ($key == 1) { $form_state->setValue(['fields', $field_key, 'settings_edit_form', 'settings'], $state->getValues()); } elseif ($key == 2) { $form_state->set(['plugin_settings', $field_key, 'settings'], $state->getValues()); } } } } } /** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { $form_values = $form_state->getValues(); $plugin_settings = $form_state->get('plugin_settings'); $fields = $form_values['fields']; $config = $this->config('diff.plugins'); // Save the settings. foreach ($fields as $field_key => $field_values) { if ($field_values['plugin']['type'] == 'hidden') { $config->set('fields.' . $field_key, ['type' => 'hidden', 'settings' => []]); } else { // Initialize the plugin, if the type is unchanged then with the // existing settings, otherwise let it fall back to the default // settings. $configuration = []; if ($config->get('fields.' . $field_key . '.type') == $field_values['plugin']['type'] && $config->get('fields.' . $field_key . '.settings')) { $configuration = $config->get('fields.' . $field_key . '.settings'); } $plugin = $this->diffBuilderManager->createInstance($field_values['plugin']['type'], $configuration); // Get plugin settings. They lie either directly in submitted form // values (if the whole form was submitted while some plugin settings // were being edited), or have been persisted in $form_state. $values = NULL; // Form submitted without pressing update button on plugin settings form. if (isset($field_values['settings_edit_form']['settings'])) { $values = $field_values['settings_edit_form']['settings']; } // Form submitted after settings were updated. elseif (isset($plugin_settings[$field_key]['settings'])) { $values = $plugin_settings[$field_key]['settings']; } // Build a FormState object and call the plugin submit handler. if ($values) { $state = new FormState(); $state->setValues($values); $plugin->submitConfigurationForm($form, $state); } $config->set('fields.' . $field_key, [ 'type' => $field_values['plugin']['type'], 'settings' => $plugin->getConfiguration(), ]); } } $config->save(); drupal_set_message($this->t('Your settings have been saved.')); } /** * Returns a plugin object or NULL if no plugin could be found. * * @param array $configuration * The plugin configuration. * * @return \Drupal\diff\FieldDiffBuilderInterface|null * The plugin. */ protected function getPlugin(array $configuration) { if ($configuration && isset($configuration['type']) && $configuration['type'] != 'hidden') { if (!isset($configuration['settings'])) { $configuration['settings'] = array(); } return $this->diffBuilderManager->createInstance( $configuration['type'], $configuration['settings'] ); } return NULL; } /** * Returns the header for the table. */ protected function getTableHeader() { return array( 'entity_type' => $this->t('Entity Type'), 'field_name' => $this->t('Field'), 'field_type' => $this->t('Field Type'), 'plugin' => $this->t('Plugin'), 'settings_edit' => '', ); } }