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

雨燕双飞 提交于 2019-12-05 12:11:13
www.example.com/John-Doe

www.example.com/Mary-Smith

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.

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

Look for example at your profile link at Stack Overflow:

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

It's not http://stackoverflow.com/black-room-boy and not even http://stackoverflow.com/users/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 has built-in behavior for this, it's called SluggableBehavior.

Attach it to your model:

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

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

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

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

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

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

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

Personally I don't like this approach.

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',

In 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.');
    }
}

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.

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.

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.');
    }
}

And actionView() like so:

public function actionView($id, $slug = null)
{
    $model = $this->findModel($id);
    if ($slug != $model->slug) {
        return $this->redirect(['profile/view', ['id' => $id, 'slug' => $model->slug]]);
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!