coyote6 / laravel-str
Extends Laravel's Str Facade with new methods.
Requires
- php: ^8.1
- illuminate/support: ^10.0|^11.0|^12.0|^13.0
Requires (Dev)
- pestphp/pest: ^5.0
README
Extends Laravel's Str facade with a handful of extra macros: case converters (dot, pureKebab, pureSnake, strictKebab, strictSnake) and a set of is* checks for detecting what case a string is already in.
Requirements
- PHP ^8.1
illuminate/support^10.0 - ^13.0
The floor is illuminate/support 10.0, since that's the first version where Str::slug() accepts both $language and $dictionary (added between v9.0.0 and v10.0.0) — isSlug() mirrors that full signature. Str::kebab() and Str::slug()'s $language argument are both much older (present since at least Laravel 7), so this floor covers them comfortably.
Str::studly()'s $normalize parameter is newer still — not even in v13.0.0, only added in a recent 13.x point release. isStudly() detects at runtime whether the installed version supports it and throws a clear exception if $normalize is requested but unsupported, rather than silently ignoring it (PHP drops unknown trailing arguments instead of erroring).
CI tests PHP 8.4 (the only version pestphp/pest ^5.0 itself can install on) against both the lowest and latest resolvable dependency versions — currently illuminate/support 10.0.0 and whatever the latest 13.x release is, respectively.
Installation
composer require coyote6/laravel-str
The package registers Coyote6\LaravelStr\Providers\StrServiceProvider automatically via Laravel's package discovery — no manual provider registration needed.
Available Methods
- Str::dot()
- Str::isCamel()
- Str::isDot()
- Str::isKebab()
- Str::isLower()
- Str::isPascal()
- Str::isPureKebab()
- Str::isPureSnake()
- Str::isSlug()
- Str::isSnake()
- Str::isStrictKebab()
- Str::isStrictSnake()
- Str::isStudly()
- Str::isTitle()
- Str::isUpper()
- Str::pureKebab()
- Str::pureSnake()
- Str::strictKebab()
- Str::strictSnake()
Methods
Str::dot()
The dot method converts the given string to dot.case. Any run of characters that isn't a letter or number (spaces, punctuation, dashes, underscores, etc.) is collapsed into a single dot, and any leading or trailing dots are trimmed.
use Illuminate\Support\Str; $converted = Str::dot('User - View All'); // user.view.all
This is commonly useful for turning human-readable permission or ability names into machine keys:
Str::dot('Posts - Create Draft'); // posts.create.draft
Str::isCamel()
The isCamel method determines if the given string is already in camelCase.
use Illuminate\Support\Str; Str::isCamel('aCamelLikeString'); // true Str::isCamel('A Camel-like String'); // false
Str::isDot()
The isDot method determines if the given string is already in dot.case. It checks the string against the output of Str::dot().
use Illuminate\Support\Str; Str::isDot('user.view.all'); // true Str::isDot('User - View All'); // false
Str::isKebab()
The isKebab method determines if the given string is already in kebab-case.
use Illuminate\Support\Str; Str::isKebab('a-kebab-like-string'); // true Str::isKebab('A Kebab-like String'); // false
Note:
Str::kebab()only inserts a dash at case-boundary transitions — it never validates or collapses the separators already in the string. That meansStr::isKebab('a_kebab_like_string')andStr::isKebab('a--kebab--like--string')both returntrue, even though neither looks like clean kebab-case. If you do not want to allow underscores in the output and want them to be converted as a separator, useStr::isPureKebab(). If you want to require exactly one canonical spelling, useStr::isStrictKebab().
Str::isLower()
The isLower method determines if the given string is entirely lowercase.
use Illuminate\Support\Str; Str::isLower('a lowercased string'); // true Str::isLower('A Lowercased String'); // false
Str::isPascal()
The isPascal method checks if the given string is already in PascalCase. Str::pascal() is undocumented on laravel.com, but present in the framework source since Laravel 12. It is just an alias to Str::studly(). Rather than call Str::pascal() itself — which doesn't exist at all before Laravel 12 — isPascal calls isStudly(), so it behaves identically, including the second $normalize argument, and works across this package's full supported range.
use Illuminate\Support\Str; Str::isPascal('APascalOrStudlyLikeString'); // true Str::isPascal('A Pascal Or Studly-like String'); // false Str::isPascal('CBOR', true); // false - normalize would rewrite it to 'Cbor' first
Note:
$normalizewas only added toStr::studly()(and thereforeisStudly()/isPascal()) inilluminate/supportv13.12.0. See the note onisStudly()— the same runtime guard applies here sinceisPascaljust callsisStudlyunder the hood.
Str::isPureKebab()
The isPureKebab method determines if the given string is already in kebab-case, using Str::pureKebab() instead of Str::kebab(). Unlike Str::isKebab(), it rejects the wrong separator character (e.g. underscores). Repeated dashes are accepted by default; pass a $consecutiveDashes limit to cap how many are allowed.
use Illuminate\Support\Str; Str::isPureKebab('a-kebab-like-string'); // true Str::isPureKebab('a_kebab_like_string'); // false Str::isPureKebab('a--kebab--like--string'); // true - repeated dashes are fine by default Str::isPureKebab('a--kebab--like--string', 1); // false - exceeds the 1-consecutive-dash limit
Str::isPureSnake()
The isPureSnake method determines if the given string is already in snake_case, using Str::pureSnake() instead of Str::snake(). Unlike Str::isSnake(), it rejects the wrong separator character (e.g. dashes). Repeated underscores are accepted by default; pass a $consecutiveUnderscores limit to cap how many are allowed.
use Illuminate\Support\Str; Str::isPureSnake('a_snakelike_string'); // true Str::isPureSnake('a-snakelike-string'); // false Str::isPureSnake('a__snakelike__string'); // true - repeated underscores are fine by default Str::isPureSnake('a__snakelike__string', 1); // false - exceeds the 1-consecutive-underscore limit
Str::isSlug()
The isSlug method determines if the given string is already a valid slug. It mirrors Str::slug()'s full signature — $charReplacement (separator), $language, and $dictionary — so a check can be run under the same options you'd slugify with.
use Illuminate\Support\Str; Str::isSlug('a-url-slug'); // true Str::isSlug('A Url Slug'); // false Str::isSlug('a_url_slug', '_'); // true
$language can meaningfully flip the result, since it controls whether accented letters get transliterated to ASCII before the slug check runs:
Str::isSlug('café'); // false - 'en' (the default) transliterates é to e, so 'café' no longer matches itself Str::isSlug('café', '-', null); // true - transliteration disabled, so the accented letter passes through unchanged
Note:
$dictionaryis accepted and forwarded for signature completeness, but it can't change the boolean result in practice — its keys (like@) never surviveStr::slug()either way, whether expanded via the dictionary or simply stripped by an empty one, so no input is a valid slug under one dictionary but not another.
Str::isSnake()
The isSnake method determines if the given string is already in snake_case.
use Illuminate\Support\Str; Str::isSnake('a_snakelike_string'); // true Str::isSnake('A Snake-like String'); // false
Note:
Str::snake()only inserts an underscore at case-boundary transitions — it never validates or collapses the separators already in the string. That meansStr::isSnake('a-snakelike-string')andStr::isSnake('a__snakelike__string')both returntrue, even though neither looks like clean snake_case. If you do not want to allow dashes in the output and want them to be converted as a separator, useStr::isPureSnake(). If you want to require exactly one canonical spelling, useStr::isStrictSnake().
isSnake also accepts a second $delimiter argument, mirroring Str::snake()'s own $delimiter argument:
Str::isSnake('a-snake-case', '-'); // true
Note: unlike
$languageonisSlug,$delimiteris accepted for signature completeness but can't change the boolean result —Str::snake()only ever inserts a delimiter at a case boundary, so a string with no case boundary at all is a fixed point for every delimiter, and a string that does have a case boundary can never match itself for any delimiter (the result is always lowercased and always has something inserted). It's forwarded purely so the two signatures stay in sync.
Str::isStrictKebab()
The isStrictKebab method determines if the given string is already in kebab-case, using Str::strictKebab() instead of Str::kebab(). Unlike Str::isKebab() and Str::isPureKebab(), it always collapses repeated separators, so there's exactly one valid spelling for a given name — useful when generating a canonical machine key.
use Illuminate\Support\Str; Str::isStrictKebab('a-kebab-like-string'); // true Str::isStrictKebab('a--kebab--like--string'); // false
Str::isStrictSnake()
The isStrictSnake method determines if the given string is already in snake_case, using Str::strictSnake() instead of Str::snake(). Unlike Str::isSnake() and Str::isPureSnake(), it always collapses repeated separators, so there's exactly one valid spelling for a given name — useful when generating a canonical machine key.
use Illuminate\Support\Str; Str::isStrictSnake('a_snakelike_string'); // true Str::isStrictSnake('a__snakelike__string'); // false
Str::isStudly()
The isStudly method determines if the given string is already in StudlyCase.
use Illuminate\Support\Str; Str::isStudly('AStudlyLikeString'); // true Str::isStudly('A Studly-like String'); // false
isStudly also accepts a second $normalize argument, mirroring Str::studly()'s own $normalize argument. When enabled, a standalone all-caps "word" (an acronym) is lowercased before comparing, so 'CBOR' no longer matches itself — only its normalized form, 'Cbor', does:
Str::isStudly('CBOR'); // true - acronyms are left alone by default Str::isStudly('CBOR', true); // false - normalize would rewrite it to 'Cbor' first Str::isStudly('Cbor', true); // true - already in the normalized shape
Note:
$normalizewas only added toStr::studly()in a recentilluminate/supportrelease.isStudly()checks at runtime whether the installed version supports it (via reflection) and throws aRuntimeExceptionif$normalizeis requested but unsupported, instead of silently comparing against the un-normalized result — PHP doesn't error on unknown trailing arguments, it just drops them, which would otherwise produce a quietly wrong answer.
Str::isTitle()
The isTitle method determines if the given string is already in Title Case.
use Illuminate\Support\Str; Str::isTitle('A Title For Your Article'); // true Str::isTitle('A-Title-for-Your-Article'); // false
Str::isUpper()
The isUpper method determines if the given string is entirely uppercase.
use Illuminate\Support\Str; Str::isUpper('AN UPPERCASED STRING'); // true Str::isUpper('An uppercased string'); // false
Str::pureKebab()
The pureKebab method converts the given string to kebab-case, accepting dashes and underscores as valid input separators. Unlike Str::kebab(), it converts underscores (not just case-boundary transitions), and it groups consecutive uppercase letters (acronyms) into a single word instead of splitting every capital letter — see laravel/framework#47005.
Every individual non-alphanumeric character becomes its own dash, so repeated separators are preserved by default:
use Illuminate\Support\Str; Str::pureKebab('my_example_text'); // my-example-text Str::pureKebab('my_exampleCombined_text'); // my-example-combined-text Str::pureKebab('A - Kebab'); // a---kebab - each of the 3 separator characters (space, dash, space) converts on its own Str::kebab('my_example_text'); // for comparison // my_example_text (Str::kebab() leaves this untouched)
Pass $consecutiveDashes to cap how many consecutive dashes are allowed in the result (default 0 is unlimited):
Str::pureKebab('A - Kebab', 2); // a--kebab
If you want exactly one dash between words regardless of input, use Str::strictKebab() instead.
Str::pureSnake()
The pureSnake method converts the given string to snake_case, accepting underscores and dashes as valid input separators. Unlike Str::snake(), it converts dashes (not just case-boundary transitions), and it groups consecutive uppercase letters (acronyms) into a single word instead of splitting every capital letter — see laravel/framework#47005.
Every individual non-alphanumeric character becomes its own underscore, so repeated separators are preserved by default:
use Illuminate\Support\Str; Str::pureSnake('my-example-text'); // my_example_text Str::pureSnake('LARAVELFramework'); // laravel_framework Str::pureSnake('a - snake'); // a___snake - each of the 3 separator characters (space, dash, space) converts on its own Str::snake('LARAVELFramework'); // for comparison // l_a_r_a_v_e_l_framework (Str::snake() splits every capital letter)
Pass $consecutiveUnderscores to cap how many consecutive underscores are allowed in the result (default 0 is unlimited):
Str::pureSnake('a - snake', 2); // a__snake
If you want exactly one underscore between words regardless of input, use Str::strictSnake() instead.
Str::strictKebab()
The strictKebab method converts the given string to kebab-case with exactly one canonical spelling for a given name — it's a thin wrapper around Str::pureKebab() with $consecutiveDashes locked to 1, so every run of separator characters always collapses down to a single dash. Useful for generating machine keys, where 'a-kebab' and 'a--kebab' should resolve to the same value.
use Illuminate\Support\Str; Str::strictKebab('my_example_text'); // my-example-text Str::strictKebab('A - Kebab'); // a-kebab Str::pureKebab('A - Kebab'); // for comparison // a---kebab (pureKebab() preserves each separator character)
Str::strictSnake()
The strictSnake method converts the given string to snake_case with exactly one canonical spelling for a given name — it's a thin wrapper around Str::pureSnake() with $consecutiveUnderscores locked to 1, so every run of separator characters always collapses down to a single underscore. Useful for generating machine keys, where 'a_snake' and 'a__snake' should resolve to the same value.
use Illuminate\Support\Str; Str::strictSnake('my-example-text'); // my_example_text Str::strictSnake('a - snake'); // a_snake Str::pureSnake('a - snake'); // for comparison // a___snake (pureSnake() preserves each separator character)