我正在构建我的第一个Laravel应用程序。我的帖子属于不同的类别。
我试图为类别制作SEO友好网址/categories/category_name
而不保存' slug'在数据库中。
这是我到目前为止所得到的:
我的分类模型:
class Category extends Model
{
public function posts()
{
return $this->hasMany(Post::class);
}
public function getSlugAttribute(): string
{
return str_slug($this->name);
}
public function getUrlAttribute(): string
{
return action('CategoriesController@index', [$this->id, $this->slug]);
}
}
我的类别控制器
class CategoriesController extends Controller
{
public function index($id, $slug = '')
{
$posts = Category::findOrFail($id)->posts;
return view('index', compact('posts'));
}
}
我的路线:
Route::get('/categories/{slug}', 'CategoriesController@index')->name('category');
使用{{ $post->category->url }}
我得到类似http://localhost/category/1?alpha
的内容,但它可以正常显示相应的帖子。路线返回错误。
我如何乘坐id?
并使路线有效?
提前感谢您的帮助!
答案 0 :(得分:2)
我不认为这是可能的。背后的原因是您需要使用slug搜索类别但不存储在数据库中,因此您需要将slug转换为其原始值。
例如,如果您有一个名为“现代艺术”的类别,则slug看起来像modern-art
。如果您将该slug传递给控制器,则需要将其转换回“Modern art”以便能够按名称检索该类别。但也许真正的名字是“现代艺术”或“现代艺术!”或其他什么。
我建议你把slug存放在数据库中。
答案 1 :(得分:2)
我假设您有一个人类可读的类别名称(来自我的类别),并且您正在将其转换为您的网址中的一个slug(ex my-category)。
这样做的一种天真的方法是尝试反转slug并按名称查找类别,但是有些情况不适用。
class CategoriesController extends Controller
{
public function index($slug)
{
$name = ucwords(str_replace('-', ' ', $slug));
$posts = Category::where('name', '=', $name)->first()->posts;
return view('index', compact('posts'));
}
}
该方法存在的问题是,在将名称转换为slug时会丢失信息,例如,如果正确的类别名称包含连字符,则在转换结果slug时连字符将成为空格。
您可以通过修改路线来以不同的方式处理此问题,而无需存储子弹:
Route::get('/categories/{category}/{slug}', 'CategoriesController@index')->name('category');
在这种情况下,您将传递URL中的ID和slug。您可以从ID中获取类别,也可以使用路径模型绑定自动获取它。这在技术上意味着你可以传递任何字符串作为slug,它仍然可以工作。您可以通过确定实际的slug并在最终用户提供不正确的slug时重定向到规范URL来处理这个问题。
class CategoriesController extends Controller
{
public function index(Category $category, $slug)
{
if(str_slug($category->name) != $slug) {
// Redirect to the canonical URL
}
$posts = $category->posts;
return view('index', compact('posts'));
}
}
保留URL中的ID和slug的好处是您可以免费重定向:如果类别名称更改,新URL将起作用,旧URL将自动重定向到新URL。
旁注:如果您查看其问题的网址,您会发现这是StackOverflow使用的方法。