[EXTENSION] ChildrenRequiredValidator

This thread is for any discussion related to the ChildrenRequiredValidator.

http://www.yiiframework.com/extension/childrenrequiredvalidator/

The validator is extremely simple, as I wanted to keep it as clean as possible. Complex parent field analysis can be performed by making a magic property of the model.

Any and all feedback/suggestions welcome!

Haven’t tested it, but anonymous function to the match field should ™ work as well.

Just thought I’d share this additional method for using the validator.

I have a structure with three models – one parent form with two children forms. Which child form is filled out depends on the toggle item selected from the parent.

Ie:


Form A:

   Do you want to do B or C?

      If B: Render and validate B

      If C: Render and validate C

So, form A model has property B and property C.

I don’t want A to validate unless B OR C validates and I want A to be smart enough to know what it needs to do.

So, in my rules for A, I add:




array(

	'BValid', 

	'application.components.validators.ChildrenRequiredValidator',

	'parentAttribute'=>'BOrC',

	'requiredValue'=>true,

	'match'=>self::OPTION_B

),

			

array(

	'CValid', 

	'application.components.validators.ChildrenRequiredValidator',

	'parentAttribute'=>'BOrC',

	'requiredValue'=>true,

	'match'=>self::OPTION_C

),	



And then I add the following methods to A:




public function getBValid(){ return $this->B->validate(); }

public function getCValid(){ return $this->C->validate(); }



So now, my controller will only have to run $a->validate() rather than a complex series to determine if A validates, then if B or C validates depending on which sub-section is required.

Like so in my controller action:




$model = new A();

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

{

    $model->attributes = $_POST['A'];

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

       $model->B->attributes = $_POST['B'];

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

       $model->C->attributes = $_POST['C'];

    

    // the children required way..

    if ( $model->validate() )

    {

         // do whatever I need to do next here

    }

}



Rather than the old way:




$model = new A();

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

{

    $model->attributes = $_POST['A'];

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

       $model->B->attributes = $_POST['B'];

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

       $model->C->attributes = $_POST['C'];

    

    // check which selected children have been chosen

    // and ensure everything validates

    if ( $model->validate() && (

         $model->selectedB && $model->B->validate() || 

         $model->selectedC && $model->C->validate()

    ))

    { 

         // do whatever I need to do next here

    }

}



The old way requries that my controller be very cognizant of the way B and C might be used and is much more confusing for another developer to maintain in the long run.

(Should be noted that I’m instancing B and C as part of the afterConstruct for A)

This is the original thread and those are additional examples, not questions.

Did someone post a question somewhere I missed about this extension?

Hi,

I’m trying to use this extenion with the function based validation, and it doesn’t seem to be picking up the function. I have the following:




// Rules section

array('otherSuburb', 'application.components.validators.ChildrenRequiredValidator', 'parentAttribute' => 'isSuburbOther', 'requiredValue' => true, 'message' => 'Other Suburb cannot be blank.')


// Validator Function

public function isSuburbOther()

{

	$suburbName = Lookup::item("customer", "suburbId", $this->suburbId);

	if ($suburbName == 'Other') {

		return true;

	} else {

		return false;

	}

}



Error: Property "ContactForm.isSuburbOther" is not defined.

Highlighted line: if ( !$object->$parent || $object->$parent != $this->match )

Can you tell me what I’ve done wrong here?

Ok, I worked around the issue (sample below), but I’d still like to know if I did something wrong, or if there’s a bug in the validator?




array('otherSuburb', 'application.components.validators.ChildrenRequiredValidator',

      'parentAttribute' => 'suburbId',

      'match' => Lookup::itemId("customer", "suburbId", "Other"),

      'requiredValue' => true, 'message' => 'Other Suburb cannot be blank.'),



Your first way would have worked, but to access it magically, you needed to call the method "getIsSuburbOther()" which would allow your model to access it as a property $model->isSuburbOther

Make sense?

Hmm, unfortunately no. I tried:

‘parentAttribute’ => ‘getIsSuburbOther()’

‘parentAttribute’ => ‘getIsSuburbOther’

function is declared as: public function getIsSuburbOther()

I continue to get the same error. The model I’m working on is based on CFormModel, as opposed to CActiveRecord. Would that make a difference?

The method is getIsSuburbOther()

The parent attribute is isSuburbOther

It’s standard “magic” for php and Yii for getting the result of a “get” method as a model property.

You’re getting your names mixed up still.

Awesome, it works now. Didn’t realise I needed to leave the ‘get’ bit off in the function reference. Thanks.

Great extension!

Thank you :)

One question about the usage:

Is it possible to check against multiple matches?

E.g.:


array('parent',

	'application.extensions.validators.ChildrenRequiredValidator',

	'parentAttribute'=>'parent',

	'match'=>'MULTIPLE VALUES HERE'),

No, not with the current implementation.

It could be refactored to check whether match is an array, and if so, match any value within it. But that would be a change.

If you open up the validator and look at line 43, that is the one that would need to be refactored.

Change:




if ( !$object->$parent || $object->$parent != $this->match)

  return;



to something like:




if ( !$object->$parent)

  return;


if ( is_array( $this->match ) ) 

{ 

   if ( !in_array( $object->parent, $this->match ))

     return;


} else {

   if ( $object->parent != $this->match )

     return;

}




Then you can set match to be an array of allowed values.

I will update the extension to reflect this ability tonight.

Hi,

I have used this extension with my project , works wonderful . thanks :)

I have just one problem say example :

i have two fields min_age and max_age(min_age and max_age is not compulsory fields).Now when user fills the min_age then only max_age is compulsory(done by using this extension) and its works fine .But max_filed is showing me yii required mark by default(max_age*).

is there any way to remove this require mark.

Thanks:)

hey got an answer :

Instead of using echo $form->labelEx($model,‘max_age’); use echo $form->label($model,‘max_age’);

The above answer is based on the assumption that you are using default crud generated code from gii.

:)