소스 검색

Working filter with basic test coverage for process().

Frederic G. MARAND 7 년 전
부모
커밋
29aeee42f0
2개의 변경된 파일66개의 추가작업 그리고 233개의 파일을 삭제
  1. 20 186
      src/Plugin/Filter/UrlReplaceFilter.php
  2. 46 47
      test/src/Unit/UrlReplaceFilterTest.php

+ 20 - 186
src/Plugin/Filter/UrlReplaceFilter.php

@@ -3,7 +3,6 @@
 namespace Drupal\url_replace_filter\Plugin\Filter;
 
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\Component\Utility\Html;
 use Drupal\Core\Messenger\MessengerInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Routing\CurrentRouteMatch;
@@ -71,20 +70,8 @@ class UrlReplaceFilter extends FilterBase implements ContainerFactoryPluginInter
     parent::__construct($configuration, $plugin_id, $plugin_definition);
     $this->currentRouteMatch = $currentRouteMatch;
     $this->messenger = $messenger;
-  }
 
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(
-    ContainerInterface $container,
-    array $configuration,
-    $plugin_id,
-    $plugin_definition
-  ) {
-    $messenger = $container->get('messenger');
-    $currentRouteMatch = $container->get('current_route_match');
-    return new static($configuration, $plugin_id, $plugin_definition, $currentRouteMatch, $messenger);
+    $this->base = base_path();
   }
 
   /**
@@ -117,6 +104,20 @@ class UrlReplaceFilter extends FilterBase implements ContainerFactoryPluginInter
     return $form;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(
+    ContainerInterface $container,
+    array $configuration,
+    $plugin_id,
+    $plugin_definition
+  ) {
+    $messenger = $container->get('messenger');
+    $currentRouteMatch = $container->get('current_route_match');
+    return new static($configuration, $plugin_id, $plugin_definition, $currentRouteMatch, $messenger);
+  }
+
   /**
    * Return the list of input formats containing the active URL Replace filter.
    *
@@ -247,10 +248,10 @@ class UrlReplaceFilter extends FilterBase implements ContainerFactoryPluginInter
    */
   public function tips($long = FALSE) {
     if ($long) {
-      return $this->t('To post pieces of code, surround them with <code>...</code> tags. For PHP code, you can use <?php ... ?>, which will also colour it based on syntax.');
+      return $this->t('Selected URLs may be rewritten by url_rewrite_filter.');
     }
     else {
-      return $this->t('You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.');
+      return NULL;
     }
   }
 
