在我的系统中,用户需要拥有他们的个人资料页面。要求我将这些页面显示在 url 中,如下所示:
www.example.com/John-Doe
www.example.com/Mary-Smith
如何在 yii2 中实现这些网址?这些 John-Doe 和 Mary-Smith 可以是用户名或个人资料名称。例如,我在用户表中有一个名为"name"的字段,它将包含名称"John Doe","Mary Smith"。请注意,我需要带有"-"而不是空格的 SEO 友好 URL。
像这样的网址: www.example.com/profile/view?id=1不是一种选择。
www.example.com/John-Doe
www.example.com/Mary-Smith
我认为没有使用这些 url 的正常方法,因为首先需要确定控制器(在您的情况下是ProfileController
)。从这些网址中,这是不可能做到的。
您提供的网址的第二个问题 - 不保证唯一性。如果另一个名为 John Doe
的用户将在网站上注册怎么办?
例如,在Stack Overflow的个人资料链接中查找:
http://stackoverflow.com/users/4395794/black-room-boy
它不是http://stackoverflow.com/black-room-boy
,甚至不是http://stackoverflow.com/users/black-room-boy
.
将id
和name
结合起来是更广泛和更稳健的方法。它们也可以像这样与破折号组合:http://stackoverflow.com/users/4395794-black-room-boy
Yii 2 对此有内置的行为,它被称为 SluggableBehavior。
将其附加到模型:
use yii'behaviors'SluggableBehavior;
public function behaviors()
{
return [
[
'class' => SluggableBehavior::className(),
'attribute' => 'name',
// In case of attribute that contains slug has different name
// 'slugAttribute' => 'alias',
],
];
}
对于您的特定 url 格式,您还可以指定$value
:
'value' => function ($event) {
return str_replace(' ', '-', $this->name);
}
这只是生成自定义 slug 的一个示例。在保存之前,请根据您的name
属性要素和验证/过滤进行更正。
实现唯一 url 的另一种方法是将$ensureUnique属性设置为 true
。
因此,如果存在John-Doe
John-Doe-1
将生成 slug,依此类推。
请注意,您还可以通过设置可调用$uniqueSlugGenerator来指定自己唯一的生成器。
就个人而言,我不喜欢这种方法。
如果您选择的选项类似于堆栈溢出使用的选项,请将其添加到您的 url 规则中:
'profile/<id:'d+>/<slug:[-a-zA-Z]+>' => 'profile/view',
在ProfileController
:
public function actionView($id, $slug)
{
$model = $this->findModel($id, $slug);
...
}
protected function findModel($id, $slug)
{
if (($model = User::findOne(['id' => $id, 'name' => $slug]) !== null) {
return $model;
} else {
throw new NotFoundHttpException('User was not found.');
}
}
但实际上id
就足以找到用户。堆栈溢出确实重定向,如果您使用正确的id
但不同的slug
进行访问。当您完全跳过名称时,也会发生重定向。
例如,http://stackoverflow.com/users/4395794/black-room-bo
重定向到原始页面http://stackoverflow.com/users/4395794/black-room-boy
以避免 SEO 不希望的内容重复。
如果您也想使用它,请像这样修改findModel()
方法:
protected function findModel($id)
{
if (($model = User::findOne($id) !== null) {
return $model;
} else {
throw new NotFoundHttpException('User was not found.');
}
}
actionView()
是这样的:
public function actionView($id, $slug = null)
{
$model = $this->findModel($id);
if ($slug != $model->slug) {
return $this->redirect(['profile/view', ['id' => $id, 'slug' => $model->slug]]);
}
}