Laravel generate slug before save

You could use this package which I use https://github.com/cviebrock/eloquent-sluggable or check how it applies an observer on the model saving and how it generates a unique Slug, then do the same.


One way to accomplish this would be to hook into model events. In this instance, we want to generate a slug upon creating.

/**
 * Laravel provides a boot method which is 'a convenient place to register your event bindings.'
 * See: https://laravel.com/docs/4.2/eloquent#model-events
 */
public static function boot()
{
    parent::boot();

    // registering a callback to be executed upon the creation of an activity AR
    static::creating(function($activity) {

        // produce a slug based on the activity title
        $slug = \Str::slug($news->title);

        // check to see if any other slugs exist that are the same & count them
        $count = static::whereRaw("slug RLIKE '^{$slug}(-[0-9]+)?$'")->count();

        // if other slugs exist that are the same, append the count to the slug
        $activity->slug = $count ? "{$slug}-{$count}" : $slug;

    });

}

You will also need to add the following to your applications list of aliases (app.php):

'Str' => Illuminate\Support\Str::class,

You got 2 ways:

1. Add localy in your controller method this line:

$request['slug'] = Str::slug($request->title);

Example:

//use Illuminate\Support\Str;

public function store(Request $request)
{
    $request['slug'] = Str::slug($request->title);

    auth()->user()->question()->create($request->all());
    return response('Created!',Response::HTTP_CREATED);
}

2. Add it in your model to check it every save in db

//use Illuminate\Support\Str;

protected static function boot() {
    parent::boot();

    static::creating(function ($question) {
        $question->slug = Str::slug($question->title);
    });
}

Example:

<?php

namespace App\Model;

use Illuminate\Database\Eloquent\Model;
use App\User;
use Illuminate\Support\Str;

class Question extends Model
{
    protected static function boot() {
        parent::boot();

        static::creating(function ($question) {
            $question->slug = Str::slug($question->title);
        });
    }

//The rest of methods

In each way you have to add this code before class declaration:

use Illuminate\Support\Str;

I believe this isn't working because you aren't trying to set a slug attribute so that function never gets hit.

I'd suggest setting $this->attributes['slug'] = ... in your setTitleAttribute() function so it runs whenever you set a title.

Otherwise, another solution would be to create an event on save for your model which would set it there.

Edit: According to comments, it's also necessary to actually set the title attribute in this function as well...

public function setTitleAttribute($value)
{
    $this->attributes['title'] = $value;
    $this->attributes['slug'] = str_slug($value);
}