Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
155 views
in Technique[技术] by (71.8m points)

php - Yii2: validation errors that are not attribute specific

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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 kartikwidgetsAlertBlock

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 kartikwidgetsAlertBlock;

AlertBlock::widget (
        [
            'useSessionFlash' => false ,
            'type' => AlertBlock::TYPE_GROWL ,
            'alertSettings' => [
                'settings' => [
                    'type' => kartikwidgetsGrowl::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' => kartikwidgetsGrowl::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' => kartikwidgetsGrowl::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' => kartikwidgetsGrowl::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' => kartikwidgetsGrowl::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 />",yiihelpersArrayHelper::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');
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...