Unverified Commit adf48cb3 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3061571 by Wim Leers, mradcliffe, webchick, heddn, mikelutz: If no...

Issue #3061571 by Wim Leers, mradcliffe, webchick, heddn, mikelutz: If no Drupal 8 equivalent filter is found during migration, drop transformation-only filters, so that body fields show up

(cherry picked from commit f8c0cf38)
parent ab5ca5e4
Loading
Loading
Loading
Loading
+353 −0
Original line number Diff line number Diff line
@@ -5,7 +5,9 @@
use Drupal\Component\Plugin\PluginManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\filter\Plugin\FilterInterface;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\MigrateSkipProcessException;
use Drupal\migrate\Plugin\migrate\process\StaticMap;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row;
@@ -75,6 +77,11 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
      return $plugin_id;
    }
    else {
      if (in_array(static::getSourceFilterType($value), [FilterInterface::TYPE_TRANSFORM_REVERSIBLE, FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE], TRUE)) {
        $message = sprintf('Filter %s could not be mapped to an existing filter plugin; omitted since it is a transformation-only filter. Install and configure a successor after the migration.', $plugin_id);
        $migrate_executable->saveMessage($message, MigrationInterface::MESSAGE_INFORMATIONAL);
        throw new MigrateSkipProcessException("The transformation-only filter $plugin_id was skipped.");
      }
      $fallback = $this->filterManager->getFallbackPluginId($plugin_id);

      // @see \Drupal\filter\Plugin\migrate\process\FilterSettings::transform()
@@ -85,4 +92,350 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
    }
  }

  /**
   * Gets the Drupal 8 filter type for a Drupal 7 filter.
   *
   * @param string $filter_id
   *   A Drupal 7 filter ID.
   *
   * @return int
   *   One of:
   *   - FilterInterface::TYPE_MARKUP_LANGUAGE
   *   - FilterInterface::TYPE_HTML_RESTRICTOR
   *   - FilterInterface::TYPE_TRANSFORM_REVERSIBLE
   *   - FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE
   *
   * @see \Drupal\filter\Plugin\FilterInterface::getType()
   */
  protected static function getSourceFilterType($filter_id) {
    switch ($filter_id) {
      // Drupal 7 core filters.
      // - https://git.drupalcode.org/project/drupal/blob/7.69/modules/filter/filter.module#L1229
      // - https://git.drupalcode.org/project/drupal/blob/7.69/modules/php/php.module#L139
      case 'filter_html':
        return FilterInterface::TYPE_HTML_RESTRICTOR;
      case 'filter_url':
        return FilterInterface::TYPE_MARKUP_LANGUAGE;
      case 'filter_autop':
        return FilterInterface::TYPE_MARKUP_LANGUAGE;
      case 'filter_htmlcorrector':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      case 'filter_html_escape':
        return FilterInterface::TYPE_HTML_RESTRICTOR;
      case 'php_code':
        return FilterInterface::TYPE_MARKUP_LANGUAGE;

      // Drupal 7 contrib filters.
      // https://www.drupal.org/project/abbrfilter
      case 'abbrfilter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/ace_editor
      case 'ace_editor':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/adsense
      case 'adsense':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/api
      case 'api_filter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/api_tokens
      case 'api_tokens':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/autofloat
      case 'filter_autofloat':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/bbcode
      case 'bbcode':
        return FilterInterface::TYPE_MARKUP_LANGUAGE;
      // https://www.drupal.org/project/biblio
      case 'biblio_filter_reference':
      case 'biblio_filter_inline_reference':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/caption
      case 'caption':
        return FilterInterface::TYPE_TRANSFORM_REVERSIBLE;
      // https://www.drupal.org/project/caption_filter
      case 'caption_filter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/cincopa
      case 'filter_cincopa':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/ckeditor_blocks
      case 'ckeditor_blocks':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/ckeditor_filter
      case 'ckeditor_filter':
        return FilterInterface::TYPE_HTML_RESTRICTOR;
      // https://www.drupal.org/project/ckeditor_link
      case 'ckeditor_link_filter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/ckeditor_swf
      case 'ckeditor_swf_filter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/codefilter
      case 'codefilter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/collapse_text
      case 'collapse_text_filter':
        return FilterInterface::TYPE_TRANSFORM_REVERSIBLE;
      // https://www.drupal.org/project/columns_filter
      case 'columns_filter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/commonmark
      case 'commonmark':
        return FilterInterface::TYPE_MARKUP_LANGUAGE;
      // https://www.drupal.org/project/commons_hashtags
      case 'filter_hashtags':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/deepzoom
      case 'deepzoom':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/editor
      case 'editor_align':
      case 'editor_caption':
        return FilterInterface::TYPE_TRANSFORM_REVERSIBLE;
      // https://www.drupal.org/project/elf
      case 'elf':
        return FilterInterface::TYPE_TRANSFORM_REVERSIBLE;
      // https://www.drupal.org/project/emogrifier
      case 'filter_emogrifier':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/emptyparagraphkiller
      case 'emptyparagraphkiller':
        return FilterInterface::TYPE_HTML_RESTRICTOR;
      // https://www.drupal.org/project/entity_embed
      case 'emtity_embed':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      case 'filter_align':
        return FilterInterface::TYPE_TRANSFORM_REVERSIBLE;
      // https://www.drupal.org/project/ext_link_page
      case 'ext_link_page':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/filter_html_image_secure
      case 'filter_html_image_secure':
        return FilterInterface::TYPE_HTML_RESTRICTOR;
      // https://www.drupal.org/project/filter_transliteration
      case 'filter_transliteration':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/flickr
      case 'flickr_filter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/float_filter
      case 'float_filter':
        return FilterInterface::TYPE_TRANSFORM_REVERSIBLE;
      // https://www.drupal.org/project/footnotes
      case 'filter_footnotes':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/forena
      case 'forena_report':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/g2
      case 'filter_g2':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/geo_filter
      case 'geo_filter_filter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/google_analytics_counter
      case 'filter_google_analytics_counter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/google_analytics_referrer
      case 'filter_google_analytics_referrer':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/gotwo
      case 'gotwo_link':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/h5p
      case 'h5p_content':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/highlightjs
      case 'highlight_js':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/htmLawed
      case 'htmLawed':
        return FilterInterface::TYPE_HTML_RESTRICTOR;
      // https://www.drupal.org/project/htmlpurifier
      case 'htmlpurifier_basic':
      case 'htmlpurifier_advanced':
        return FilterInterface::TYPE_HTML_RESTRICTOR;
      // https://www.drupal.org/project/htmltidy
      case 'htmltidy':
        return FilterInterface::TYPE_HTML_RESTRICTOR;
      // https://www.drupal.org/project/icon
      case 'icon_filter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/iframe_filter
      case 'iframe':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/image_resize_filter
      case 'image_resize_filter':
        return FilterInterface::TYPE_TRANSFORM_REVERSIBLE;
      // https://www.drupal.org/project/insert_view
      case 'insert_view':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/intlinks
      case 'intlinks title':
      case 'intlinks hide bad':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/jquery_ui_filter
      case 'accordion':
      case 'dialog':
      case 'tabs':
        return FilterInterface::TYPE_MARKUP_LANGUAGE;
      // https://www.drupal.org/project/language_sections
      case 'language_sections':
        return FilterInterface::TYPE_MARKUP_LANGUAGE;
      // https://www.drupal.org/project/lazy
      case 'lazy_filter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/lazyloader_filter
      case 'lazyloader_filter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/link_node
      case 'filter_link_node':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/linktitle
      case 'linktitle':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/markdown
      case 'filter_markdown':
        return FilterInterface::TYPE_MARKUP_LANGUAGE;
      // https://www.drupal.org/project/media_wysiwyg
      case 'media_filter':
      case 'media_filter_paragraph_fix':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/mentions
      case 'filter_mentions':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/menu_filter
      case 'menu_filter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/mobile_codes
      case 'mobile_codes':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/multicolumn
      case 'multicolumn':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/multilink
      case 'multilink_filter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/mytube
      case 'mytube':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/node_embed
      case 'node_embed':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/node_field_embed
      case 'node_field_embed':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/noindex_external_links
      case 'external_links':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/noreferrer
      case 'noreferrer':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/oembed
      case 'oembed':
      case 'oembed_legacy':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/office_html
      case 'office_html_strip':
        return FilterInterface::TYPE_HTML_RESTRICTOR;
      case 'office_html_convert':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/openlayers_filters
      case 'openlayers':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/opengraph_filter
      case 'opengraph_filter':
        return FilterInterface::TYPE_TRANSFORM_REVERSIBLE;
      // https://www.drupal.org/project/pathologic
      case 'pathologic':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/popup
      case 'popup_tags':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/prettify
      case 'prettify':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/rel_to_abs
      case 'rel_to_abs':
        return FilterInterface::TYPE_TRANSFORM_REVERSIBLE;
      // https://www.drupal.org/project/rollover_filter
      case 'rollover_filter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/sanitizable
      case 'sanitizable':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/smart_paging
      case 'smart_paging_filter':
      case 'smart_paging_filter_autop':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/spamspan
      case 'spamspan':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/scald
      case 'mee_scald_widgets':
        return FilterInterface::TYPE_TRANSFORM_REVERSIBLE;
      // https://www.drupal.org/project/script_filter
      case 'script_filter':
        return FilterInterface::TYPE_TRANSFORM_REVERSIBLE;
      // https://www.drupal.org/project/shortcode
      case 'shortcode':
        return FilterInterface::TYPE_MARKUP_LANGUAGE;
      case 'shortcode_text_corrector':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/smiley
      case 'smiley':
        return FilterInterface::TYPE_TRANSFORM_REVERSIBLE;
      // https://www.drupal.org/project/svg_embed
      case 'filter_svg_embed':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/spoiler
      case 'spoiler':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/tableofcontents
      case 'filter_toc':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/tables
      case 'filter_tables':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/target_filter_url
      case 'target_filter_url':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/textile
      case 'textile':
        return FilterInterface::TYPE_MARKUP_LANGUAGE;
      // https://www.drupal.org/project/theme_filter
      case 'theme_filter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/token_filter
      case 'filter_tokens':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/transliteration
      case 'transliteration':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/typogrify
      case 'typogrify':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/uuid_link
      case 'uuid_link_filter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/wysiwyg
      case 'wysiwyg':
      case 'wysiwyg_template_cleanup':
        return FilterInterface::TYPE_HTML_RESTRICTOR;
      // https://www.drupal.org/project/word_link
      case 'word_link':
        return FilterInterface::TYPE_TRANSFORM_REVERSIBLE;
      // https://www.drupal.org/project/wordfilter
      case 'wordfilter':
        return FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE;
      // https://www.drupal.org/project/xbbcode
      case 'xbbcode':
        return FilterInterface::TYPE_MARKUP_LANGUAGE;
    }

    return NULL;
  }

}
+21 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
use Drupal\filter\Plugin\migrate\process\FilterID;
use Drupal\KernelTests\KernelTestBase;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\MigrateSkipProcessException;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row;

@@ -61,6 +62,18 @@ public function testTransform($value, $expected_value, $invalid_id = NULL) {
    ];
    $plugin = FilterID::create($this->container, $configuration, 'filter_id', []);

    if ($expected_value instanceof MigrateSkipProcessException) {
      $this->executable
        ->expects($this->exactly(1))
        ->method('saveMessage')
        ->with(
          sprintf('Filter %s could not be mapped to an existing filter plugin; omitted since it is a transformation-only filter. Install and configure a successor after the migration.', $value),
          MigrationInterface::MESSAGE_INFORMATIONAL
        );
      $this->expectException(MigrateSkipProcessException::class);
      $this->expectExceptionMessage(sprintf("The transformation-only filter %s was skipped.", $value));
    }

    if (isset($invalid_id)) {
      $this->executable
        ->expects($this->exactly(1))
@@ -110,6 +123,14 @@ public function provideFilters() {
        'filter_null',
        'filter:1',
      ],
      'transformation-only D7 contrib filter' => [
        'editor_align',
        new MigrateSkipProcessException('The transformation-only filter editor_align was skipped.'),
      ],
      'non-transformation-only D7 contrib filter' => [
        'bbcode',
        'filter_null',
      ],
    ];
  }