You are here

private function HTMLRestrictions::doDiff in Drupal 10

Computes difference of two HTML restrictions, without wildcard support.

Parameters

\Drupal\ckeditor5\HTMLRestrictions $other: The HTML restrictions to compare to.

Return value

\Drupal\ckeditor5\HTMLRestrictions Returns a new HTML restrictions value object with all the elements that are not allowed in $other.

File

core/modules/ckeditor5/src/HTMLRestrictions.php, line 438

Class

HTMLRestrictions
Represents a set of HTML restrictions.

Namespace

Drupal\ckeditor5

Code

private function doDiff(HTMLRestrictions $other) : HTMLRestrictions {
  $diff_elements = array_filter(DiffArray::diffAssocRecursive($this->elements, $other->elements), function ($value, string $tag) use ($other) {

    // If this HTML restrictions object contains a tag that the other did
    // not contain at all: keep the DiffArray result.
    if (!array_key_exists($tag, $other->elements)) {
      return TRUE;
    }

    // All subsequent checks can assume that $other contains an entry for
    // this tag.
    // If this HTML restrictions object does not allow any attributes for
    // this tag, then the other is at least equally restrictive: drop the
    // DiffArray result.
    if ($value === FALSE) {
      return FALSE;
    }

    // If this HTML restrictions object allows any attributes for this
    // tag, then the other is at most equally permissive: keep the
    // DiffArray result.
    if ($value === TRUE) {
      return TRUE;
    }

    // Otherwise, this HTML restrictions object allows specific attributes
    // only. DiffArray only knows to compare arrays. When the other object
    // has a non-array value for this tag, interpret those values correctly.
    assert(is_array($value));

    // The other object is more restrictive regarding allowed attributes
    // for this tag: keep the DiffArray result.
    if ($other->elements[$tag] === FALSE) {
      return TRUE;
    }

    // The other object is more permissive regarding allowed attributes
    // for this tag: drop the DiffArray result.
    if ($other->elements[$tag] === TRUE) {
      return FALSE;
    }

    // Both objects have lists of allowed attributes: keep the DiffArray
    // result and apply postprocessing after this array_filter() call,
    // because this can only affect tag-level differences.
    // @see ::validateAllowedRestrictionsPhase3()
    assert(is_array($other->elements[$tag]));
    return TRUE;
  }, ARRAY_FILTER_USE_BOTH);

  // Attribute-level postprocessing for two special cases:
  // - wildcard attribute names
  // - per attribute name: attribute value restrictions in $this vs all values
  //   allowed in $other
  foreach ($diff_elements as $tag => $tag_config) {

    // If there are no per-attribute restrictions for this tag in either
    // operand, then no postprocessing is needed.
    if (!is_array($tag_config) || !(isset($other->elements[$tag]) && is_array($other->elements[$tag]))) {
      continue;
    }

    // Special case: wildcard attributes, and the ability to define
    // restrictions for all concrete attributes matching them using:
    // - prefix wildcard, f.e. `*-foo`
    // - infix wildcard, f.e. `*-entity-*`
    // - suffix wildcard, f.e. `data-*`, to match `data-foo`, `data-bar`, etc.
    $wildcard_attributes = array_filter(array_keys($other->elements[$tag]), [
      __CLASS__,
      'isWildcardAttributeName',
    ]);
    foreach ($wildcard_attributes as $wildcard_attribute_name) {
      $regex = self::getRegExForWildCardAttributeName($wildcard_attribute_name);
      foreach ($tag_config as $html_tag_attribute_name => $html_tag_attribute_restrictions) {

        // If a wildcard attribute name (f.e. `data-*`) is allowed in $other
        // with the same attribute value restrictions (e.g. TRUE to allow all
        // attribute values or an array of specific allowed attribute values),
        // then all concrete matches (f.e. `data-foo`, `data-bar`, etc.) are
        // allowed and should be explicitly omitted from the difference.
        if ($html_tag_attribute_restrictions === $other->elements[$tag][$wildcard_attribute_name] && preg_match($regex, $html_tag_attribute_name) === 1) {
          unset($tag_config[$html_tag_attribute_name]);
        }
      }
    }

    // Attribute value restrictions in $this, all values allowed in $other.
    foreach ($tag_config as $html_tag_attribute_name => $html_tag_attribute_restrictions) {
      if (is_array($html_tag_attribute_restrictions) && isset($other->elements[$tag][$html_tag_attribute_name]) && $other->elements[$tag][$html_tag_attribute_name] === TRUE) {
        unset($tag_config[$html_tag_attribute_name]);
      }
    }

    // Ensure $diff_elements continues to be structured in a way that is valid
    // for a HTMLRestrictions object to be constructed from it.
    if ($tag_config !== []) {
      $diff_elements[$tag] = $tag_config;
    }
    else {
      unset($diff_elements[$tag]);
    }
  }
  return new self($diff_elements);
}