Вопрос По Формам

Всем доброе утро. Подскажите пожалуйста, можно ли разделить правила валидации для нескольких форм одной модели ? Т.е. чего имеем - есть 4 формы все они расположены в CJuiTabs, модель у них общая. И к примеру если на вкладке 1 у меня обязательное поле Имя, а на вкладке 2 - Фамилия, то к примеру форму с вкладки 2 не удастся отправить пока я не заполню Имя на вкладке 1, т.е. интересует можно ли с помощью сценариев разделить правила для разных форм одной модели. Грубый пример:




	public function rules()

	{

		return array(

                        if($form_id = form1){

			    array('name', 'required'),

                        }

                        if($form_id = form2){

			    array('surname', 'required'),

                        }

		);

	}



Вобщем принцип я думаю понятен :)

Принцип понятен, вопрос непонятен :)

Да, это делается сценариями.

При создании формы, соответственно, просто указываете сценарий: $form1 = new YourModelForm(‘scenario1’);

При сабмите формы при ajax валидации передает id. В таком случае нет необходимости инициировать 4 модели. Пример для ajax валидации.




        if (isset($_POST['ajax']) && $_POST['ajax'] === 'form1')

{

            $model->scenario='form1_scenario';

            $this->performAjaxValidation($model);

}



А можно кусок кода наглядный ? :) Есть виджет CJuiTabs в нем 4 формы:




<?php $this->widget('zii.widgets.jui.CJuiTabs',array(

    'tabs'=>array(

        'Авто'=>$this->renderPartial("/forms/_autoform", array('model' => $model), $this),

        'Запчасти'=>$this->renderPartial("/forms/_sparesform", array('model' => $model), $this),

        'Услуги'=>$this->renderPartial("/forms/_servicesform", array('model' => $model), $this),

        'Обратная связь'=>$this->renderPartial("/forms/_feedbackform", array('model' => $model), $this),

    ),

    // additional javascript options for the tabs plugin

    'options'=>array(

        'collapsible'=>true,

    ),

)); ?>



Дык вот если я сделаю обязательными поля в форме _autoform и к примеру _sparesform, то отправить _autoform у меня не получится, пока я не заполню обязательные поля в форме _sparesform, а мне же нужно сделать их независимыми ::)

Спасибо, сейчас гляну, модель как раз таки одна :)

В общем вроде получилось, в модели сделал:




return array(

	array('feedback_name, feedback_email', 'required', 'on'=>'feedback'),

	array('spares_name', 'required', 'on'=>'spares'),



Ну и в контроллере получается:




$model=new Forms('feedback');

$model=new Forms('spares');



И все, больше ничего не трогал, вроде работает.

ORey, tuschkan, спасибо вам за помощь :)

Всем добрый вечер. Что бы не засорять форум решил написать здесь. Продолжаю свои попытки осилить ajax валидацию.

Есть форма:




<?php $form=$this->beginWidget('CActiveForm', array(

        'id'=>'auto-form',

        'enableAjaxValidation'=>true,

        'action'=>'/forms/SendAutoForm',

        'clientOptions'=>array(

            'validateOnSubmit'=>true,

            'afterValidate'=>'js:function(form,data,hasError){

                        if(!hasError){

                                $.ajax({

                                        "type":"POST",

                                        "url":"'.CHtml::normalizeUrl(array("/forms/SendAutoForm")).'",

                                        "data":form.serialize(),

                                        "success":function(data){$("#auto-form").html("data");},

                                        

                                        });

                                }

                        }'

        ),

)); ?>


//здесь поля формы


<?php echo CHtml::submitButton(''); ?>

<?php $this->endWidget(); ?>



В контроллере:




