Skip to main content

Backfilling existing rows

Generate the current slug for a model whose rows predate Polyslug:

php artisan polyslug:backfill "App\Models\Page"

# or for a specific locale
php artisan polyslug:backfill "App\Models\Page" --locale=de

# or dispatch chunked queued jobs for a large table
php artisan polyslug:backfill "App\Models\Page" --queue --chunk=500

The model argument must be an Eloquent model class implementing Sluggable; anything else is an error and a non-zero exit rather than a silent no-op.

Safe to run repeatedly

It streams rows in chunks and skips any row that already has a current slug for the target locale, so a second run costs a pass over the table and changes nothing. That makes it safe to schedule during a migration window, to re-run after a partial failure, or to run again for a second locale.

Without --locale the application locale is used.

Inline or queued

By default the work runs inline in the command, one row at a time, and reports how many slugs it wrote.

With --queue the rows are split into Polyslug\Jobs\BackfillSlugsJob jobs — one per --chunk (1000 rows by default) — dispatched across your queue workers. The command then reports how many jobs it dispatched and returns immediately, which is what you want for a table large enough that a single inline pass would outlive the deploy.

No new dependencies are involved: the job is a plain queued job on your existing connection.

Keep it off the queue your users wait on

A backfill walks the whole table. On the default queue it sits in front of every password reset and order confirmation the application has, for as long as that takes. Send it somewhere your workers treat as bulk:

php artisan polyslug:backfill "App\Models\Page" --queue --on-queue=bulk --on-connection=redis

Or decide it once, in config/polyslug.php:

'backfill' => [
'connection' => 'redis',
'queue' => 'bulk',
'tries' => 3, // a chunk re-queries its own rows, so a retry is safe
'timeout' => 900, // a large chunk needs a timeout that admits it
],

All four default to null, which leaves the framework's own defaults in place — so an installation that names none keeps exactly the behavior it had.

After a backfill

Slugs are written through the normal write path, so everything downstream applies — uniqueness suffixes, the reserved list, and a SlugChanged event per row. If a listener on that event does expensive work (a search reindex, a CDN purge), a large backfill will fan out into it — worth checking before the first run.