function SourceEditingRedundantTagsConstraintValidator::validate

Same name and namespace in other branches
  1. 9 core/modules/ckeditor5/src/Plugin/Validation/Constraint/SourceEditingRedundantTagsConstraintValidator.php \Drupal\ckeditor5\Plugin\Validation\Constraint\SourceEditingRedundantTagsConstraintValidator::validate()
  2. 10 core/modules/ckeditor5/src/Plugin/Validation/Constraint/SourceEditingRedundantTagsConstraintValidator.php \Drupal\ckeditor5\Plugin\Validation\Constraint\SourceEditingRedundantTagsConstraintValidator::validate()

Throws

\Symfony\Component\Validator\Exception\UnexpectedTypeException Thrown when the given constraint is not supported by this validator.

File

core/modules/ckeditor5/src/Plugin/Validation/Constraint/SourceEditingRedundantTagsConstraintValidator.php, line 33

Class

SourceEditingRedundantTagsConstraintValidator
Ensures tags already available via plugin are not be added to Source Editing.

Namespace

Drupal\ckeditor5\Plugin\Validation\Constraint

Code

public function validate($value, Constraint $constraint) : void {
  if (!$constraint instanceof SourceEditingRedundantTagsConstraint) {
    throw new UnexpectedTypeException($constraint, __NAMESPACE__ . '\\SourceEditingRedundantTagsConstraint');
  }
  if (empty($value)) {
    return;
  }
  $text_editor = $this->createTextEditorObjectFromContext();
  $other_enabled_plugins = $this->getOtherEnabledPlugins($text_editor, 'ckeditor5_sourceEditing');
  $enableable_disabled_plugins = $this->getEnableableDisabledPlugins($text_editor);
  // An array of tags enabled by every plugin other than Source Editing.
  $enabled_plugin_elements = new HTMLRestrictions($this->pluginManager
    ->getProvidedElements(array_keys($other_enabled_plugins), $text_editor, FALSE));
  $enabled_plugin_elements_optional = (new HTMLRestrictions($this->pluginManager
    ->getProvidedElements(array_keys($other_enabled_plugins))))
    ->diff($enabled_plugin_elements);
  $disabled_plugin_elements = new HTMLRestrictions($this->pluginManager
    ->getProvidedElements(array_keys($enableable_disabled_plugins), $text_editor, FALSE));
  $enabled_plugin_plain_tags = new HTMLRestrictions($this->pluginManager
    ->getProvidedElements(array_keys($other_enabled_plugins), $text_editor, FALSE, TRUE));
  $disabled_plugin_plain_tags = new HTMLRestrictions($this->pluginManager
    ->getProvidedElements(array_keys($enableable_disabled_plugins), $text_editor, FALSE, TRUE));
  // The single element for which source editing is enabled, which we are
  // checking now.
  $source_enabled_element = HTMLRestrictions::fromString($value);
  // Test for empty allowed elements with resolved wildcards since, for the
  // purposes of this validator, HTML restrictions containing only wildcards
  // should be considered empty.
  // @todo Remove this early return in
  //   https://www.drupal.org/project/drupal/issues/2820364. It is only
  //   necessary because CKEditor5ElementConstraintValidator does not run
  //   before this, which means that this validator cannot assume it receives
  //   valid values.
  if (count($source_enabled_element->getAllowedElements()) !== 1) {
    return;
  }
  $enabled_plugin_overlap = $enabled_plugin_elements->intersect($source_enabled_element);
  $enabled_plugin_optional_overlap = $enabled_plugin_elements_optional->intersect($source_enabled_element);
  $disabled_plugin_overlap = $disabled_plugin_elements->merge($enabled_plugin_elements)
    ->intersect($source_enabled_element)
    ->diff($enabled_plugin_overlap);
  foreach ([
    $enabled_plugin_overlap,
    $enabled_plugin_optional_overlap,
    $disabled_plugin_overlap,
  ] as $overlap) {
    $checking_enabled = $overlap === $enabled_plugin_overlap || $overlap === $enabled_plugin_optional_overlap;
    if (!$overlap->allowsNothing()) {
      $plugins_to_check_against = $checking_enabled ? $other_enabled_plugins : $enableable_disabled_plugins;
      $plain_tags_to_check_against = $checking_enabled ? $enabled_plugin_plain_tags : $disabled_plugin_plain_tags;
      $tags_plugin_report = $this->pluginsSupplyingTagsMessage($overlap, $plugins_to_check_against, $enabled_plugin_elements);
      $message = match ($overlap) {  $enabled_plugin_overlap => $constraint->enabledPluginsMessage,
        $enabled_plugin_optional_overlap => $constraint->enabledPluginsOptionalMessage,
        $disabled_plugin_overlap => $constraint->availablePluginsMessage,
      
      };
      // Determine which element type is relevant for the violation message.
      assert(count($overlap->getAllowedElements(FALSE)) === 1);
      $overlap_tag = array_keys($overlap->getAllowedElements(FALSE))[0];
      $is_attr_overlap = self::tagHasAttributeRestrictions($overlap, $overlap_tag);
      // If one or more attributes (and all of the allowed attribute values)
      // of the HTML elements being configured to be edited via the Source
      // Editing plugin is supported by a CKEditor 5 plugin, complain. But if
      // an attribute overlap is detected due to a wildcard attribute, then do
      // not generate a violation message.
      // For example:
      // - value `<ol start foo>` triggers a violation because `<ol start>` is
      //   supported by the `ckeditor5_list` plugin
      // - value `<img data-*>` does NOT trigger a violation because only
      //   concrete `data-`-attributes are supported by the
      //   `ckeditor5_imageUpload`, `ckeditor5_imageCaption` and
      //   `ckeditor5_imageAlign` plugins
      if ($is_attr_overlap && $source_enabled_element->diff($overlap)
        ->getAllowedElements(FALSE) == $source_enabled_element->getAllowedElements(FALSE)) {
        continue;
      }
      // If there is overlap, but the plain tag is not supported in the
      // overlap, exit this iteration without generating a violation message.
      // Essentially when assessing a particular value (for example `<span>`),
      // CKEditor 5 plugins supporting only the creation of attributes on this
      // tag (`<span lang>`) and not supporting the creation of this plain tag
      // (`<span>` explicitly listed in their elements) can trigger a
      // violation.
      if (!$is_attr_overlap) {
        $value_is_plain_tag_only = !self::tagHasAttributeRestrictions($source_enabled_element, $overlap_tag);
        // When the configured value is a plain tag (`<tag>`): do not generate
        // a violation message if this tag cannot be created by any CKEditor 5
        // plugin.
        if ($value_is_plain_tag_only && $overlap->intersect($plain_tags_to_check_against)
          ->allowsNothing()) {
          continue;
        }
        // When the configured value is not a plain tag (so the value has the
        // shape `<tag attr>`, not `<tag>`): do not generate a violation
        // message if the tag can already be created by another CKEditor 5
        // plugin: this is just adding the ability to set more attributes.
        // Note: this does not check whether the plain tag can indeed be
        // created, validating that is out of scope for this validator.
        // @see \Drupal\ckeditor5\Plugin\Validation\Constraint\FundamentalCompatibilityConstraintValidator::checkAllHtmlTagsAreCreatable()
        if (!$value_is_plain_tag_only) {
          continue;
        }
      }
      // If we reach this, it means the entirety (so not just the tag but also
      // the attributes, and not just some of the attribute values, but all of
      // them) of the HTML elements being configured to be edited via the
      // Source Editing plugin's 'allowed_tags' configuration is supported by
      // a CKEditor 5 plugin. This earns a violation.
      $this->context
        ->buildViolation($message)
        ->setParameter('@element_type', $is_attr_overlap ? $this->t('attribute') : $this->t('tag'))
        ->setParameter('%overlapping_tags', $tags_plugin_report)
        ->addViolation();
    }
  }
}

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