From e54e345866433a3601bb5dc8186849d51d4e360b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Auswo=CC=88ger?= Date: Fri, 8 Sep 2023 18:06:02 +0200 Subject: [PATCH] Add trimDelimiter option --- CHANGELOG.md | 2 ++ README.md | 10 ++++++++++ src/SlugGenerator.php | 15 ++++++++++++--- src/SlugOptions.php | 24 ++++++++++++++++++++++++ tests/SlugGeneratorTest.php | 15 +++++++++++++++ tests/SlugOptionsTest.php | 14 +++++++++++++- 6 files changed, 76 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4addc28..51342be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] + * Add `trimDelimiter` option. [#36] ## [1.1.1] (2020-10-19) @@ -51,6 +52,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm [1.0.0-alpha2]: https://github.com/ausi/slug-generator/compare/v1.0.0-alpha1...v1.0.0-alpha2 [1.0.0-alpha1]: https://github.com/ausi/slug-generator/commits/v1.0.0-alpha1 +[#36]: https://github.com/ausi/slug-generator/issues/36 [#23]: https://github.com/ausi/slug-generator/issues/23 [#13]: https://github.com/ausi/slug-generator/issues/13 [#11]: https://github.com/ausi/slug-generator/issues/11 diff --git a/README.md b/README.md index 555fd30..c91e3a6 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,16 @@ $generator->generate('Hello World!', ['delimiter' => '_']); // Result: hello_w $generator->generate('Hello World!', ['delimiter' => '%20']); // Result: hello%20world ``` +### `trimDelimiter`, default `true` + +If set to `true` the delimiter will be stripped +from the beginning and the end of the slug. + +```php +$generator->generate('Hello World!'); // Result: hello-world +$generator->generate('Hello World!', ['trimDelimiter' => false]); // Result: hello-world- +``` + ### `validChars`, default `"a-z0-9"` Valid characters that are allowed in the slug. diff --git a/src/SlugGenerator.php b/src/SlugGenerator.php index f660ac3..9ed8abb 100644 --- a/src/SlugGenerator.php +++ b/src/SlugGenerator.php @@ -74,7 +74,7 @@ public function generate(string $text, iterable $options = []): string $options = $this->options->merge($options); if ($options->getValidChars() === '') { - return ''; + return $options->getTrimDelimiter() || $text === '' ? '' : $options->getDelimiter(); } /** @var string $text */ @@ -83,7 +83,12 @@ public function generate(string $text, iterable $options = []): string $text = $this->transform($text, $options->getValidChars(), $options->getTransforms(), $options->getLocale()); $text = $this->removeIgnored($text, $options->getIgnoreChars()); - return $this->replaceWithDelimiter($text, $options->getValidChars(), $options->getDelimiter()); + return $this->replaceWithDelimiter( + $text, + $options->getValidChars(), + $options->getDelimiter(), + $options->getTrimDelimiter() + ); } /** @@ -108,7 +113,7 @@ private function removeIgnored(string $text, string $ignore): string * Replace all invalid characters with a delimiter * and strip the delimiter from the beginning and the end. */ - private function replaceWithDelimiter(string $text, string $valid, string $delimiter): string + private function replaceWithDelimiter(string $text, string $valid, string $delimiter, bool $trimDelimiter): string { $quoted = preg_quote($delimiter); @@ -123,6 +128,10 @@ private function replaceWithDelimiter(string $text, string $valid, string $delim throw new \RuntimeException(sprintf('Failed to replace "%s" with "%s" in "%s".', '(?:[^'.$valid.']|'.$quoted.')+', $delimiter, $text)); } + if (!$trimDelimiter) { + return $replaced; + } + // Remove delimiters from the beginning and the end $removed = preg_replace('(^(?:'.$quoted.')+|(?:'.$quoted.')+$)us', '', $replaced); diff --git a/src/SlugOptions.php b/src/SlugOptions.php index ae1c78a..702b640 100644 --- a/src/SlugOptions.php +++ b/src/SlugOptions.php @@ -27,6 +27,11 @@ class SlugOptions implements \IteratorAggregate */ private $delimiter = '-'; + /** + * @var bool + */ + private $trimDelimiter = true; + /** * @var string */ @@ -126,6 +131,24 @@ public function getDelimiter(): string return $this->delimiter; } + /** + * @param bool $trimDelimiter True if the delimiter should be trimmed from the beginning and end of the slug + * + * @return static + */ + public function setTrimDelimiter(bool $trimDelimiter): self + { + $this->trimDelimiter = $trimDelimiter; + $this->setOptions['trimDelimiter'] = null; + + return $this; + } + + public function getTrimDelimiter(): bool + { + return $this->trimDelimiter; + } + /** * @param string $chars Character range for allowed characters * in the form of a regular expression character set, @@ -294,6 +317,7 @@ private function assertOptionName(string $option): void { static $validOptions = [ 'delimiter', + 'trimDelimiter', 'validChars', 'ignoreChars', 'locale', diff --git a/tests/SlugGeneratorTest.php b/tests/SlugGeneratorTest.php index 94003fe..a2581db 100644 --- a/tests/SlugGeneratorTest.php +++ b/tests/SlugGeneratorTest.php @@ -241,6 +241,21 @@ public function getGenerate(): array '', ['validChars' => ''], ], + [ + '-A B C-', + '-', + ['validChars' => '-', 'trimDelimiter' => false], + ], + [ + '-A B C-', + '-a-b-c-', + ['validChars' => 'a-z', 'trimDelimiter' => false], + ], + [ + '- -A B C- -', + '...a...b...c...', + ['validChars' => 'a-z', 'delimiter' => '...', 'trimDelimiter' => false], + ], [ 'contextöcontextöcontext', 'CONTEXTöCONTEXTöCONTEXT', diff --git a/tests/SlugOptionsTest.php b/tests/SlugOptionsTest.php index 2f7fc62..7e0b799 100644 --- a/tests/SlugOptionsTest.php +++ b/tests/SlugOptionsTest.php @@ -35,11 +35,13 @@ public function testMerge(): void $this->assertSame('x', $options->getDelimiter()); $this->assertSame('a-z0-9', $options->getValidChars()); - $options2 = $options->merge(new SlugOptions(['validChars' => 'x'])); + $options2 = $options->merge(new SlugOptions(['validChars' => 'x', 'trimDelimiter' => false])); $this->assertSame('x', $options->getDelimiter()); $this->assertSame('a-z0-9', $options->getValidChars()); + $this->assertTrue($options->getTrimDelimiter()); $this->assertSame('x', $options2->getDelimiter()); $this->assertSame('x', $options2->getValidChars()); + $this->assertFalse($options2->getTrimDelimiter()); } public function testGetIterator(): void @@ -69,6 +71,16 @@ public function testSetDelimiter(): void $this->assertSame('xx', $options->setDelimiter('xx')->getDelimiter()); } + public function testSetTrimDelimiter(): void + { + $options = new SlugOptions; + $this->assertTrue($options->getTrimDelimiter()); + + $options = new SlugOptions(['trimDelimiter' => false]); + $this->assertFalse($options->getTrimDelimiter()); + $this->assertTrue($options->setTrimDelimiter(true)->getTrimDelimiter()); + } + public function testSetValidChars(): void { $options = new SlugOptions;