public function actionSendAutoForm() {


		 $model=new Forms('auto-form');              

                

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

                { 

                  $valid=$model->validate();            

                        if($valid){

                            $auto_bodycode = $_POST['Forms']['auto_bodycode'];

			    $auto_enginecode = $_POST['Forms']['auto_enginecode'];

			    $auto_equipment = $_POST['Forms']['auto_equipment'];

			    $auto_vinframe = $_POST['Forms']['auto_vinframe'];


                            //тут еще массив из того что выше//


                            $model->content = json_encode($autoform);

                            if($model->save()){

                                echo CJSON::encode(array('status'=>'success'));

                            }

                            Yii::app()->end();

                        

                        }else{

                                // $error = CActiveForm::validate($model);

                                // if($error!='[]')

                                //     echo $error;

                                // Yii::app()->end();

                        	print_r($model->getErrors());

                            }

                        }


protected function performAjaxValidation($model)

	{

		if(isset($_POST['ajax']) && $_POST['ajax']==='feedback-form')

		{

                        $this->performAjaxValidation($model);

			Yii::app()->end();

		}


		if(isset($_POST['ajax']) && $_POST['ajax']==='spares-form')

		{

			$this->performAjaxValidation($model);

			Yii::app()->end();

		}


		if(isset($_POST['ajax']) && $_POST['ajax']==='auto-form')

		{

			$this->performAjaxValidation($model);

			Yii::app()->end();

		}

	}




И в модели:




 public $auto_bodycode;

 public $auto_enginecode;

 public $auto_equipment;

 public $auto_vinframe;


 public function rules()

	{

		// NOTE: you should only define rules for those attributes that

		// will receive user inputs.

		return array(

array('auto_bodycode, auto_enginecode, auto_equipment, auto_vinframe', 'required', 'on'=>'autoform')

);

}



Но валидация не проходит. Даже если заполнить все поля, все равно получаю в ответ:




Array

(

    [auto_bodycode] => Array

        (

            [0] => Необходимо заполнить поле «Код кузова».

        )


    [auto_enginecode] => Array

        (

            [0] => Необходимо заполнить поле «Код двигателя».

        )


    [auto_equipment] => Array

        (

            [0] => Необходимо заполнить поле «Комплектация».

        )


    [auto_vinframe] => Array

        (

            [0] => Необходимо заполнить поле «VIN или FRAME».

        )


)



Третий день сижу, не могу вкурить почему :(

Бывает.

Должно быть так:




public function actionSendAutoForm() {


                $model=new Forms('auto-form');              

                if (Yii::app()->request->isAjaxRequest)

                {

                   $error = CActiveForm::validate($model);

                   if($error!='[]')

                       echo $error;

                   Yii::app()->end();

                }  

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

                { 

                   $model->auto_bodycode = $_POST['Forms']['auto_bodycode'];

                   $model->auto_enginecode = $_POST['Forms']['auto_enginecode'];

                   $model->auto_equipment = $_POST['Forms']['auto_equipment'];

                   $model->auto_vinframe = $_POST['Forms']['auto_vinframe'];


                            //тут еще массив из того что выше//


                   $model->content = json_encode($autoform);

                   if($model->save()){

                        echo CJSON::encode(array('status'=>'success'));

                        Yii::app()->end();

                     }

                 }



И $model->validate делайте после присвоения значений, иначе получается вы делаете валидацию пустой модели.

Еще одно,




else{

     // $error = CActiveForm::validate($model);

     // if($error!='[]')

     //     echo $error;

     // Yii::app()->end();

     print_r($model->getErrors());

     }



должно быть не тут, а вначале. Делайте проверку


if(Yii::app()->request->isAjaxRequest)

и тут делайте валидацию.

Да и еще одно, при вызове save() вызывается и validate(), так как validate() тут вам не очень нужно его можно опустить, ну или чтобы избежать двойной валидации можно использовать save(false). Иногда бывает очень полезно, особенно на больших таблицах.

Все таки нужно написать статью об аякс валидации форм, на выходных постараюсь заняться.

ineersa, огромное вам спасибо, сейчас буду разбираться :)

Я переписал ваш контроллер, так должно работать.

Не углядел




protected function performAjaxValidation($model)

        {

                if(isset($_POST['ajax']) && $_POST['ajax']==='feedback-form')

                {

                        $this->performAjaxValidation($model);

                        Yii::app()->end();

                }


                if(isset($_POST['ajax']) && $_POST['ajax']==='spares-form')

                {

                        $this->performAjaxValidation($model);

                        Yii::app()->end();

                }


                if(isset($_POST['ajax']) && $_POST['ajax']==='auto-form')

                {

                        $this->performAjaxValidation($model);

                        Yii::app()->end();

                }

        }



Вам явно нужно отдохнуть, взглянете на свежую голову, очень удивитесь.

ineersa, еще раз спасибо. Наверное вы правы, стоит отдохнуть :)

Всем доброе утро, с обычными полями разобрался вроде, но как быть с динамическими ?

К примеру, есть такая строка формы:




<?php echo $form->textField($model,'spares_name[]', array('placeholder'=>'Название запчасти')); ?>

<?php echo $form->error($model,'spares_name'); ?>



Поля в форме можно добавлять динамически, по умолчанию оно 1, но может быть и 10, и 20. Собственно получаю массив значений в контроллере следующего вида:




$spares_name = $_POST['Forms']['spares_name'];


array(7) {

  [0]=>

  string(18) "Запчасть 1"

  [1]=>

  string(18) "Запчасть 2"

  [2]=>

  string(18) "Запчасть 3"

  [3]=>

  string(18) "Запчасть 4"

  [4]=>

  string(18) "Запчасть 5"

  [5]=>

  string(18) "Запчасть 6"

  [6]=>

  string(18) "Запчасть 7"

}



Нашел пример в доках http://www.yiiframework.com/doc/guide/1.1/ru/form.table, но там скорее редактирование, а у меня именно сохранение. Принцип я то вроде понял - пробежаться foreach по массиву этих самых полученных значений полей и проверить каждое, но как я не пытался пристроить следующую часть кода:




$model->content=$_POST['Forms']['spares_name'];

$valid=true;

				        foreach($model->content as $i=>$item)

				        {

				            if(isset($_POST['Forms'][$i]))

				                $item->attributes=$_POST['Forms'][$i];

				            	$valid=$item->validate() && $valid;

				        }



Получаю в ответ Fatal error: Call to a member function validate() on a non-object.

Гугл ничего не подсказал достойного, надеюсь на вашу помощь :(

Все верно, $item ведь у вас не обьект, зачем его мучить)

Для такого есть 2 варианта.

  1. Свой валидатор:



//модель

class MyModel extends CActiveRecord

{

    public $spares=array();

    

    public function rules()

    {

        

        return array(

            ....

            array('spares','checkSpares'),

        );

    }

    

    public function checkSpares()

    {

    //тут делаем валидацию чего нам нужно

    //ошибки пихаем как $this->addError('spares','error text');

    }

}



2й вариант, поправить rules:




class MyModel extends CActiveRecord

{

    public $spares=array();

    

    public function rules()

    {

        $rules = array(

        ......//ваши старые rules

        );

        foreach ($spares as $key=>$spare)

        {

            array_push($rules,array("spares[$key]",'required'));//тут добавляем валидации которые нам надо

        }

        return $rules;

    }



Нужно немного поправить контроллер, по сути единственное что нам нужно это:




$model->spares=$_POST['Forms']['spares_name'];

$model->validate();



И мы точно также получим ошибки валидации вдруг чего в getErrors().

Еще одно, насчет подсветки полей, вы вывели ошибку только для верхнего элемента(массива), если же вам нужна подсветка полей внутри массива с выводом ошибок, попробуйте тоже самое, только атрибуты делайте в виде spares[$i].

Тоесть для этого подходит 2й вариант. В этом варианте вью должно выглядеть как то так:




for($i = 0; $i <= 10; $i++)

<?php echo $form->textField($model,"spares_name[$i]", array('placeholder'=>'Название запчасти')); ?>

<?php echo $form->error($model,"spares_name[$i]"); ?>



Не на 100% уверен что так будет работать, но по логике вещей должно.

Спасибо, гляну, еще нашел вариант с validateTabular, может кому пригодится:




if(Yii::app()->getRequest()->getIsAjaxRequest()) {

            if (isset($_POST['Profile'])) {

                foreach ($_POST['Profile'] as $key => $value) {

                    $profiles[] = new Profile;

                }

            }

            echo CActiveForm::validateTabular(  $profiles );

            Yii::app()->end();

}