Баг с CActiveForm::validate

Предварительное обсуждение найденных ошибок перед отправкой их авторам фреймворка, а также внесение новых предложений.
Ответить
Аватара пользователя
Антон Смирнов
Сообщения: 284
Зарегистрирован: 2011.07.08, 10:37
Контактная информация:

Баг с CActiveForm::validate

Сообщение Антон Смирнов »

Не могу точно утвержать, но насколько удалось выяснить, баг в следующем.

Допустим, у нас есть модель, у которой много полей. В форме мы выводим не все поля + на форму включаем валидацию по аяксу. В конроллере мы устанавливаем значения аттрибутам модели, которые пришли из поста и вызываем валидацию:

Код: Выделить всё

echo CActiveForm::validate($model, null, false); 
Так вот в форме, сработает метод afterValidate и hasError будет false (т.е. валидация прошла успешно), если все свойства, что пришли из поста, прошли валидацию, и независимо от того, прошли ли валидацию остальные свойства модели.

Как я понял, JSON с ошибкой вовращается, но поскольку не содержит информации об ошибках для тех полей, что есть на форме, то считается, что ошибки нет.

Пример,

1) Модель "Comment" содержит аттрибуты: name, text
2) На форме выводится только "name"
3) В контроллере

Код: Выделить всё

$model = new Comment;
$model->attributes = $_POST['Comment'];
$model->text = ''; //Ошибка, текст не может быть пустым
echo CActiveForm::validate($model, null, false); 
4) Вызывается afterValidate и hasError = false
Nafania
Сообщения: 1227
Зарегистрирован: 2011.01.31, 13:12

Re: Баг с CActiveForm::validate

Сообщение Nafania »

А rules в модели-то правильные?
Аватара пользователя
Антон Смирнов
Сообщения: 284
Зарегистрирован: 2011.07.08, 10:37
Контактная информация:

Re: Баг с CActiveForm::validate

Сообщение Антон Смирнов »

Да, все правильно.

Потому что если в контроллере вызвать метод getErrors() для модели, то он правильно скажет, что аттрибут text пустой. И не даст сохранить методом save().
Nafania
Сообщения: 1227
Зарегистрирован: 2011.01.31, 13:12

Re: Баг с CActiveForm::validate

Сообщение Nafania »

Так, а метода hasError нету.
http://www.yiiframework.com/search/?q=h ... pi-suggest

Есть hasErrors($attribute) или без аргумента для всех атрибутов сразу.
Вы точно все верно используете?
Аватара пользователя
Антон Смирнов
Сообщения: 284
Зарегистрирован: 2011.07.08, 10:37
Контактная информация:

Re: Баг с CActiveForm::validate

Сообщение Антон Смирнов »

А где я писал про метод hasError ? Я писал, что у CActiveForm есть событие afterValidate, прототип которого afterValidate(form, data, hasError) Так вот, после аякс валидации, hasError принимает значение false, что говорит о том, что нет ошибок.

Извиняюсь, если выражаюсь не ясно.
Nafania
Сообщения: 1227
Зарегистрирован: 2011.01.31, 13:12

Re: Баг с CActiveForm::validate

Сообщение Nafania »

Антон Смирнов писал(а):А где я писал про метод hasError ? Я писал, что у CActiveForm есть событие afterValidate, прототип которого afterValidate(form, data, hasError) Так вот, после аякс валидации, hasError принимает значение false, что говорит о том, что нет ошибок.

Извиняюсь, если выражаюсь не ясно.
Если я все правильно понял, то у вас есть метод afterValidate в модели, так?
Только у него нет аргументов.
Или я чего-то неверно понимаю и мы говорим о разных вещах.

Можно больше кода?
Аватара пользователя
Антон Смирнов
Сообщения: 284
Зарегистрирован: 2011.07.08, 10:37
Контактная информация:

Re: Баг с CActiveForm::validate

Сообщение Антон Смирнов »

Есть модель Comment, у нее есть аттрибуты: name и text. Оба являются обязательными (required)

На странице выводится форма (CActiveForm), у которой включена аякс валидация. В форме выводится только аттрибут name.

