使用url创建yii2动态页面:www.example.com/pageName

时间:2015-01-16 14:26:57

标签: php url routing seo yii2

在我的系统中,用户需要拥有自己的个人资料页面。我要求这些页面将以这样的方式显示在网址中:

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 不是一种选择。

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

结合idname是更广泛和更健全的方法。此外,它们可以与破折号结合使用: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]]);
    }
}