Yii2: validation errors that are not attribute specific

可紊 提交于 2020-01-07 08:28:12

问题


How do I handle generic validation errors in a Yii2 ActiveRecord model that do not relate to a specific attribute? For example I need to completely prohibit saving a model when a related record/modal has been set to inactive.

I can of course just pick a more or less random attribute and assign the error message to it, but what if the front end form doesn't have that attribute and therefore doesn't show the error? Or even worse, if a scenario later disables validation of that attribute (by not including it in the list of active attributes)?

I can of course return false in beforeSave() or beforeValidate() but then I have no option to specify a message to the user about why the model couldn't be saved, so I really don't like that idea.

Also, I don't want to throw Exceptions, it should just be a soft error message shown to the user.

What is the intended/best approach to handle this?


回答1:


have you looked into flash data they can be used for this purpose to show messages like success, errors and warnings which are or are not specific to your model attributes. It's up to you where you want o use them.

I mostly insert data or save models within transaction block and there when I am saving multiple models I use try catch block to get the errors for any models that occur and use session flash along with ArrayHelper to add errors in the flash message.

For your purpose you can use it the following way.

Set the flash message with

Yii::$app->session->setFlash('error','you are not allowed to perform this message');

and you can get it using the following inside your view

if(Yii::$app->session->hasFlash('error')){

echo Yii::$app->session->gettFlash('error');

}

a more sophisticated approach towards this is \kartik\widgets\AlertBlock

install it using composer

php composer.phar require kartik-v/yii2-widget-alert "*"

Then create a file called alerts.php in layouts folder with the following code

use kartik\widgets\AlertBlock;

AlertBlock::widget (
        [
            'useSessionFlash' => false ,
            'type' => AlertBlock::TYPE_GROWL ,
            'alertSettings' => [
                'settings' => [
                    'type' => kartik\widgets\Growl::TYPE_SUCCESS ,
                    'icon' => 'glyphicon glyphicon-ok-sign' ,
                    'title' => 'Note' ,
                    'showSeparator' => true ,
                    'body' => Yii::$app->session->getFlash ( 'success' )
                ] ,
            ]
] );

AlertBlock::widget (
        [
            'useSessionFlash' => false ,
            'type' => AlertBlock::TYPE_GROWL ,
            'alertSettings' => [
                'settings' => [
                    'type' => kartik\widgets\Growl::TYPE_INFO ,
                    'icon' => 'glyphicon glyphicon-ok-sign' ,
                    'title' => 'Note' ,
                    'showSeparator' => true ,
                    'body' => Yii::$app->session->getFlash ( 'info' )
                ] ,
            ]
] );


AlertBlock::widget (
        [
            'useSessionFlash' => false ,
            'type' => AlertBlock::TYPE_GROWL ,
            'alertSettings' => [
                'settings' => [
                    'type' => kartik\widgets\Growl::TYPE_DANGER ,
                    'icon' => 'glyphicon glyphicon-ok-sign' ,
                    'title' => 'Note' ,
                    'showSeparator' => true ,
                    'body' => Yii::$app->session->getFlash ( 'error' )
                ] ,
            ]
] );


AlertBlock::widget (
        [
            'useSessionFlash' => false ,
            'type' => AlertBlock::TYPE_GROWL ,
            'alertSettings' => [
                'settings' => [
                    'type' => kartik\widgets\Growl::TYPE_DANGER ,
                    'icon' => 'glyphicon glyphicon-ok-sign' ,
                    'title' => 'Note' ,
                    'showSeparator' => true ,
                    'body' => Yii::$app->session->getFlash ( 'danger' )
                ] ,
            ]
] );


AlertBlock::widget (
        [
            'useSessionFlash' => false ,
            'type' => AlertBlock::TYPE_GROWL ,
            'alertSettings' => [
                'settings' => [
                    'type' => kartik\widgets\Growl::TYPE_WARNING ,
                    'icon' => 'glyphicon glyphicon-ok-sign' ,
                    'title' => 'Note' ,
                    'showSeparator' => true ,
                    'body' => Yii::$app->session->getFlash ( 'warning' )
                ] ,
            ]
] );

and then include it in your layout file after $this->beginBody() call like below

<?= Yii::$app->view->renderFile ( '@frontend/views/layouts/alerts.php' ); ?>

then you just have to set the flash message and that is it you won't even have to call getFlash(), the extension will display it automatically you have the following variables available

  • success
  • info
  • danger
  • warning
  • error

set using Yii::$app->session->setFlash('danger','You cannot do this');

EDIT:

Note: Whenever you are redirecting after setting the flash message remember to use return along with redirect() otherwise you may face the problem that the messages are not showing up.

return $this->redirect(['index']);

EDIT 2:

you are trying to add an error message for any particular model that is related to the model currently being saved and you want some soultion that would allow you to throw exceptions and show them in a nicely formatted error message, so the problem you are facing is setting the error message, if i would do it i would use the following approach. Lets say i have a actionTest() like below which is saving the form on submission.

public function actionTest() {

    $model = new Campaign();

    if ($model->load(Yii::$app->request->post())) {

        //start transaction block
        $transaction = Yii::$app->db->beginTransaction();

        try {
            if (!$model->save()) {
                //throw an exception if any errors
                throw new \Exception(implode("<br />",\yii\helpers\ArrayHelper::getColumn($model->errors, 0,false)));
            }
            //commit the transaction if there arent any erorrs to save the record
            $transaction->commit();

        } catch (\Exception $ex) {

            //roll back the transaction if any exception
            $transaction->rollBack();

            //catch the error and display with session flash
            Yii::$app->session->setFlash('danger',$ex->getMessage());
        }
    }
    $this->render('test');
}



回答2:


Another Option then picking a random attribute is to throw exceptions with a specific errorcode. Create a final class with Error Code constants with their messages. Then Put your save function call within a try Catch Block and Catch all specific exceptions and Return the Message to the Frontend



来源:https://stackoverflow.com/questions/48571647/yii2-validation-errors-that-are-not-attribute-specific

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!