Laravel - 如何从文章标题中正确生成独特的 slug?
Laravel - How to properly generate unique slugs from article titles?
我需要根据文章标题生成独特的 slug。对于匹配的 slug,我想在末尾附加一个数字以使它们独一无二。我根据周围发现的其他工作制作了此功能:
static function slugify($title)
{
$slug = str_slug($title, '-');
//THIS IS THE PROBLEMATIC LINE:
$common = Article::whereRaw("slug RLIKE '^{$slug}(-[0-9]+)?$'")->orderBy('slug', 'desc')->get();
$count = count($common);
if( $count > 0 ){
$last = $common[0];
$broken = explode('-', $last->slug);
$num = $broken[count($broken)-1];
$num = intval($num) + 1;
return $slug.'-'.$num;
} else
return $slug.'-1';
}
问题:
如您所见,我尝试使用 Laravel 的 str_slug 函数生成新的 slug,该函数会将字符串转换为 slug 形式。然后,我尝试从数据库中查询现有的 slug,将它们降序排列(高 > 低),并从本质上取有序集中最高的一个。
问题是 MySQL 当然将它们排序为字符串,因此 slug-title-9 实际上会被认为高于 slug-title -10 因为它将它们作为字符排序,而不是基于末尾数字的值。我怎样才能使这项工作?有没有办法根据最后一个数字来订购它们,还是我走错了方向?
我想避免的解决方案:
我见过其他实现,其中人们一次查询所有类似的 slug,对它们进行计数,然后将 count+1 附加到新 slug 的末尾。 这很糟糕,因为如果您删除一些文章,总计数会降低,并且新的 slug 可能会与旧的 slug 冲突。
我见过一个实现,其中一个人将 1 附加到 slug 的末尾并检查它是否存在。如果它存在,他们将改为附加 2 并尝试检查它是否存在,直到他们找到例如 slug-title-9 不存在。 IMO 这很糟糕,因为您给数据库带来了不必要的压力。
我需要一个不错的解决方案,因为我正在从事的项目很有可能经常遇到匹配的 slug。
lastInsertId return每个连接的id,意味着并发sql个连接不会相互干扰。
但是,无论您在做什么,lastInsertId() 可能都不是最佳方法。我看到您已经在使用 Eloquent 模型。当在table中创建一个新条目时,那些模型return对应的对象,然后您可以准确地获得该对象的id而不会造成任何混淆。
$article = Article::create(['title' => 'First post', 'content' => '...']);
echo $article->id;
这将始终输出正确的文章 ID,您不必担心实施细节。我看不出在现代 Web 框架中使用 lastInsertId 的充分理由,除了极少数边缘情况。
作为一般规则,尽量避免在您的应用程序中直接处理数据库并使用框架提供的抽象 - 这将使您的代码更易于维护和更容易理解。
P.S。这对您来说可能不重要,但 lastInsertId() 不适用于交易。
你可以用这个方法。这是我用来获得独特的 seo 友好 slug 的一个
我需要根据文章标题生成独特的 slug。对于匹配的 slug,我想在末尾附加一个数字以使它们独一无二。我根据周围发现的其他工作制作了此功能:
static function slugify($title)
{
$slug = str_slug($title, '-');
//THIS IS THE PROBLEMATIC LINE:
$common = Article::whereRaw("slug RLIKE '^{$slug}(-[0-9]+)?$'")->orderBy('slug', 'desc')->get();
$count = count($common);
if( $count > 0 ){
$last = $common[0];
$broken = explode('-', $last->slug);
$num = $broken[count($broken)-1];
$num = intval($num) + 1;
return $slug.'-'.$num;
} else
return $slug.'-1';
}
问题: 如您所见,我尝试使用 Laravel 的 str_slug 函数生成新的 slug,该函数会将字符串转换为 slug 形式。然后,我尝试从数据库中查询现有的 slug,将它们降序排列(高 > 低),并从本质上取有序集中最高的一个。 问题是 MySQL 当然将它们排序为字符串,因此 slug-title-9 实际上会被认为高于 slug-title -10 因为它将它们作为字符排序,而不是基于末尾数字的值。我怎样才能使这项工作?有没有办法根据最后一个数字来订购它们,还是我走错了方向?
我想避免的解决方案:
我见过其他实现,其中人们一次查询所有类似的 slug,对它们进行计数,然后将 count+1 附加到新 slug 的末尾。 这很糟糕,因为如果您删除一些文章,总计数会降低,并且新的 slug 可能会与旧的 slug 冲突。
我见过一个实现,其中一个人将 1 附加到 slug 的末尾并检查它是否存在。如果它存在,他们将改为附加 2 并尝试检查它是否存在,直到他们找到例如 slug-title-9 不存在。 IMO 这很糟糕,因为您给数据库带来了不必要的压力。
我需要一个不错的解决方案,因为我正在从事的项目很有可能经常遇到匹配的 slug。
lastInsertId return每个连接的id,意味着并发sql个连接不会相互干扰。
但是,无论您在做什么,lastInsertId() 可能都不是最佳方法。我看到您已经在使用 Eloquent 模型。当在table中创建一个新条目时,那些模型return对应的对象,然后您可以准确地获得该对象的id而不会造成任何混淆。
$article = Article::create(['title' => 'First post', 'content' => '...']);
echo $article->id;
这将始终输出正确的文章 ID,您不必担心实施细节。我看不出在现代 Web 框架中使用 lastInsertId 的充分理由,除了极少数边缘情况。
作为一般规则,尽量避免在您的应用程序中直接处理数据库并使用框架提供的抽象 - 这将使您的代码更易于维护和更容易理解。
P.S。这对您来说可能不重要,但 lastInsertId() 不适用于交易。
你可以用这个方法。这是我用来获得独特的 seo 友好 slug 的一个