@@ -258,29 +259,9 @@ class UrlReplaceFilter extends FilterBase implements ContainerFactoryPluginInter
    * {@inheritdoc}
    */
   public function process($text, $langcode) {
-    // Escape code tags to prevent other filters from acting on them.
-    $text = preg_replace_callback('@<code>(.+?)</code>@s', [get_class($this), 'codeTagCallback'], $text);
-    $text = preg_replace_callback('@[\[<](\?php)(.+?)(\?)[\]>]@s', [get_class($this), 'phpTagCallback'], $text);
-
-    // Replace code.
-    $text = preg_replace_callback('@\[codefilter_code\](.+?)\[/codefilter_code\]@s', [get_class($this), 'processCodeCallback'], $text);
-    $text = preg_replace_callback('@\[codefilter_php\](.+?)\[/codefilter_php\]@s', [get_class($this), 'processPHPCallback'], $text);
-
-    // A hack, so we can conditionally nowrap based on filter settings.
-    // @todo Refactor how replacements are done so we can do this more cleanly.
-    if ($this->settings['nowrap_expand']) {
-      $text = str_replace('class="codeblock"', 'class="codeblock nowrap-expand"', $text);
-    }
-    return new FilterProcessResult($text);
-  }
-
-  /**
-   * Filter the given text.
-   */
-  public function doProcess($text, $format) {
-    $settings = _url_replace_filter_get_settings($format);
+    $settings = unserialize($this->settings['replacements']);
     foreach ($settings as $setting) {
-      if ($setting['original']) {
+      if (!empty($setting['original'])) {
         $pattern = '!((<a\s[^>]*href)|(<img\s[^>]*src))\s*=\s*"' . preg_quote($setting['original']) . '!iU';
         if (preg_match_all($pattern, $text, $matches)) {
           $replacement = str_replace('%baseurl', rtrim(base_path(), '/'), $setting['replacement']);
@@ -290,155 +271,8 @@ class UrlReplaceFilter extends FilterBase implements ContainerFactoryPluginInter
         }
       }
     }
-    return $text;
-  }
-
-  /**
-   * Callback to replace content of the <code> elements.
-   *
-   * @param array $matches
-   *   An array of matches passed by preg_replace_callback().
-   *
-   * @return string
-   *   A formatted string.
-   */
-  public static function processCodeCallback(array $matches) {
-    return self::processCode($matches[1]);
-  }
-
-  /**
-   * Callback to replace content of the <?php ?> elements.
-   *
-   * @param array $matches
-   *   An array of matches passed by preg_replace_callback().
-   *
-   * @return string
-   *   A formatted string.
-   */
-  public static function processPhpCallback(array $matches) {
-    return self::processPhp($matches[1]);
-  }
-
-  /**
-   * Escape code blocks.
-   *
-   * @param string $text
-   *   The string to escape.
-   * @param string $type
-   *   The type of code block, either 'code' or 'php'.
-   *
-   * @return string
-   *   The escaped string.
-   */
-  public static function escape($text, $type = 'code') {
-    // Note, pay attention to odd preg_replace-with-/e behaviour on slashes.
-    $text = Html::escape(str_replace('\"', '"', $text));
-
-    // Protect newlines from line break converter.
-    $text = str_replace(["\r", "\n"], ['', '&#10;'], $text);
-
-    // Add codefilter escape tags.
-    $text = "[codefilter_$type]{$text}[/codefilter_$type]";
-
-    return $text;
-  }
-
-  /**
-   * Processes chunks of escaped code into HTML.
-   */
-  public static function processCode($text) {
-    // Undo linebreak escaping.
-    $text = str_replace('&#10;', "\n", $text);
-    // Inline or block level piece?
-    $multiline = strpos($text, "\n") !== FALSE;
-    // Note, pay attention to odd preg_replace-with-/e behaviour on slashes.
-    $text = preg_replace("/^\n/", '', preg_replace('@</?(br|p)\s*/?>@', '', str_replace('\"', '"', $text)));
-    // Trim leading and trailing linebreaks.
-    $text = trim($text, "\n");
-    // Escape newlines.
-    $text = nl2br($text);
-
-    // PHP code in regular code.
-    $text = preg_replace_callback('/&lt;\?php.+?\?&gt;/s', [get_class(), 'processPHPInline'], $text);
-
-    $text = '<code>' . self::fixSpaces(str_replace(' ', '&nbsp;', $text)) . '</code>';
-    $text = $multiline ? '<div class="codeblock">' . $text . '</div>' : $text;
-    // Remove newlines to avoid clashing with the linebreak filter.
-    return str_replace("\n", '', $text);
-  }
-
-  /**
-   * Helper function for processCode().
-   */
-  public static function processPhpInline($matches) {
-    // Undo nl2br.
-    $text = str_replace('<br />', '', $matches[0]);
-    // Decode entities (the highlighter re-entifies) and highlight text.
-    $text = highlight_string(Html::decodeEntities($text), 1);
-    // Remove PHPs own added code tags.
-    $text = str_replace(['<code>', '</code>', "\n"], ['', '', ''], $text);
-    return $text;
-  }
 
-  /**
-   * Processes chunks of escaped PHP code into HTML.
-   */
-  public static function processPhp($text) {
-    // Note, pay attention to odd preg_replace-with-/e behaviour on slashes.
-    // Undo possible linebreak filter conversion.
-    $text = preg_replace('@</?(br|p)\s*/?>@', '', str_replace('\"', '"', $text));
-    // Undo the escaping in the prepare step.
-    $text = Html::decodeEntities($text);
-    // Trim leading and trailing linebreaks.
-    $text = trim($text, "\r\n");
-    // Highlight as PHP.
-    $text = '<div class="codeblock">' . highlight_string("<?php\n$text\n?>", 1) . '</div>';
-    // Remove newlines to avoid clashing with the linebreak filter.
-    $text = str_replace("\n", '', $text);
-    return self::fixSpaces($text);
-  }
-
-  /**
-   * Replace html space elements with literal space characters.
-   *
-   * @param string $text
-   *   A string to fix spaces for.
-   *
-   * @return string
-   *   A formatted string.
-   */
-  public static function fixSpaces($text) {
-    $text = preg_replace('@&nbsp;(?!&nbsp;)@', ' ', $text);
-    // A single space before text is ignored by browsers. If a single space
-    // follows a break tag, replace it with a non-breaking space.
-    $text = preg_replace('@<br /> ([^ ])@', '<br />&nbsp;$1', $text);
-    return $text;
-  }
-
-  /**
-   * Callback to escape content of <code> tags.
-   *
-   * @param array $matches
-   *   An array of matches passed by preg_replace_callback().
-   *
-   * @return string
-   *   A formatted string.
-   */
-  public static function codeTagCallback(array $matches) {
-    return self::escape($matches[1], 'code');
-  }
-
-  /**
-   * Callback to escape content of <?php ?>, [?php ?], <% %>, and [% %] tags.
-   *
-   * @param array $matches
-   *   An array of matches passed by preg_replace_callback().
-   *
-   * @return string
-   *   A formatted string.
-   */
-  public static function phpTagCallback(array $matches) {
-    return self::escape($matches[2], 'php');
+    return new FilterProcessResult($text);
   }
 
 }

