From acc48a3034c5e4caf43b33dffeef7a859f1d08cb Mon Sep 17 00:00:00 2001 From: ADmad Date: Mon, 14 Mar 2016 12:31:29 +0530 Subject: [PATCH] Add Text::slug(). --- src/Utility/Text.php | 27 ++++++++++ src/Utility/composer.json | 9 ++-- tests/TestCase/Utility/TextTest.php | 81 +++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 3 deletions(-) diff --git a/src/Utility/Text.php b/src/Utility/Text.php index e3b3f129cb4..daa8e9214ed 100644 --- a/src/Utility/Text.php +++ b/src/Utility/Text.php @@ -852,4 +852,31 @@ public static function parseFileSize($size, $default = false) } 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); + } } diff --git a/src/Utility/composer.json b/src/Utility/composer.json index 92b09b45d61..0d780887341 100644 --- a/src/Utility/composer.json +++ b/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\\": "." diff --git a/tests/TestCase/Utility/TextTest.php b/tests/TestCase/Utility/TextTest.php index 666f9648ad4..66bc0fa7463 100644 --- a/tests/TestCase/Utility/TextTest.php +++ b/tests/TestCase/Utility/TextTest.php @@ -1588,4 +1588,85 @@ public function filesizes() [['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); + } }