如何获得其他时间相同的标题后的独特slug?

时间:2018-01-15 13:34:50

标签: laravel

我尝试过以下代码。

 $post->title = $request->title;
        $post->body = $request->body;
        $post->slug  = str_slug($post->title,'%');

代码运行良好但现在我的帖子具有相同的标题,因此它的抛出错误因为它在db中设置为唯一。 有什么方法可以得到另一个slug?

5 个答案:

答案 0 :(得分:3)

如果您正面临一个slug colision,在这种情况下,最好的方法是在最后一个例子中添加一个额外的整数:

mysite.dev/my-post
mysite.dev/my-post-1

为此,您可以使用check this生成slug

如果你想自己做,那么在模型中添加slugattribute

public function setSlugAttribute($value) {

    if (static::whereSlug($slug = str_slug($value))->exists()) {

        $slug = $this->incrementSlug($slug);
    }

    $this->attributes['slug'] = $slug;
}

因此setSlugAtrribute将始终检查给定模型的slug是否存在,如果是,那么它将按照我上面的意思递增slug,只需调用以下方法。

public function incrementSlug($slug) {

    $original = $slug;

    $count = 2;

    while (static::whereSlug($slug)->exists()) {

        $slug = "{$original}-" . $count++;
    }

    return $slug;

}

基本上我们总是检查数据库中是否存在slug,如果是,那么我们使用一个访问器来通过最后添加一个整数来改变slug,这样你就永远不会遇到slug重复问题。

答案 1 :(得分:0)

创建我们自己的函数,该函数可从任何标题生成唯一的子弹。看一下代码,这很清楚。

来自this link的参考代码。


<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Product;
class ProductController extends Controller
{
    public function store(Request $request)
    {
        $product = new Product;
        $product->title = $request->title;
        $product->slug = $this->createSlug($request->title);
        $product->save();
    }
    public function createSlug($title, $id = 0)
    {
        $slug = str_slug($title);
        $allSlugs = $this->getRelatedSlugs($slug, $id);
        if (! $allSlugs->contains('slug', $slug)){
            return $slug;
        }

        $i = 1;
        $is_contain = true;
        do {
            $newSlug = $slug . '-' . $i;
            if (!$allSlugs->contains('slug', $newSlug)) {
                $is_contain = false;
                return $newSlug;
            }
            $i++;
        } while ($is_contain);
    }
    protected function getRelatedSlugs($slug, $id = 0)
    {
        return Product::select('slug')->where('slug', 'like', $slug.'%')
        ->where('id', '<>', $id)
        ->get();
    }
}

最后。我们在Laravel中创建了一个独特的子弹。

localhost:8000/kwee-dev
localhost:8000/kwee-dev-1

答案 2 :(得分:0)

我遇到了同样的问题,那就是我的解决方案:

  1. 我会检查数据库中是否有相同的标题。
  2. 如果是,则返回具有相同标题的行
  3. 将返回值增加1
  4. 如果没有标题相同的帖子/列表,并且不会执行检查
/**
     * Create a slug from title
     * @param  string $title
     * @return string $slug
     */
    protected function createSlug(string $title): string
    {

        $slugsFound = $this->getSlugs($title);
        $counter = 0;
        $counter += $slugsFound;

        $slug = str_slug($title, $separator = "-", app()->getLocale());

        if ($counter) {
            $slug = $slug . '-' . $counter;
        }
        return $slug;
    }

    /**
     * Find same listing with same title
     * @param  string $title
     * @return int $total
     */
    protected function getSlugs($title): int
    {
        return Listing::select()->where('title', 'like', $title)->count();
    }

答案 3 :(得分:0)

使用以下两个软件包之一,只需几行代码即可轻松解决此常见问题:

Laravel容易

https://github.com/spatie/laravel-sluggable

只需安装运行的软件包即可:

composer require spatie/laravel-sluggable

然后将以下代码添加到您的模型中:

use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;

class Post extends Model
{
    use HasSlug;

    public function getSlugOptions() : SlugOptions
    {
        return SlugOptions::create()
            ->generateSlugsFrom('title')
            ->saveSlugsTo('slug');
    }

或替代:

口才很慢

https://github.com/cviebrock/eloquent-sluggable

您可以输入以下内容进行安装:

composer require cviebrock/eloquent-sluggable

然后添加到您的模型中:

use Cviebrock\EloquentSluggable\Sluggable;

class Post extends Model
{
    use Sluggable;

    /**
     * Return the sluggable configuration array for this model.
     *
     * @return array
     */
    public function sluggable()
    {
        return [
            'slug' => [
                'source' => 'title'
            ]
        ];
    }
}

答案 4 :(得分:0)

几个月前,我搜索了自动化 slug 创建的便捷解决方案,并发现了 Taner Fejzulovski 使用 Laravel 的 Mutator 做出的有趣决定。

但是,当我开始检查和调试时,我明白代码还没有完全完成。 因此,我根据自己的需要和对检查的理解对其进行了更新和重构。

我使用了递归方法来完整检查数据库中先前创建的 slug。也许它对你和其他人也有用!

    /**
     * Set the proper slug attribute.
     *
     * @param string $value
     * @return mixed
     */
    public function setSlugAttribute($value)
    {
        if(static::whereSlug($slug = Str::slug($value))->exists())
        {
            if(static::whereSlug($slug)->get('id')->first()->id !== $this->id){
                $slug = $this->incrementSlug($slug);

                if(static::whereSlug($slug)->exists()){
                    return $this->setSlugAttribute($slug);
                }
            }
        }

        $this->attributes['slug'] = $slug;
    }

    /**
     * Increment slug
     *
     * @param   string $slug
     * @return  string
     **/
    public function incrementSlug($slug)
    {
        // Get the slug of the created post earlier
        $max = static::whereSlug($slug)->latest('id')->value('slug');

        if (is_numeric($max[-1])) {
            return preg_replace_callback('/(\d+)$/', function ($matches) {
                return $matches[1] + 1;
            }, $max);
        }

        return "{$slug}-2";
    }