我正在使用Yii2创建博客我希望帖子的网址是帖子的年,月和slug。我有一个slug目前正在努力验证自己,但我不知道如何在产生独特的slug时告诉可缓慢的行为将年份和月份考虑在内。
在我的帖子表中,我有一个slug(基于帖子标题)和published_at datetime。我目前有以下设置,它根据年,月和slug检索给定的帖子。
urlManager有'/<year:\d{4}>/<month:\d{2}>/<slug>' => 'post/view',
,在我的控制器中有以下内容:
public function actionView($year, $month, $slug)
{
$model = $this->findModel($year, $month, $slug);
return $this->render('view', [
'model' => $model,
]);
}
...
protected function findModel($year, $month, $slug)
{
$model = Post::find()
->where(['slug' => $slug])
->andWhere(['FROM_UNIXTIME(publish_at, "%m")' => $month])
->andWhere(['FROM_UNIXTIME(publish_at, "%Y")' => $year])
->one();
if ($model !== null) {
return $model;
} else {
throw new NotFoundHttpException('The requested post does not exist.');
}
}
目前,Post模型仅定义了以下行为。
'SluggableBehavior' => [
'class' => SluggableBehavior::className(),
'attribute' => 'title',
'immutable' => true,
'ensureUnique' => true,
],
如何编辑行为,以便在确定唯一性时评估年,月和slug?
我是否需要将年份和月份存储在数据库中,而不是仅仅将它们从published_at日期时间(我目前在find()期间执行)中动态拉出来?
答案 0 :(得分:0)
我为年和月创建了列,因此不需要动态评估publish_at字段。将年份和月份存储在各自的列中,uniqueValidator
属性在SluggableBehavior上设置如下
'uniqueValidator' => ['targetAttribute' => ['publish_year', 'publish_month', 'slug']],
为targetAttribute
设置uniqueValidator
时,在确定slug是否唯一时,行为将考虑所有三个字段。
如果其他人想要实现类似的东西,以下是使这个解决方案有效的所有各个部分。
这确保了在生成slug时,它还使用publish_year和publish_month字段来评估slug是否是唯一的
public function behaviors()
{
return [
'SluggableBehavior' => [
'class' => SluggableBehavior::className(),
'attribute' => ['title'],
'immutable' => true,
'ensureUnique' => true,
'uniqueValidator' => ['targetAttribute' => ['publish_year', 'publish_month', 'slug']],
],
];
}
以下规则是确保如果用户手动输入一个slug,它仍会针对年份和月份进行唯一性评估
public function rules()
{
return [
....
[['slug'], 'unique', 'targetAttribute' => ['publish_year', 'publish_month', 'slug'],
];
}
我允许用户输入发布日期,并根据他们输入的内容填充年份和月份。这里需要注意的重要一点是,beforeValidate的父实现需要在之后设置这些值,以便在执行sluggableBehavior时设置它们。如果用户没有设置publish_at日期时间,则使用当前时间(用户可以稍后更改,但我们需要对日期做出某种假设,以便我们有一年和一个月进行检查)。
public function beforeValidate()
{
$publish_at = ($this->publish_at) ? $this->publish_at : time();
$this->publish_year = date('Y', $publish_at);
$this->publish_month = date('m', $publish_at);
// Invoke parent implementation
parent::beforeValidate();
return true;
}
urlManager需要以下规则才能将帖子定向到更正控制器/操作
'/<year:\d{4}>/<month:\d{2}>/<slug>' => 'post/view',
最后,控制器需要知道如何处理这些数据才能找到合适的帖子
public function actionView($year, $month, $slug)
{
$model = $this->findModel($year, $month, $slug);
return $this->render('view', [
'model' => $model,
]);
}
这不是制作此功能所需的最后一行代码(例如,显然findModel需要找到具有该年,月和slug的正确帖子,而不仅仅是像往常一样的id)但这应该至少得到当试图完成类似的事情时,有人指出了正确的方向。