From 4d7bd089f6a5b7166905c9e246975741fbb6c6f2 Mon Sep 17 00:00:00 2001 From: Josh Bruce Date: Fri, 19 May 2023 13:27:04 -0400 Subject: [PATCH] add: String to slug capability --- composer.json | 3 +- composer.lock | 76 +++++++++++++++++++++++++++++++++- src/Php/StrToSlug.php | 82 +++++++++++++++++++++++++++++++++++++ tests/Php/StrToSlugTest.php | 31 ++++++++++++++ 4 files changed, 190 insertions(+), 2 deletions(-) create mode 100644 src/Php/StrToSlug.php create mode 100644 tests/Php/StrToSlugTest.php diff --git a/composer.json b/composer.json index 6bc0a91..2ba4c54 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,8 @@ "php": "^8.1", "8fold/php-xml-builder": "^2.0", "psr/http-message": "^1.1", - "psr/log": "^3.0" + "psr/log": "^3.0", + "voku/portable-ascii": "^2.0" }, "require-dev": { "phpstan/phpstan": "^1.10", diff --git a/composer.lock b/composer.lock index 30f3d23..c16fa62 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e526c8f8975994b46abdac77d29dc505", + "content-hash": "0b93e6bc8923580ba41e09f3add7a3f7", "packages": [ { "name": "8fold/php-xml-builder", @@ -163,6 +163,80 @@ "source": "https://github.com/php-fig/log/tree/3.0.0" }, "time": "2021-07-14T16:46:02+00:00" + }, + { + "name": "voku/portable-ascii", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/voku/portable-ascii.git", + "reference": "b56450eed252f6801410d810c8e1727224ae0743" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b56450eed252f6801410d810c8e1727224ae0743", + "reference": "b56450eed252f6801410d810c8e1727224ae0743", + "shasum": "" + }, + "require": { + "php": ">=7.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" + }, + "suggest": { + "ext-intl": "Use Intl for transliterator_transliterate() support" + }, + "type": "library", + "autoload": { + "psr-4": { + "voku\\": "src/voku/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lars Moelleken", + "homepage": "http://www.moelleken.org/" + } + ], + "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", + "homepage": "https://github.com/voku/portable-ascii", + "keywords": [ + "ascii", + "clean", + "php" + ], + "support": { + "issues": "https://github.com/voku/portable-ascii/issues", + "source": "https://github.com/voku/portable-ascii/tree/2.0.1" + }, + "funding": [ + { + "url": "https://www.paypal.me/moelleken", + "type": "custom" + }, + { + "url": "https://github.com/voku", + "type": "github" + }, + { + "url": "https://opencollective.com/portable-ascii", + "type": "open_collective" + }, + { + "url": "https://www.patreon.com/voku", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii", + "type": "tidelift" + } + ], + "time": "2022-03-08T17:03:00+00:00" } ], "packages-dev": [ diff --git a/src/Php/StrToSlug.php b/src/Php/StrToSlug.php new file mode 100644 index 0000000..f96c99d --- /dev/null +++ b/src/Php/StrToSlug.php @@ -0,0 +1,82 @@ + $replacements + */ + public static function fromString( + string $string, + string $separator = '-', + string $language = 'en', + array $replacements = ['@' => 'at'] + ): string { + $instance = new self(); + return $instance($string, $separator, $language, $replacements); + } + + /** + * @param array $replacements + */ + public function __invoke( + string $string, + string $separator = '-', + string $language = 'en', + array $replacements = ['@' => 'at'] + ): string { + $string = ASCII::to_ascii($string, $language); // @phpstan-ignore-line + + // Convert all dashes/underscores into separator + $flip = $separator === '-' ? '_' : '-'; + + $string = preg_replace( + '![' . preg_quote($flip) . ']+!u', + $separator, + $string + ); + + if ($string == null) { + return ''; + } + + // Replace dictionary words + foreach ($replacements as $key => $value) { + $replacements[$key] = $separator . $value . $separator; + } + + $string = str_replace( + array_keys($replacements), + array_values($replacements), + $string + ); + + // Remove all characters that are not the separator, letters, numbers, or whitespace + $string = preg_replace( + '![^' . preg_quote($separator) . '\pL\pN\s]+!u', + '', + mb_strtolower($string, 'UTF-8') + ); + + if ($string == null) { + return ''; + } + + // Replace all separator characters and whitespace by a single separator + $string = preg_replace( + '![' . preg_quote($separator) . '\s]+!u', + $separator, + $string + ); + + if ($string == null) { + return ''; + } + + return trim($string, $separator); + } +} diff --git a/tests/Php/StrToSlugTest.php b/tests/Php/StrToSlugTest.php new file mode 100644 index 0000000..10b9cb9 --- /dev/null +++ b/tests/Php/StrToSlugTest.php @@ -0,0 +1,31 @@ +assertSame($expected, $result); + + $obj = new StrToSlug(); + + $result = $obj($base); + + $this->assertSame($expected, $result); + } +}