function CKEditor5::validateConfigurationForm

Same name in other branches
  1. 9 core/modules/ckeditor5/src/Plugin/Editor/CKEditor5.php \Drupal\ckeditor5\Plugin\Editor\CKEditor5::validateConfigurationForm()
  2. 10 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 570

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.