+ 46 - 47
test/src/Unit/UrlReplaceFilterTest.php

@@ -2,9 +2,13 @@
 
 namespace Drupal\Tests\filter\Unit;
 
+use Drupal\Core\Language\Language;
 use Drupal\Tests\UnitTestCase;
 use Drupal\url_replace_filter\Plugin\Filter\UrlReplaceFilter;
 
+// The plugin needs base_path(), but the normal test boot does not load it.
+require_once 'core/includes/common.inc';
+
 /**
  * @coversDefaultClass \Drupal\url_replace_filter\Plugin\Filter\UrlReplaceFilter
  * @group filter
@@ -12,6 +16,8 @@ use Drupal\url_replace_filter\Plugin\Filter\UrlReplaceFilter;
 class UrlReplaceFilterTest extends UnitTestCase {
 
   /**
+   * An instance of the filter plugin to test.
+   *
    * @var \Drupal\url_replace_filter\Plugin\Filter\UrlReplaceFilter
    */
   protected $filter;
@@ -21,10 +27,13 @@ class UrlReplaceFilterTest extends UnitTestCase {
    */
   protected function setUp() {
     parent::setUp();
+    $GLOBALS['base_path'] = '/';
     $configuration['settings'] = [
       UrlReplaceFilter::SETTING_NAME => serialize([
-        'original' => '',
-        'replacement' => '',
+        [
+          'original' => '/blog/files/',
+          'replacement' => '/sites/blog/files/',
+        ],
       ]),
     ];
     $this->filter = new UrlReplaceFilter($configuration, UrlReplaceFilter::ID, ['provider' => 'test']);
@@ -32,66 +41,56 @@ class UrlReplaceFilterTest extends UnitTestCase {
   }
 
   /**
-   * @covers ::filterAttributes
+   * @covers ::process
    *
-   * @dataProvider providerFilterAttributes
+   * @dataProvider providerProcess
    *
    * @param string $html
    *   Input HTML.
-   * @param array $expected
+   * @param string $expected
    *   The expected output string.
    */
-  public function testfilterAttributes($html, $expected) {
-    $this->assertSame($expected, $this->filter->filterAttributes($html));
+  public function testProcess(string $html, string $expected) {
+    $this->assertSame($expected, $this->filter->process($html, Language::LANGCODE_SITE_DEFAULT)->__toString());
   }
 
   /**
-   * Provides data for testfilterAttributes.
+   * Provides data for testProcess.
    *
    * @return array
    *   An array of test data.
    */
-  public function providerFilterAttributes() {
+  public function providerProcess() {
     return [
-      ['<a href="/blog" title="Blog">Blog</a>', '<a href="/blog">Blog</a>'],
-      ['<p dir="rtl" />', '<p dir="rtl"></p>'],
-      ['<p dir="bogus" />', '<p></p>'],
-      ['<p id="first" />', '<p></p>'],
-      // The addition of xml:lang isn't especially desired, but is still valid
-      // HTML5. See https://www.drupal.org/node/1333730.
-      ['<p id="first" lang="en">text</p>', '<p lang="en" xml:lang="en">text</p>'],
-      ['<p style="display: none;" />', '<p></p>'],
-      ['<code class="pretty invalid">foreach ($a as $b) {}</code>', '<code class="pretty">foreach ($a as $b) {}</code>'],
-      ['<code class="boring pretty">foreach ($a as $b) {}</code>', '<code class="boring pretty">foreach ($a as $b) {}</code>'],
-      ['<code class="boring    pretty ">foreach ($a as $b) {}</code>', '<code class="boring pretty">foreach ($a as $b) {}</code>'],
-      ['<code class="invalid alpaca">foreach ($a as $b) {}</code>', '<code>foreach ($a as $b) {}</code>'],
-      ['<h3 class="big">a heading</h3>', '<h3>a heading</h3>'],
-      ['<h3 id="first">a heading</h3>', '<h3 id="first">a heading</h3>'],
-      // Wilcard value. Case matters, so upper case doesn't match.
-      ['<code class="align-left bold">foreach ($a as $b) {}</code>', '<code class="align-left">foreach ($a as $b) {}</code>'],
-      ['<code class="align-right ">foreach ($a as $b) {}</code>', '<code class="align-right">foreach ($a as $b) {}</code>'],
-      ['<code class="Align-right ">foreach ($a as $b) {}</code>', '<code>foreach ($a as $b) {}</code>'],
-      // Wilcard name, case is ignored.
-      ['<ol style="display: none;" llama-wim="noble majestic"></ol>', '<ol llama-wim="noble majestic"></ol>'],
-      ['<ol style="display: none;" LlamA-Wim="majestic"></ol>', '<ol llama-wim="majestic"></ol>'],
-      ['<ol style="display: none;" llama-="noble majestic"></ol>', '<ol llama-="noble majestic"></ol>'],
-      // Both wildcard names and values.
-      ['<ul style="display: none;" alpaca-wool="wooly-warm strong majestic"></ul>', '<ul alpaca-wool="wooly-warm strong"></ul>'],
-    ];
-  }
-
-  /**
-   * @covers ::setConfiguration
-   */
-  public function testSetConfiguration() {
-    $configuration['settings'] = [
-      // New lines and spaces are replaced with a single space.
-      'allowed_html' => "<a>  <br>\r\n  <p>",
-      'filter_html_help' => 1,
-      'filter_html_nofollow' => 0,
+      [
+        '<a href="/blog" title="Blog">Blog</a>',
+        '<a href="/blog" title="Blog">Blog</a>',
+      ],
+      [
+        '<a href="/blog/files" title="Blog files">Blog</a>',
+        '<a href="/blog/files" title="Blog files">Blog</a>',
+      ],
+      [
+        '<a href="/blog/files/foo.png" title="Blog Foo">Blog</a>',
+        '<a href="/sites/blog/files/foo.png" title="Blog Foo">Blog</a>',
+      ],
+      [
+        '<img src="/blog" title="Blog">Blog</img>',
+        '<img src="/blog" title="Blog">Blog</img>',
+      ],
+      [
+        '<img src="/blog/files" title="Blog files">Blog</img>',
+        '<img src="/blog/files" title="Blog files">Blog</img>',
+      ],
+      [
+        '<img src="/blog/files/foo.png" alt="Blog Foo">Blog</img>',
+        '<img src="/sites/blog/files/foo.png" alt="Blog Foo">Blog</img>',
+      ],
+      [
+        '<img alt="Blog Foo" src="/blog/files/foo.png">Blog</img>',
+        '<img alt="Blog Foo" src="/sites/blog/files/foo.png">Blog</img>',
+      ],
     ];
-    $filter = new FilterHtml($configuration, 'filter_html', ['provider' => 'test']);
-    $this->assertSame('<a> <br> <p>', $filter->getConfiguration()['settings']['allowed_html']);
   }
 
 }