У CAсtiveForm есть такое событие afterValidate (подробеее тут - http://www.yiiframework.com/doc/api/1.1 ... ons-detail ) прототип события - afterValidate(form, data, hasError) {...}, где hasError говорит нам о том прошла ли успешно аякс валидация.

В контроллере обрабатываем аякс - валидацию:

Код: Выделить всё

    
//Создаем новую модель
$model = new Comment;
//Мы из поста ловим только name, посколько это единственное, что есть в форме
$model->attributes = $_POST['Comment'];
//Аттрибут text мы присваиваем ручками
$model->text = ''; 
//Для справки: наша модель не сможет сохраниться, потому что аттрибут [b]text[/b] пустой
//Вызываем валидацию, результат которой будет преобразован в JSON
echo CActiveForm::validate($model, null, false);
//JSON будет правильным: в нем сказан, что есть ошибка в поле text, которое должно быть заполнено.
  
В нашу форму приходит аякс ответ, что типа "ошибка только в аттрибуте text, которое пустое". Но, поскольку у нас на форме нет поля text для данной модели, то Yii считает, что ошибки нет и вызывает afterValidate с hasError = false, т.е. как будто валидация прошла успешно.
Аватара пользователя
Антон Смирнов
Сообщения: 284
Зарегистрирован: 2011.07.08, 10:37
Контактная информация:

Re: Баг с CActiveForm::validate

Сообщение Антон Смирнов »

Код сейчас не доступен, но форма выводится правильно:

Код: Выделить всё

<?php $form = $this->beginWidget('CActiveForm', array(
    'id'=>'user-form',
    'enableAjaxValidation'=>true,
    'enableClientValidation'=>true,
    'clientOptions'=>array(
        'afterValidate'=>'afterValidate(form, data, hasError) {...}',
)

... 
Nafania
Сообщения: 1227
Зарегистрирован: 2011.01.31, 13:12

Re: Баг с CActiveForm::validate

Сообщение Nafania »

Так, вы мягкое с мелким не путаете?
afterValidate это евент, в нем вызывается javascript функция, которая кстати вызывается только если validateOnSubmit = true.
Вы вызываете CActiveForm статически и validateOnSubmit у вас false по дефолту.
И к тому же этот afterValidate не играет роли вообщем-то при сохранении модели, ибо там валидаторы модели уже.

Пока писал вы уже дополнили.
afterValidate работает только при afterValidate = true, а по дефолту он равен false.
Аватара пользователя
Антон Смирнов
Сообщения: 284
Зарегистрирован: 2011.07.08, 10:37
Контактная информация:

Re: Баг с CActiveForm::validate

Сообщение Антон Смирнов »

Nafania писал(а):Так, вы мягкое с мелким не путаете?
afterValidate это евент, в нем вызывается javascript функция, которая кстати вызывается только если validateOnSubmit = true.
Вы вызываете CActiveForm статически и validateOnSubmit у вас false по дефолту.
И к тому же этот afterValidate не играет роли вообщем-то при сохранении модели, ибо там валидаторы модели уже.

Пока писал вы уже дополнили.
afterValidate работает только при afterValidate = true, а по дефолту он равен false.
Вы меня не понимаете: все всегда работает правильно, кроме тех слуачев, когда ошибка содержится в том аттрибуте, которого нет в форме, т.е. который не отображается, в этих случаея CActiveForm считает все равно валидацию успешной.

validateOnSubmit = true стоит. Я забыл это сказать.
Nafania
Сообщения: 1227
Зарегистрирован: 2011.01.31, 13:12

Re: Баг с CActiveForm::validate

Сообщение Nafania »

Ну видимо это потому, что атрибуты могут заполнятся еще как угодно, например через beforeSave (то же время комментария).
Почему его тогда надо помечать как false?
Аватара пользователя
Антон Смирнов
Сообщения: 284
Зарегистрирован: 2011.07.08, 10:37
Контактная информация:

Re: Баг с CActiveForm::validate

Сообщение Антон Смирнов »

Потому что validate должен валидировать по-умолчанию все аттрибуты согласно rules. Давайте тогда при такой конструкции:

$model = new Comment;
$model->save();

Ничего не валидировать, вдруг значения заполнятся в beforeSave )))

Если вы какие-то аттрибуты не хотите валидировать - пишите им safe
Nafania
Сообщения: 1227
Зарегистрирован: 2011.01.31, 13:12

Re: Баг с CActiveForm::validate

Сообщение Nafania »

CActiveForm это виджет, который валидирует форму согласно правилам модели.
Если в форме нет полей каких-то полей, то их и валидировать не зачем.
Так что такое поведение правильное.
Но это естественно только мое мнение, думаю что Sam Dark даст более развернутый ответ.
Аватара пользователя
Антон Смирнов
Сообщения: 284
Зарегистрирован: 2011.07.08, 10:37
Контактная информация:

Re: Баг с CActiveForm::validate

Сообщение Антон Смирнов »

Nafania писал(а):CActiveForm это виджет, который валидирует форму согласно правилам модели.
Если в форме нет полей каких-то полей, то их и валидировать не зачем.
Так что такое поведение правильное.
Но это естественно только мое мнение, думаю что Sam Dark даст более развернутый ответ.
Параметр hasError по логике должен иметь значение true.
Аватара пользователя
because
Сообщения: 689
Зарегистрирован: 2010.09.30, 22:01

Re: Баг с CActiveForm::validate

Сообщение because »

hasError - false, поскольку ошибок нет в форме. ajax, client валидация работает только с формой и ее полями, которые в ней есть. если есть поле, для которого нужно показать ошибку - он выведет. если нет полей с ошибкой - считает, что ошибок нет. на все остальное есть серверная валидация.
RTFM !
Wassup
Сообщения: 1
Зарегистрирован: 2014.09.09, 13:15

Re: Баг с CActiveForm::validate

Сообщение Wassup »

Столкнулся с подобной проблемой. Я после валидации отправляю по ajax данные для сохранения, а в ответ принимаю данные для выбора дальнейшего действия(переход к карточки модели, создать еще одну модель...)
Решил:

Код: Выделить всё

<?php $form=$this->beginWidget('CActiveForm', array(
    'enableAjaxValidation'=>true,
    'clientOptions' => array(
        'validateOnSubmit' => true,
        'afterValidate' => 'js:function(form, data, hasError) {
                if(!$.isEmptyObject(data)) {//было if(hasError)
                    for(var i in data) $("#"+i).parent().addClass("has-error");
                }else {
                    form.children().removeClass("has-error");
                    form.ajaxSubmit({
                       ...
                    });
                }
                return false;
            }',
        'afterValidateAttribute' => 'js:function(form, attribute, data, hasError) {
                if(hasError) $("#"+attribute.id).parent().addClass("has-error");
                else $("#"+attribute.id).parent().removeClass("has-error");
            }'
    )
)); ?>
В

Код: Выделить всё

'afterValidate' => 'js:function(form, data, hasError) {
hasError - булевое значение о валидации отправленных данных, hasError - объект со всеми ошибками моделей из

Код: Выделить всё

echo CActiveForm::validate($models);
Ответить