Validating common error (not related to particular attribute)

Hi there!

I need to validate a set of attributes and display a common error (not related to particular attribute) as described here

I have created a class that extends yii\validators\Validator in which I need to validate a date composed from multilple attributes, in my validateAttribute($model, $attribute) function I created the date and validate in this way:

        $date = "$year-$month-$day";
        $dateValidator = new DateValidator();
        $dateValidator->format = 'php:Y-m-d';
        if(!$dateValidator->validate($date)){
            $model->addError('*', "Date $date is not a valid date");
        }

In my view I display the geral error in this way (I am using twig view template engine):

<div class="col-md-12 col-sm-12 col-xs-12 form-group">
      {{ form.errorSummary(model) | raw }}
  </div>

However when my date is validated the server raise an exception

name: Exception
message: Attribute name must contain word characters only.
code: 0
type: yii\base\InvalidArgumentException
file: /var/www/apache/plurima.snake.lappi.virt/vendor/yiisoft/yii2/helpers/BaseHtml.php
line: 2240

It seems like the * character in the addError function are not recognized as a general error and Yii2 complains because the attribute names cannot contain special characters… what am I doing wrong?

Thanks everybody for the help

The first parameter of addError must be the name of an attribute, and * is not considered to be a valid attribute name. You have to select one of the attributes that make up the date, i.e., year, month or day. I think day would be a decent selection for it.

Otherwise you could define an additional virtual attribute of date that will receive the error message. In that case you would need to tweak your form a bit to include that virtual attribute.

P.S.

This document describes the issue in detail. Please check it.

Custom validator for multiple attributes

Thanks for your reply, I’ll take a look :grinning:

I’m sorry. This is not correct. You can use * as a valid attribute name.

https://www.yiiframework.com/doc/guide/2.0/en/input-validation#multiple-attributes-errors

So, your original code should work as expected. I don’t know what’s wrong with it.

The exception is thrown in BaseHtml::getAttributeValue($model, $attribute), and I wonder where this method is called from. Could you check the stack trace?

It seems like it comes from yii\widgets\ActiveForm::validate … here is the exception and the stack trace

Exception 'yii\base\InvalidArgumentException' with message 'Attribute name must contain word characters only.' 

in /var/www/apache/plurima.snake.lappi.virt/vendor/yiisoft/yii2/helpers/BaseHtml.php:2240

Stack trace:
#0 /var/www/apache/plurima.snake.lappi.virt/vendor/yiisoft/yii2/helpers/BaseHtml.php(2266): yii\helpers\BaseHtml::getInputName(Object(app\models\AnalisiChangeDatesForm), '*')
#1 /var/www/apache/plurima.snake.lappi.virt/vendor/yiisoft/yii2/widgets/ActiveForm.php(420): yii\helpers\BaseHtml::getInputId(Object(app\models\AnalisiChangeDatesForm), '*')
#2 /var/www/apache/plurima.snake.lappi.virt/controllers/AnalisiController.php(258): yii\widgets\ActiveForm::validate(Object(app\models\AnalisiChangeDatesForm))
#3 [internal function]: app\controllers\AnalisiController->actionValidateDates('[{"id":154,"id_...')
#4 /var/www/apache/plurima.snake.lappi.virt/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)
#5 /var/www/apache/plurima.snake.lappi.virt/vendor/yiisoft/yii2/base/Controller.php(157): yii\base\InlineAction->runWithParams(Array)
#6 /var/www/apache/plurima.snake.lappi.virt/vendor/yiisoft/yii2/base/Module.php(528): yii\base\Controller->runAction('validate-dates', Array)
#7 /var/www/apache/plurima.snake.lappi.virt/vendor/yiisoft/yii2/web/Application.php(103): yii\base\Module->runAction('analisi/validat...', Array)
#8 /var/www/apache/plurima.snake.lappi.virt/vendor/yiisoft/yii2/base/Application.php(386): yii\web\Application->handleRequest(Object(yii\web\Request))
#9 /var/www/apache/plurima.snake.lappi.virt/web/index.php(19): yii\base\Application->run()
#10 {main}

This is the controller method that perform the AJAX validation of the form maybe is something wrong here…

public function actionValidateDates($ids) {
    $model = new \app\models\AnalisiChangeDatesForm(['ids' => json_decode($ids)]);
    if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
        Yii::$app->response->format = Response::FORMAT_JSON;
        return ActiveForm::validate($model);
    }
}

I believe the case of a generic error, not associated with any model attribute, is not taken into consideration in the method ActiveForm::validate()

public static function validate($model, $attributes = null)
{
    $result = [];
    if ($attributes instanceof Model) {
        // validating multiple models
        $models = func_get_args();
        $attributes = null;
    } else {
        $models = [$model];
    }
    /* @var $model Model */
    foreach ($models as $model) {
        $model->validate($attributes);
        foreach ($model->getErrors() as $attribute => $errors) {
            $result[Html::getInputId($model, $attribute)] = $errors;
        }
    }

    return $result;
}

I see. The call of Html::getInputId can throw an exception when the model has a validation error whose $attribute is *.
I think you should report an issue.

In the meantime, you might try using some non-existing attribute name in place of *, something like `date_error’.

1 Like

Thank you @softark I created another attribute and declared as hidden input in my view, inside the active form, and manage to solve in this way. Thanks also for the issue report suggestion, I think I will soon.

Cheers

1 Like