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


Creating yii2 dynamic pages with url: www.example.com/pageName

在我的系统中,用户需要拥有他们的个人资料页面。要求我将这些页面显示在 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.

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',
        ],
    ];
}

对于您的特定 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]]);
    }
}