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

2022-01-07 00:00:00 url routing php yii2 seo

在我的系统中,用户需要有他们的个人资料页面.我要求这些页面将显示在 url 中,如下所示:

In my system, users need to have their profile pages. It is requested from me that these pages will be displayed in url like this:

www.example.com/John-Doe

www.example.com/Mary-Smith

如何在 yii2 中实现这些 URL?这些 John-Doe 和 Mary-Smith 可以是用户用户名或个人资料名称.例如,我在用户表中有一个名为name"的字段,它将保存名称John Doe"、Mary Smith".请注意,我需要带有-"而不是空格的 SEO 友好 URL.

How to achieve these URLs in yii2 ? These John-Doe and Mary-Smith can be user usernames or profile names. For example I have field in user table called "name" and it will hold names "John Doe", "Mary Smith". Pay attention that I need SEO friendly URLs with "-" instead of blank spaces.

像这样的网址:www.example.com/profile/view?id=1不是一个选项.

URLs like this: www.example.com/profile/view?id=1 are not an option.

推荐答案

www.example.com/John-Doe

www.example.com/Mary-Smith

我认为没有使用这些 url 的正常方法,因为首先需要确定控制器(在您的情况下是 ProfileController).从这些网址是不可能做到的.

I think there is no normal way to use these urls because at first controller (in your case it's ProfileController) needs to be determined. From these urls it's impossible to do.

您提供的网址的第二个问题 - 不保证唯一性.如果另一个名为 John Doe 的用户在网站上注册会怎样?

Second problem with the urls you provided - uniqueness is not guaranteed. What if another user with name John Doe will sign up on site?

以您在 Stack Overflow 上的个人资料链接为例:

Look for example at your profile link at Stack Overflow:

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

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

It's not http://stackoverflow.com/black-room-boy and not even http://stackoverflow.com/users/black-room-boy.

结合 idname 是更广泛和更强大的方法.它们也可以像这样与破折号结合使用:http://stackoverflow.com/users/4395794-black-room-boy

Combining id and name is more widespread and robust approach. Also they can be combined with dash like this: http://stackoverflow.com/users/4395794-black-room-boy

Yii 2 为此具有内置行为,称为 SluggableBehavior.

Yii 2 has built-in behavior for this, it's called SluggableBehavior.

将其附加到您的模型:

use yiiehaviorsSluggableBehavior;

public function behaviors()
{
    return [
        [
            'class' => SluggableBehavior::className(),
            'attribute' => 'name',
            // In case of attribute that contains slug has different name
            // 'slugAttribute' => 'alias',
        ],
    ];
}

对于您的特定 url 格式,您还可以指定 $value:

For your specific url format you can also specify $value:

'value' => function ($event) {
    return str_replace(' ', '-', $this->name);
}

这只是生成自定义 slug 的示例.保存前根据您的 name 属性特征和验证/过滤进行更正.

This is just an example of generating custom slug. Correct it according to your name attribute features and validation / filtering before save.

实现唯一网址的另一种方法是设置 $ensureUnique属性为 true.

Another way of achieving unique url is setting $ensureUnique property to true.

所以如果 John-Doe 存在 John-Doe-1 slug 将被生成等等.

So in case of John-Doe existense John-Doe-1 slug will be generated and so on.

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

Note that you can also specify your own unique generator by setting $uniqueSlugGenerator callable.

我个人不喜欢这种方法.

Personally I don't like this approach.

如果您选择的选项类似于 Stack Overflow 使用的选项,请将其添加到您的 url 规则中:

If you choose the option similar to what Stack Overflow uses, then add this to your url rules:

'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 访问,则堆栈溢出会重定向.当您也完全跳过名称时会发生重定向.

But actually id is enough to find user. Stack Overflow does redirect if you access with correct id but different slug. The redirects occurs when you are completely skipping the name too.

例如 http://stackoverflow.com/users/4395794/black-room-bo 重定向到原始页面 http://stackoverflow.com/users/4395794/black-room-boy 以避免内容重复,这对 SEO 来说是不受欢迎的.

For example http://stackoverflow.com/users/4395794/black-room-bo redirects to original page http://stackoverflow.com/users/4395794/black-room-boy to avoid content duplicates that are undesirable for SEO.

如果您也想使用它,请像这样修改 findModel() 方法:

If you want use this as well, modify findModel() method like so:

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]]);
    }
}

相关文章