coyote6/laravel-str

Extends Laravel's Str Facade with new methods.

Maintainers

Package info

github.com/Coyote6/laravel-str

Homepage

pkg:composer/coyote6/laravel-str

Transparency log

Statistics

Installs: 7

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-08-12 14:18 UTC

This package is auto-updated.

Last update: 2026-08-12 14:21:41 UTC


README

Latest Version on Packagist Tests License

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

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 means Str::isKebab('a_kebab_like_string') and Str::isKebab('a--kebab--like--string') both return true, 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, use Str::isPureKebab(). If you want to require exactly one canonical spelling, use Str::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: $normalize was only added to Str::studly() (and therefore isStudly()/isPascal()) in illuminate/support v13.12.0. See the note on isStudly() — the same runtime guard applies here since isPascal just calls isStudly under 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: $dictionary is accepted and forwarded for signature completeness, but it can't change the boolean result in practice — its keys (like @) never survive Str::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 means Str::isSnake('a-snakelike-string') and Str::isSnake('a__snakelike__string') both return true, 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, use Str::isPureSnake(). If you want to require exactly one canonical spelling, use Str::isStrictSnake().

isSnake also accepts a second $delimiter argument, mirroring Str::snake()'s own $delimiter argument:

Str::isSnake('a-snake-case', '-');

// true

Note: unlike $language on isSlug, $delimiter is 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: $normalize was only added to Str::studly() in a recent illuminate/support release. isStudly() checks at runtime whether the installed version supports it (via reflection) and throws a RuntimeException if $normalize is 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)