Browse Source

Add Text::slug().

ADmad 10 years ago
parent
commit
acc48a3034
3 changed files with 114 additions and 3 deletions
  1. 27 0
      src/Utility/Text.php
  2. 6 3
      src/Utility/composer.json
  3. 81 0
      tests/TestCase/Utility/TextTest.php

+ 27 - 0
src/Utility/Text.php

@@ -852,4 +852,31 @@ class Text
         }
         throw new InvalidArgumentException('No unit type.');
     }
+
+    /**
+     * Returns a string with all spaces converted to dashes (by default), accented
+     * characters converted to non-accented characters, and non word characters removed.
+     *
+     * @param string $string the string you want to slug
+     * @param array $options Options
+     * @return string
+     */
+    public static function slug($string, $options = [])
+    {
+        $options += [
+            'replacement' => '-',
+            'transliteratorId' => 'Any-Latin; Latin-ASCII'
+        ];
+
+        $quotedReplacement = preg_quote($options['replacement'], '/');
+        $map = [
+            '/[^\s\p{Zs}\p{Ll}\p{Lm}\p{Lo}\p{Lt}\p{Lu}\p{Nd}]/mu' => ' ',
+            '/[\s\p{Zs}]+/mu' => $options['replacement'],
+            sprintf('/^[%s]+|[%s]+$/', $quotedReplacement, $quotedReplacement) => '',
+        ];
+
+        $string = preg_replace(array_keys($map), array_values($map), $string);
+
+        return transliterator_transliterate($options['transliteratorId'], $string);
+    }
 }

+ 6 - 3
src/Utility/composer.json

@@ -4,10 +4,13 @@
     "license": "MIT",
     "authors": [
         {
-        "name": "CakePHP Community",
-        "homepage": "http://cakephp.org"
-    }
+            "name": "CakePHP Community",
+            "homepage": "http://cakephp.org"
+        }
     ],
+    "suggest": {
+      "ext-intl": "To use Text::slug()."
+    },
     "autoload": {
         "psr-4": {
             "Cake\\Utility\\": "."

+ 81 - 0
tests/TestCase/Utility/TextTest.php

@@ -1588,4 +1588,85 @@ podeís adquirirla.</span></p>
             [['size' => '2VB', 'default' => 'Unknown type'], 'Unknown type']
         ];
     }
+
+    public function slugInputProvider()
+    {
+        return [
+            [
+                'Foo Bar: Not just for breakfast any-more', [],
+                'Foo-Bar-Not-just-for-breakfast-any-more'
+            ],
+            [
+                'Foo Bar: Not just for breakfast any-more', ['replacement' => '_'],
+                'Foo_Bar_Not_just_for_breakfast_any_more'
+            ],
+            [
+                'Foo Bar: Not just for breakfast any-more', ['replacement' => '+'],
+                'Foo+Bar+Not+just+for+breakfast+any+more'
+            ],
+            [
+                'Äpfel Über Öl grün ärgert groß öko', [],
+                'Aepfel-Ueber-Oel-gruen-aergert-gross-oeko'
+            ],
+            [
+                'The truth - and- more- news', [],
+                'The-truth-and-more-news'
+            ],
+            [
+                'The truth: and more news', [],
+                'The-truth-and-more-news'
+            ],
+            [
+                'La langue française est un attribut de souveraineté en France', [],
+                'La-langue-francaise-est-un-attribut-de-souverainete-en-France'
+            ],
+            [
+                '!@$#exciting stuff! - what !@-# was that?', [],
+                'exciting-stuff-what-was-that'
+            ],
+            [
+                '20% of profits went to me!', [],
+                '20-of-profits-went-to-me'
+            ],
+            [
+                '#this melts your face1#2#3', [],
+                'this-melts-your-face1-2-3'
+            ],
+            [
+                'controller/action/りんご/1', [],
+                'controller-action-りんご-1'
+            ],
+            [
+                'の話が出たので大丈夫かなあと', [],
+                'の話が出たので大丈夫かなあと'
+            ],
+            [
+                'posts/view/한국어/page:1/sort:asc', [],
+                'posts-view-한국어-page-1-sort-asc'
+            ],
+            [
+                "non\xc2\xa0breaking\xc2\xa0space", [],
+                'non-breaking-space'
+            ],
+            [
+                'Foo Bar: Not just for breakfast any-more', ['replacement' => ''],
+                'FooBarNotjustforbreakfastanymore'
+            ],
+        ];
+    }
+
+    /**
+     * testSlug method
+     *
+     * @param string $string String
+     * @param array $options Options
+     * @param String $expected Exepected string
+     * @return void
+     * @dataProvider slugInputProvider
+     */
+    public function testSlug($string, $options, $expected)
+    {
+        $result = Text::slug($string, $options);
+        $this->assertEquals($expected, $result);
+    }
 }