1.關於場景(scenarios)這個問題,開始搜了很多文章,看了其實有點容易被誤導,所以我推薦可以的話可以看一看源碼。
2.直接先給結論:
在大多數情況下,是不需要重寫 scenarios() 的。通過配置 rules() 來改變 scenarios() 的返回值,而不是直接手動覆蓋 sceanrios().覆蓋帶來的一個明顯的弊端是:你的精力被分散到了兩個方法內(rules() 和 scenarios()).
3.推薦文章如下:
yiichina.com/question/3042?sort=desc
4.你可以把scenarios源碼複製到子類當中進行修改觀看這個scenarios()是怎麼工作的。
step1.這是我的rules()函數:
public function rules()
{
return [
[['user_id', 'create_time'], 'integer'],
[['content', 'picture_url'], 'string', 'max' => 128],
[['user_id'], 'exist', 'skipOnError' => true, 'targetClass' => User::className(), 'targetAttribute' => ['user_id' => 'id']],
[['imageFile'],'file','skipOnEmpty'=>false,'extensions'=>'png,jpg','on'=>
['create']],
];
}
step2. 我把scenarios()源碼複製到了子類當中,方便修改:class Friend extends \yii\db\ActiveRecord{ };
class Friend extends \yii\db\ActiveRecord
{
/***/
public function scenarios()
{
$scenarios = [self::SCENARIO_DEFAULT => []];
foreach ($this->getValidators() as $validator) {
foreach ($validator->on as $scenario) {
$scenarios[$scenario] = [];
}
foreach ($validator->except as $scenario) {
$scenarios[$scenario] = [];
}
}
$names = array_keys($scenarios);
//這四句是我自己調試的內容
echo "第一步把rules()中所有場景都找出來:";
echo "<pre>";
print_r($names);
echo "<br><br>";
foreach ($this->getValidators() as $validator) {
if (empty($validator->on) && empty($validator->except)) {
foreach ($names as $name) {
foreach ($validator->attributes as $attribute) {
$scenarios[$name][$attribute] = true;
}
}
} elseif (empty($validator->on)) {
foreach ($names as $name) {
if (!in_array($name, $validator->except, true)) {
foreach ($validator->attributes as $attribute) {
$scenarios[$name][$attribute] = true;
}
}
}
} else {
foreach ($validator->on as $name) {
foreach ($validator->attributes as $attribute) {
$scenarios[$name][$attribute] = true;
}
}
}
}
foreach ($scenarios as $scenario => $attributes) {
if (!empty($attributes)) {
$scenarios[$scenario] = array_keys($attributes);
}
}
//這五句是我自己調試的內容
echo "第二步把每個場景的的內容都對應上去:";
echo "<pre>"; //第二步把每個場景的的內容都對應上去
print_r($scenarios);
echo "<br><br>";
exit(0);
return $scenarios;
}
}
結果輸出如下:
雖然代碼裏面有很多個foreach,其實你可以理解爲就幹了上面兩件事。
第一步,找出rules()中所有的場景,也就是'on'=>['場景'],default是默認場景。
第二步,把場景對映的驗證屬性添加到數組裏面;
如果一個屬性,不開啓 on 的話,就默認屬於每一個場景。這句話很重要。你可以發現,上面 imageFile開啓了 'on'=>['create']
所以default場景就不會去驗證imageFile屬性,所以我在創建一條新內容的地方調用create場景:
這時候就回去驗證照片有沒有上傳;
而我更新的時候不設置場景,會採用默認場景,所以你可以發現默認場景裏面不需要驗證imageFile這一項的屬性,所以直接更改文字內容就可以了,不會因爲沒有上傳照片而無法通過驗證。