Laravel在保存前生成slug

kokeuurv  于 2023-05-08  发布在  其他
关注(0)|答案(8)|浏览(155)

我试图学习laravel 5与这个wondefull网站的帮助。对于我的活动模型,我希望在将一个slug保存到数据库之前生成一个slug,因此我创建了以下模型。

<?php namespace App;

use Illuminate\Database\Eloquent\Model;

class Activity extends Model {

    protected $table = 'activitys';

    protected $fillable = [
        'title',
        'text',
        'subtitle'
    ];

    // Here I want to auto generate slug based on the title
    public function setSlugAttribute(){
        $this->attributes['slug'] = str_slug($this->title , "-");
    }
    //    
}

但是当我保存一个对象的帮助下活动模型slug是没有填充,我尝试将其更改为$this->attributes ['title'] =“test”进行测试,但它没有运行。我还尝试在setSlugAttribute()中添加参数$title,$slug,但没有帮助。
我做错了什么,有人能解释一下setSomeAttribute($whyParameterHere)的一些例子中使用的参数吗?

  • 注意:我的数据库中有一个slug字段。*

根据user 3158900的建议,我尝试过:

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

这使我的标题字段为空,但以我想要的方式保存了slug,那么为什么$this->title为空呢?如果我删除$this->title = $title;标题和slug都是空的

igsr9ssn

igsr9ssn1#

我相信这是行不通的,因为你没有试图设置一个slug属性,使函数永远不会被击中。
我建议在你的setTitleAttribute()函数中设置$this->attributes['slug'] = ...,这样每当你设置一个标题时它就会运行。
否则,另一种解决方案是在保存时为模型创建一个事件,将其设置在那里。
编辑:根据评论,还需要在此函数中实际设置title属性...

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

atmip9wb2#

有两种方式:

1.在你的控制器方法中本地添加这行:

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

示例:

//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.将其添加到模型中,每次保存到db时检查

//use Illuminate\Support\Str;

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

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

示例:

<?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

在每种方式中,你都必须在类声明之前添加以下代码:

use Illuminate\Support\Str;
aij0ehis

aij0ehis3#

实现这一点的一种方法是挂钩到模型事件中。在本例中,我们希望在创建时生成一个slug。

/**
 * 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;

    });

}

您还需要将以下内容添加到您的应用程序别名列表(app.php):

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

rbl8hiat4#

你可以使用这个包,我使用https://github.com/cviebrock/eloquent-sluggable,或者检查它如何在模型保存上应用观察者,以及它如何生成一个唯一的Slug,然后做同样的事情。

jslywgbw

jslywgbw5#

您希望在设置标题属性时根据标题设置辅助信息。

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

/// Later that same day...

$activity->title = 'Foo Bar Baz';

echo $activity->slug; // prints foo-bar-baz

另一种方法是使用ModelObserver并侦听saving事件。这将允许您在将模型写入数据库之前生成slug。

class ActivityObserver {

    public function saving($activity) 
    {
        $activity->slug = str_slug($activity->title);
    }
}

在这两种情况下,您可能都希望添加一些逻辑来测试数据库中是否已经存在slug,如果存在,则添加一个递增的数字。也就是说foo-bar-baz-2这个逻辑最安全的地方是ModelObserver,因为它是在写操作之前立即执行的。

j0pj023g

j0pj023g6#

你可以使用这个方法。这是一个我用独特的搜索引擎优化友好蛞蝓。这将在所有Laravel版本中工作。https://stackoverflow.com/a/72137537/7147060

wa7juj8i

wa7juj8i7#

这是一个老帖子,但这是你在寻找现代解决方案时发现的,所以这里是一个现代解决方案:
当使用Laravel ^9.x时,可以使用属性赋值器,并且必须看起来像这样:

use Str;
use Illuminate\Database\Eloquent\Casts\Attribute;

protected function name(): Attribute
{
    return Attribute::make(
        set: fn($value) => ['slug' => Str::slug($value), 'name' => $value]
    );
}

在闭包中用$this->slug设置它是不起作用的,因为结果在合并中消失了。

cx6n0qe3

cx6n0qe38#

你也可以使用观察器生成你的slug,这种方法会让你的控制器和模型看起来很干净
以下是在Laravel中添加观察者的步骤:
您需要做的第一件事是运行observer命令

php artisan make:observer ActivityObserver --model= Activity

然后进入观察者类,默认情况下,可能没有创建方法,但已经创建、更新、删除了等等。
如果您没有看到创建方法,则可以添加它。

app/Observers/ActivityObserver.php

<?php
namespace App\Observers;
use App\Models\Activity;
class ActivityObserver
{
  /**
  * Handle the Activity "creating" event.
  *
  * @param  \App\Models\Activity  $activity
  * @return void
  */
  public function creating(Activity $activity)
  {
   $activity->slug = \Str::slug($activity->title , '_');
  }
  /**
  * Handle the Activity "created" event.
  *
  * @param  \App\Models\Activity  $activity
  * @return void
  */
  public function created(Activity $activity)
  {
  }
  /**
  * Handle the Activity "updated" event.
  *
  * @param  \App\Models\Activity  $activity
  * @return void
  */
  public function updated(Activity $activity)
  {
  }
}
  • 注意:我们使用创建函数,因为我们希望在记录保存之前,而不是在记录保存之后,使用传递的标题自动创建slug。*
  • 如果您想在保存记录后立即执行操作,则必须使用创建的函数。*

下一件事是在 Boot 函数内的提供程序上注册观察者类。

app/Providers/EventServiceProvider.php

<?php
namespace App\Providers;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
use App\Observers\ActivityObserver;
use App\Models\Activity;
class EventServiceProvider extends ServiceProvider
{
  /**
  * The event listener mappings for the application.
  *
  * @var array
  */
  protected $listen = [
  Registered::class => [
   SendEmailVerificationNotification::class,
  ],
  ];
  /**
  * Register any events for your application.
  *
  * @return void
  */
  public function boot()
  {
    Activity::observe(ActivityObserver::class);
  }
}

使用上面的代码,每当创建活动时,都会自动创建slug。
通过这样做,你的代码会更干净,因为你不需要向你的控制器或模型添加任何东西,但是你应该通过向你的模型添加下面的代码来使slug列在你的模型中是可填充的。

protected $fillable = [
    'slug',
  ];

相关问题