validation rule - "at least one of three fields is filled"

I need validation rule something like "required", but at least one of three fields should be fields (say, phone1,phone2 or phone3)…

How, this can be done?

You can use a validation method inside your model (see: http://www.yiiframework.com/doc/guide/1.1/en/form.model#declaring-validation-rules).

Something like this (not tested):




class MyModel extends CFormModel

{

  public $phone1 = null;

  public $phone2 = null;

  public $phone3 = null;


  public function rules()

  {

    return array(

      array('phone1, phone2, phone3', 'oneOfThree', 'phone1', 'phone2', 'phone3'),

    );

  }

 

  /**

   * Should be called three times

   * 

   * $attribute will be one of phone1, phone2 or phone3

   * $params will always be array('phone1', 'phone2', 'phone3')

   *

   * (as far as I can remember...)

   */

  public function oneOfThree($attribute,$params)

  {

    $valid = false;


    foreach ($params as $param) {    

      if ($this->$param !== NULL) {

        $valid = true;

        break;

      }

    }

     

    if ($valid === false) {

      $this->addError( $attribute, 'Your error message.' );

    }

  }

}



Maybe not an ideal solution, since it checks three times what needs to be checked only once, but it should work. If you require it more often, you might think about writing your own validator class by inheriting from CValidator.

Why to call it 3 times?




class MyModel extends CFormModel

{

  public $phone1 = null;

  public $phone2 = null;

  public $phone3 = null;


  public function rules()

  {

    return array(

      array('phone1, phone2, phone3', 'filter', 'filter'=>'trim'),

      array('phone1', 'oneOfThree'),

    );

  }

 

  public function oneOfThree($attribute, $params)

  {

      if (!$this->phone1 || !$this->phone2 || !$this->phone3)

          // adding error for attribute "phone1" ONLY

          $this->addError($attribute, 'Phone is required.');

  }

}



andy_s

This depends on user needs…

If any of the 3 fields can have a value… your solution is not good… as a user can enter second or third field but not the first one…

Isn’t the custom validator always called, regardless of which field has a value?

/Tommy

If it’s set in the rules like andy_s suggested


array('phone1', 'oneOfThree'),

It would be called only for that one field

Oops, sorry it should be like this:




if (!$this->phone1 && !$this->phone2 && !$this->phone3)



You know, usually I don’t test a code I post there, just giving an idea :lol: One should edit it to suit his needs.

Yes, that’s what I meant. When it’s called it will check all three fields, right. Remaining question is: what happens if the phone1 field is left empty? Will the validator still be called? I think it should.

While writing this I came to think of ajax validation. Validating three fields would not be a good idea while entering data.

/Tommy

It will check all 3 fields but only when it is called…

in case of ajax validation it’s called only on “change” event… if nothing is entered on the first field, there is no change event and the validation would not be called…

but even if it would be called it would be no good as other fields has not been edited yet… so it’s better to bind the same function to all fields that needs to be checked…

this way when the user enters a value in any of the fields the validation will be called

Yeah, I agree. Has to bind to all three fields in order for a validation error to be cleared on subsequent data entry.

Interesting what you said about the “change” event. I haven’t done any effective work for some time but IIRC the validation will kick in if you navigate the fields with the tab key. Perhaps this event was tied to the “blur” event before?

/Tommy

by default ‘validateOnChange’ is true… this can be changed by enabling ‘validateOnType’ - http://www.yiiframework.com/doc/api/1.1/CActiveForm#clientOptions-detail

Aside of many examples provided by others in this thread, you can simply use this validator (atleastvalidator). Seems to be doing exactly, what you’re looking for.

check this.

working very fine for me.

public function validateFields($object,$attribute)

{





	 switch($object){


	 	 case "FeedId":


			 if(strlen($this->ItemName)<1 && strlen($this->RssLink)<1 && strlen($this->FeedId)<1)


				{


					$this->addError('FeedId', "Feed cannot be blank.");


				}


		break;


		case "ItemName":


			if(strlen($this->ItemName)<1 && strlen($this->FeedId)<1)


			{


				$this->addError('ItemName', "Item Name cannot be blank.");


			}				


		break;


		case "RssLink":


			if(strlen($this->RssLink)<1 && strlen($this->FeedId)<1)


			{


				$this->addError('RssLink', "Rss Link cannot be blank.");


			}				


		break;


	 }


}