使用 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中实现这些URL?这些 John-Doe 和 Mary-Smith 可以是用户用户名或个人资料名称。例如,我在用户 table 中有一个名为 "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)。从这些 urls 这是不可能做到的。

您提供的 url 的第二个问题 - 不保证唯一性。如果另一个名为 John Doe 的用户将在网站上注册怎么办?

例如,查看您在 Stack Overflow 上的个人资料 link:

http://whosebug.com/users/4395794/black-room-boy

不是 http://whosebug.com/black-room-boy 甚至 http://whosebug.com/users/black-room-boy

结合使用 idname 是更广泛和更可靠的方法。它们也可以像这样与破折号结合使用:http://whosebug.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 existense John-Doe-1 将生成 slug 等等。

请注意,您还可以通过设置 $uniqueSlugGenerator 可调用来指定您自己的唯一生成器。

我个人不喜欢这种方法。

如果您选择类似于 Stack Overflow 使用的选项,请将其添加到您的 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 进行访问,Stack Overflow 会重定向。当您也完全跳过名称时会发生重定向。

例如 http://whosebug.com/users/4395794/black-room-bo 重定向到原始页面 http://whosebug.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]]);
    }
}