Аномалия в сохранении

Добрый день.

Я только недавно начал разбираться в YII. Проблема состоит в следующем: работало все нормально, данные сохранялись в базе, если последнии 2 правила в модели были закоментированны. После того как я их разкоментировал, во время сохранения при корректно заполненых данных, ничего не происходит - не выдает ниодной ошибки, не происходит сохранение.

Люди добрые, подскажите пожалуйста в чем может быть проблема.

Так же выслушаю любые замечания по коду, если таковы будут.

МОДЕЛЬ

public $uin;


public $email;


public $pass;


public $passRepeat;


public $verifyCode;





public function rules()


{


return array(


        array('email, pass', 'required', 'message'=>Yii::t('common','empty')),


        array('email, pass', 'length', 'max'=>255,'tooLong'=>Yii::t('common','lengthLong').'255 символов','on'=>'register'),


        array('pass', 'length', 'min'=>6,'tooShort'=>Yii::t('common','lengthShort').'6 символов','on'=>'register'),


        array('email','email', 'message'=>Yii::t('common','emailCorrect'),'on'=>'register'),


        array('email','unique', 'message'=>Yii::t('common','has_in_base'),'on'=>'register'),





        //array('pass','compare', 'compareAttribute'=>'passRepeat','message'=>Yii::t('common','passRepeat'),'on'=>'register'),


        //array('verifyCode','captcha','captchaAction'=>'abit/captcha','allowEmpty'=>!extension_loaded('gd'),'message'=>Yii::t('common','verifyCode'),'on'=>'register'),


    );


}

КОНТРОЛЛЕР

public function actionRegister()

{

   $errors = Array();





   $model = new AbitPortal();





   if(isset($_POST['AbitReg']))


   {


       $model->email = substr(trim($_POST['AbitReg']['email']),0,260);


       $model->pass = substr(trim($_POST['AbitReg']['pass']),0,260);


       $model->passRepeat = substr(trim($_POST['AbitReg']['passRepeat']),0,260);


       $model->verifyCode = substr(trim($_POST['AbitReg']['verifyCode']),0,20);





       $model->scenario='register';


       


       // Check data


       $model->validate();





       if($model->hasErrors())


       {


           foreach($model->getErrors() as $field) $errors[] = $field[0];


       }





       if(!count($errors))


       {


                         


           $model->uin = RGenerate::generateUin();


           $model->code_conf = RGenerate::generateCode();


           $model->date_reg = date("Y.m.d H:i:s");


           $model->salt = RGenerate::generateSalt();


           $model->type_registr = 1;


           $model->pass = sha1(sha1($model->salt).sha1($model->pass));


           //$model->step =


           //$model->d_block =





           // Save data 


           if ($model->save())


           {





               Yii::app()->user->setFlash("registered",Yii::t("common","registered"));





               // Update page


               $this->refresh();


           }


       }


   }


   // display the register form


   $this->render('register',array('model'=>$model,'errors' => $errors));


}

У меня тоже есть странная аномалия, я её не встречал, но пользователи жалуются.

При регистрации $model->validate() проходит успешно.

Но данных почему-то в таблице нет.

Т.е. код ниже почему-то не сохраняет данные.




if($model->validate()) {

   $model->save();

}



Спасибо за то, что откликнулись. У меня как раз эта ошибка. Вы не знаете как народ с ней борится. Или ,например, как узнать секретный код конкретной капчи, если она объявлена следующим образом:

        // Создаем экшн captcha.


        'captcha'=>array(


        'class'=>'CCaptchaAction',


        'backColor'=> 0xFFFFFF,


        'maxLength'=> 6,


        'minLength'=> 6,


        'testLimit'=> 2,


        'foreColor'=> 0x003399,


        ),

Код капчи сохраняется в сессии.

Зачем в базе сохранять капчу которую ввёл пользователь при регистрации?

Это что и зачем используется?




if($model->hasErrors())

{

foreach($model->getErrors() as $field) $errors[] = $field[0];

}


if(!count($errors))

