简体   繁体   中英

Yii2 allow post only data from model's scenario

I have ActiveRecord model User with this scenarios() method:

public function scenarios()
{   
    $scenarios = parent::scenarios();
    $scenarios['create'] = ['username', 'email', 'password']; 
    return $scenarios;
}

Also, this model has rules() method:

public function rules()
{
    return [
        ['username', 'required', 'on' => ['create']], 
        ['username', 'string', 'min' => 3, 'max' => 55],
        ['email', 'required', 'on' => ['create']],
        ['email', 'email', 'on' => ['create']],
        ['password', 'required', 'on' => ['create']],
        ['password', 'string', 'min' => 6, 'on' => ['create']],
    ];
}

I want to deny post all data with keys that are not included in the "create" scenario (allow receive only data with keys: 'username', 'email', 'password' ).

Right now i do it in UserController so:

...  
$activeAttributes = $model->activeAttributes();
$postParams = Yii::$app->getRequest()->getBodyParams();

foreach($postParams as $key=>$value){
  if(!(in_array($key, $activeAttributes))) throw new \yii\web\HttpException(404, 'Invalid attribute:' . $key);
}
...

Is there a more elegant way to do this?

I don't understand what's the advantage of that.

The user can post any data, but if it's strictly validated you have nothing to worry about.

If you nevertheless want to use it, your solution is OK, here are several remarks though:

  • For getting $_POST data use high level method \\Yii::$app->request->post() (it can return either all data, subarray or specific value). getBodyParams() is called inside of it.

  • 404 Page Not Found Exception is not suitable for this situation. I think 400 Bad Request fits more.

  • It's better to use built-in Yii2 wrappers for common exceptions, such as BadRequestHttpException . This way you don't worry about its code and thinking more about its meaning.

  • activeAttributes() returns attribute names without values so you don't have to break iterated element in foreach into $key and $value .

So the code after these changes can be something like this:

$model = new YourModel(['scenario' => YourModel::SCENARIO_CREATE]);
$activeAttributes = $model->activeAttributes();

foreach (\Yii::$app->requst->post() as $attribute => $value) {
    if (!in_array($attribute, $activeAttributes)) {
        throw new BadRequestHttpException("Invalid attribute: $attribute.");
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM