В моей системе пользователи должны иметь свои страницы профиля. Мне просили, чтобы эти страницы отображались в URL-адресе:
www.example.com/John-Doe www.example.com/Mary-Smith
Как достичь этих URL-адресов в yii2? Эти John-Doe и Mary-Smith могут быть именами пользователей или именами пользователей. Например, у меня есть поле в пользовательской таблице с именем «имя», и в нем будут имена «Джон Доу», «Мэри Смит». Обратите внимание, что мне нужны дружественные URL-адреса для SEO с «-» вместо пробелов.
Такие URL-адреса: www.example.com/profile/view?id=1 не являются вариантом.
www.example.com/John-Doe www.example.com/Mary-Smith
Я думаю, что нет нормального способа использования этих URL-адресов, потому что сначала необходимо определить контроллер (в вашем случае это ProfileController
). Из этих URL-адресов это невозможно сделать.
Вторая проблема с указанными вами адресами – уникальность не гарантируется. Что делать, если другой пользователь с именем 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
.
Объединение id
и name
является более распространенным и надежным подходом. Также они могут быть объединены с тире следующим образом: 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); }
Это всего лишь пример создания пользовательского пула. Исправьте его в соответствии с вашими атрибутами атрибутов name
и проверки / фильтрации перед сохранением.
Другой способ достижения уникального URL- адреса – установить свойство $ makeUnique в true
.
Таким образом, в случае существования John-Doe
Доэ, будет сформирован пул John-Doe-1
и т. Д.
Обратите внимание, что вы также можете указать свой собственный уникальный генератор, установив $ 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
достаточно, чтобы найти пользователя. Stack Overflow перенаправляет, если вы получаете доступ с правильным 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]]); } }