{



Не проще?




if($model->hasErrors())



И ошибки передавать в виев не обязательно, они уже там, в свойствах модели.

Это не будет работать:


$model->date_reg = date("Y.m.d H:i:s");

Вместо этого используйте


$model->date_reg = new CDbExpression('NOW()');

Это зачем?


$model->scenario='register';




var_dump($model->getErrors());

if($model->validate()) {

   echo "After validate";

   $model->save();

   echo "After save";

}



Мало информации… Попробуйте это.

  • вывести все поля модели.

Тогда смотрите, может где-то валидатор не срабатывает. Или поле пустое. Или Пост пустой.

Мне кажется, что все беды могут заключаться в этом незатейливом коде:




if($model->validate()) {

   $model->save();

}



Зачем делать валидацию два раза (второй раз неявно в методе save)? Если у вас в методе beforeValidate, beforeSave и т.д. изменяются значения полей, то вторая валидация легко может не пройти. Вывод: писать save(false).

http://www.yiiframework.com/doc/api/1.1/CActiveRecord#save-detail

Всем огромное спасибо. Нашел решение в документации, а затем это подтвердил andy_s.

В моем случае надо передать параметр false при вызове метода save.

Отвечу на остальные вотпросы:

  1. код капчи никто не собирался сохранять в базу, хотел проверить верно ли проходит валидация (читал что если 2 и более раза неправлиьно объявлена капча, то это вызывает проблемы);

  2. на счет автоматически передаваемых ошибок во вьюв не знал. Спасибо

  3. как ни странно $model->date_reg = date("Y.m.d H:i:s"); работает и сохраняется все корректно, но все равно Спасибо. Буду знать.

  4. про $model->scenario=‘register’; читал, что нужно передать информацию о том какой сценарий будет выполняться. Может лучше так $model->validate(‘register’) или так $model = new AbitPortal(‘register’);?

Лучше никакой сценарий не устанавливать, если у вас их всего два: регистрация (insert) и изменение данных (update). При создании новой модели автоматически будет установлен сценарий insert, при извлечении из базы - update. В модели останется только on=>register заменить на on=>insert.

Хм, не знал про параметры. Спасибо.

Но мне кажется это не решает проблему, по сути получалась двойная валидация.

Просто если бы была ошибка то я по идее не должен попасть на $model->save();

А так, 2 валидации проходит, а записи в табличке нет.

Посмотрите что происходи у вас после $model->save();

Например так


if (!$model->save()) {

    print_r($model->getErrors());

}

Скорей всего, как написал andy_s у вас после $model->validate() меняються данный и при повторной валидации вызванной методом $model->save() происходит ошибка, просто вы ее не отображаете.

Я бы очень не советовал делать


$model->save(false);

потому что у вас может произойти ошибка на уровне mysql и все равно запись не произойдет.

Поясню, например вы делаете проверку на длину строки и после того как она коректна, изменяете ее длину в методе afterValidate() или beforeSave() например функцией htmlspecialchars(). То при попытке записи вы не пройдете повторную валидацию и это правельно, потому как после валидации нужно акуратно менять данные, а лучше не делать изменения в промежутке между валидацией и сохранением. А отключив валидацию, $model->save(false), вы получите ошибку записи в базу потому что превысили длину строки. Коварство состоит в том что htmlspecialchars() не во всех случаях изменяет длину строки и часть записей у вас получится создавая илюзию что все ок.

Лучше все таки сделать так


if ($model->save()) {

    // производим действия после успешной записи

}

// запись не получилась, показать ошибки

Вообще рассудите сами. Если у вас ошибка при $model->save(), то отключив проверку данных, $model->save(false), вы не избавились от ошибки а просто ее скрыли, а сама ошибка осталась и где нибудь всплывет после.

Открыли глаза на некоторые вещи )

Спасибо, попробую.

Извините может вопрос и глуповат. А зачем перед сохранением обрабатывать данные функцией htmlspecialchars(), не легче ли их обработать перед выводом? А перед сохранением воспользоваться функцией mysql_real_escape_string?

Ну не надо все воспринимать как инструкцию к действию, это же пример, все делается под конкретную задачу.

Я предпочитаю, в большинстве случаев, обрабатывать данные перед записью потому что запись я делаю 1 раз а вывод 1000 раз в день, а то и поболее.