在我的系统中,用户需要拥有自己的个人资料页面。我要求这些页面将以这样的方式显示在网址中:
www.example.com/John-Doe
www.example.com/Mary-Smith
如何在yii2中实现这些URL?这些John-Doe和Mary-Smith可以是用户用户名或配置文件名。例如,我在用户表中有一个名为" name"它将保留名字" John Doe"," Mary Smith"。注意我需要SEO友好的URL" - "而不是空格。
这样的网址: www.example.com/profile/view?id=1 不是一种选择。
答案 0 :(得分:9)
www.example.com/John-Doe
www.example.com/Mary-Smith
我认为没有正常的方法来使用这些网址,因为首先需要确定控制器(在你的情况下是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',
],
];
}
对于您的特定网址格式,您还可以指定$value
:
'value' => function ($event) {
return str_replace(' ', '-', $this->name);
}
这只是生成自定义slug的一个示例。在保存之前根据您的name
属性功能和验证/过滤进行更正。
实现唯一网址的另一种方法是将$ensureUnique属性设置为true
。
因此,如果John-Doe
存在John-Doe-1
,则会生成slug等等。
请注意,您还可以通过设置$uniqueSlugGenerator callable。
来指定您自己的唯一生成器我个人不喜欢这种做法。
如果您选择类似于Stack Overflow使用的选项,请将其添加到您的网址规则:
'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]]);
}
}