function CKEditor5::validateConfigurationForm

Same name and namespace in other branches
  1. 9 core/modules/ckeditor5/src/Plugin/Editor/CKEditor5.php \Drupal\ckeditor5\Plugin\Editor\CKEditor5::validateConfigurationForm()
  2. 11.x core/modules/ckeditor5/src/Plugin/Editor/CKEditor5.php \Drupal\ckeditor5\Plugin\Editor\CKEditor5::validateConfigurationForm()

Overrides EditorBase::validateConfigurationForm

File

core/modules/ckeditor5/src/Plugin/Editor/CKEditor5.php, line 599

Class

CKEditor5
Defines a CKEditor 5-based text editor for Drupal.

Namespace

Drupal\ckeditor5\Plugin\Editor

Code

public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
  $json = $form_state->getValue([
    'toolbar',
    'items',
  ]);
  $toolbar_items = Json::decode($json);
  // This basic validation must live in the form logic because it can only
  // occur in a form context.
  if (!$toolbar_items) {
    $form_state->setErrorByName('toolbar][items', $this->t('Invalid toolbar value.'));
    return;
  }
  // Construct a Text Editor config entity with the submitted values for
  // validation. Do this on a clone: do not manipulate form state.
  $submitted_editor = clone $form_state->get('editor');
  $settings = $submitted_editor->getSettings();
  // Update settings first to match the submitted toolbar items. This is
  // necessary for ::shouldHaveVisiblePluginSettingsForm() to work.
  $settings['toolbar']['items'] = $toolbar_items;
  $submitted_editor->setSettings($settings);
  $eventual_editor_and_format_for_plugin_settings_visibility = $this->getEventualEditorWithPrimedFilterFormat($form_state, $submitted_editor);
  $settings['plugins'] = [];
  $default_configurations = [];
  foreach ($this->ckeditor5PluginManager
    ->getDefinitions() as $plugin_id => $definition) {
    if (!$definition->isConfigurable()) {
      continue;
    }
    // Create a fresh instance of this CKEditor 5 plugin, not tied to a text
    // editor configuration entity.
    $plugin = $this->ckeditor5PluginManager
      ->getPlugin($plugin_id, NULL);
    // If this plugin is configurable but it has empty default configuration,
    // that means the configuration must be stored out of band.
    // @see \Drupal\ckeditor5\Plugin\CKEditor5Plugin\Image
    // @see editor_image_upload_settings_form()
    $default_configuration = $plugin->defaultConfiguration();
    $configuration_stored_out_of_band = empty($default_configuration);
    // If this plugin is configurable but has not yet had user interaction,
    // the default configuration will still be active and may trigger
    // validation errors. Do not trigger those validation errors until the
    // form is actually saved, to allow the user to first configure other
    // CKEditor 5 functionality.
    $default_configurations[$plugin_id] = $default_configuration;
    if ($form_state->hasValue([
      'plugins',
      $plugin_id,
    ])) {
      $subform = $form['plugins'][$plugin_id];
      $subform_state = SubformState::createForSubform($subform, $form, $form_state);
      $plugin->validateConfigurationForm($subform, $subform_state);
      $plugin->submitConfigurationForm($subform, $subform_state);
      // If the configuration is stored out of band, ::submitConfigurationForm
      // will already have stored it. If it is not stored out of band,
      // populate $settings, to populate $submitted_editor.
      if (!$configuration_stored_out_of_band) {
        $settings['plugins'][$plugin_id] = $plugin->getConfiguration();
      }
    }
    elseif ($this->shouldHaveVisiblePluginSettingsForm($definition, $eventual_editor_and_format_for_plugin_settings_visibility)) {
      if (!$configuration_stored_out_of_band) {
        $settings['plugins'][$plugin_id] = $default_configuration;
      }
    }
  }
  // All plugin settings have been collected, including defaults that depend
  // on visibility. Store the collected settings, throw away the interim state
  // that allowed determining which defaults to add.
  // Create a new clone, because the plugins whose data is being stored
  // out-of-band may have modified the Text Editor config entity in the form
  // state.
  // @see \Drupal\editor\EditorInterface::setImageUploadSettings()
  // @see \Drupal\ckeditor5\Plugin\CKEditor5Plugin\Image::submitConfigurationForm()
  unset($eventual_editor_and_format_for_plugin_settings_visibility);
  $submitted_editor = clone $form_state->get('editor');
  $submitted_editor->setSettings($settings);
  // Validate the text editor + text format pair.
  // Note that the eventual pair is computed and validated, not the received
  // pair: if the filter_html filter is in use, the CKEditor 5 configuration
  // dictates the filter_html's filter plugin's "allowed_html" setting.
  // @see ckeditor5_form_filter_format_form_alter()
  // @see ::getGeneratedAllowedHtmlValue()
  $eventual_editor_and_format = $this->getEventualEditorWithPrimedFilterFormat($form_state, $submitted_editor);
  $violations = CKEditor5::validatePair($eventual_editor_and_format, $eventual_editor_and_format->getFilterFormat());
  foreach ($violations as $violation) {
    $property_path_parts = explode('.', $violation->getPropertyPath());
    // Special case: AJAX updates that do not submit the form (that cannot
    // result in configuration being saved).
    if (in_array('editor_form_filter_admin_format_editor_configure', $form_state->getSubmitHandlers(), TRUE)) {
      // Ensure that plugins' validation constraints do not immediately
      // trigger a validation error: the user may choose to configure other
      // CKEditor 5 aspects first.
      if ($property_path_parts[0] === 'settings' && $property_path_parts[1] === 'plugins') {
        $plugin_id = $property_path_parts[2];
        // This CKEditor 5 plugin settings form was just added: the user has
        // not yet had a chance to configure it.
        if (!$form_state->hasValue([
          'plugins',
          $plugin_id,
        ])) {
          continue;
        }
        // This CKEditor 5 plugin settings form was added recently, the user
        // is triggering AJAX rebuilds of the configuration UI because they're
        // configuring other functionality first. Only require these to be
        // valid at form submission time.
        if ($form_state->getValue([
          'plugins',
          $plugin_id,
        ]) === $default_configurations[$plugin_id]) {
          continue;
        }
      }
    }
    $form_item_name = static::mapPairViolationPropertyPathsToFormNames($violation->getPropertyPath(), $form);
    // When adding a toolbar item, it is possible that not all conditions for
    // using it have been met yet. FormBuilder refuses to rebuild forms when a
    // validation error is present. But to meet the condition for the toolbar
    // item, configuration must be set in a vertical tab that must still
    // appear. Work-around: reduce the validation error to a warning message.
    // @see \Drupal\ckeditor5\Plugin\Validation\Constraint\ToolbarItemConditionsMetConstraintValidator
    if ($form_state->isRedirectDisabled() && $form_item_name === 'editor][settings][toolbar][items') {
      $this->messenger()
        ->addWarning($violation->getMessage());
      continue;
    }
    $form_state->getCompleteFormState()
      ->setErrorByName($form_item_name, $violation->getMessage());
  }
  // Pass it on to ::submitConfigurationForm().
  $form_state->get('editor')
    ->setSettings($settings);
  // Provide the validated eventual pair in form state to
  // ::getGeneratedAllowedHtmlValue(), to update filter_html's
  // "allowed_html".
  $form_state->set('ckeditor5_validated_pair', $eventual_editor_and_format);
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.