From 15b391c17c13623a81da54c81971e2148558bbe4 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 15 Sep 2020 13:40:12 +0200 Subject: [PATCH] [String] allow translit rules to be given as closure --- AbstractUnicodeString.php | 4 +++- Slugger/AsciiSlugger.php | 18 ++++++++++++++++-- Tests/AbstractUnicodeTestCase.php | 10 ++++++++++ Tests/SluggerTest.php | 11 +++++++++++ 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/AbstractUnicodeString.php b/AbstractUnicodeString.php index 2584079..0cba861 100644 --- a/AbstractUnicodeString.php +++ b/AbstractUnicodeString.php @@ -77,7 +77,7 @@ public static function fromCodePoints(int ...$codes): self * * Install the intl extension for best results. * - * @param string[]|\Transliterator[] $rules See "*-Latin" rules from Transliterator::listIDs() + * @param string[]|\Transliterator[]|\Closure[] $rules See "*-Latin" rules from Transliterator::listIDs() */ public function ascii(array $rules = []): self { @@ -107,6 +107,8 @@ public function ascii(array $rules = []): self if ($rule instanceof \Transliterator) { $s = $rule->transliterate($s); + } elseif ($rule instanceof \Closure) { + $s = $rule($s); } elseif ($rule) { if ('nfd' === $rule = strtolower($rule)) { normalizer_is_normalized($s, self::NFD) ?: $s = normalizer_normalize($s, self::NFD); diff --git a/Slugger/AsciiSlugger.php b/Slugger/AsciiSlugger.php index 3352b04..c6ddbdf 100644 --- a/Slugger/AsciiSlugger.php +++ b/Slugger/AsciiSlugger.php @@ -66,8 +66,15 @@ class AsciiSlugger implements SluggerInterface, LocaleAwareInterface */ private $transliterators = []; - public function __construct(string $defaultLocale = null, array $symbolsMap = null) + /** + * @param array|\Closure|null $symbolsMap + */ + public function __construct(string $defaultLocale = null, $symbolsMap = null) { + if (null !== $symbolsMap && !\is_array($symbolsMap) && !$symbolsMap instanceof \Closure) { + throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be array, Closure or null, "%s" given.', __METHOD__, \gettype($symbolMap))); + } + $this->defaultLocale = $defaultLocale; $this->symbolsMap = $symbolsMap ?? $this->symbolsMap; } @@ -103,9 +110,16 @@ public function slug(string $string, string $separator = '-', string $locale = n $transliterator = (array) $this->createTransliterator($locale); } + if ($this->symbolsMap instanceof \Closure) { + $symbolsMap = $this->symbolsMap; + array_unshift($transliterator, static function ($s) use ($symbolsMap, $locale) { + return $symbolsMap($s, $locale); + }); + } + $unicodeString = (new UnicodeString($string))->ascii($transliterator); - if (isset($this->symbolsMap[$locale])) { + if (\is_array($this->symbolsMap) && isset($this->symbolsMap[$locale])) { foreach ($this->symbolsMap[$locale] as $char => $replace) { $unicodeString = $unicodeString->replace($char, ' '.$replace.' '); } diff --git a/Tests/AbstractUnicodeTestCase.php b/Tests/AbstractUnicodeTestCase.php index 84e64b0..e4bf998 100644 --- a/Tests/AbstractUnicodeTestCase.php +++ b/Tests/AbstractUnicodeTestCase.php @@ -20,6 +20,16 @@ public function testAscii() $this->assertSame('Dieser Wert sollte groesser oder gleich', (string) $s->ascii(['de-ASCII'])); } + public function testAsciiClosureRule() + { + $rule = function ($c) { + return str_replace('ö', 'OE', $c); + }; + + $s = static::createFromString('Dieser Wert sollte größer oder gleich'); + $this->assertSame('Dieser Wert sollte grOEsser oder gleich', (string) $s->ascii([$rule])); + } + public function provideCreateFromCodePoint(): array { return [ diff --git a/Tests/SluggerTest.php b/Tests/SluggerTest.php index 1290759..e838da6 100644 --- a/Tests/SluggerTest.php +++ b/Tests/SluggerTest.php @@ -64,4 +64,15 @@ public function testSlugCharReplacementLocaleMethod() $slug = (string) $slugger->slug('yo & tu a esta dirección slug@test.es', '_', 'es'); $this->assertSame('yo_y_tu_a_esta_direccion_slug_en_senal_test_es', $slug); } + + public function testSlugClosure() + { + $slugger = new AsciiSlugger(null, function ($s, $locale) { + $this->assertSame('foo', $locale); + + return str_replace('❤️', 'love', $s); + }); + + $this->assertSame('love', (string) $slugger->slug('❤️', '-', 'foo')); + } }