retrieving model attributes in behaviour

Hi all,

A beginner’s question from someone new to OOP. In my app, users can sign up with just an email and a password. However, some content is only visible to those who provided us with more info. Hence, I need to test in the database whether all user fields are filled out.

Because I will need this function for different tables I created a behavior in /protected/models/behaviors. I loaded this behavior in my model.

My 3 questions are:

  1. How can I retrieve the values from my model (e.g. $model-> first_name) for the foreach loop?

  2. How can I retrieve the table_name (or do I have to pass it on when loading the behaviour)?

  3. How can I set a variable that I can then access from the view file using $model->allDataProvided?

Any help would be much appreciated.

Model




public function behaviors(){

		return array(

			'CTimestampBehavior' => array(

				'class' => 'zii.behaviors.CTimestampBehavior',

				'createAttribute' => 'created',

				'updateAttribute' => 'modified',

			),


                    'CheckRequiredFieldsNotEmptyBehavior'=>array(


                            // locate file

                            'class'=>'application.models.behaviors.CheckRequiredFieldsNotEmptyBehavior',

                            // is it really necessary to pass on the model?

                            //'model'=>$this->model,


                        )

		);

                

                return array(

                        

                );                

	}



Behavior


<?php

/**

 * CheckRequiredFieldsNotEmptyBehavior

 *

 * Used by actionBuy in UserController 

 *

 * Checks whether a set of required fields are not empty 

 *

 * @author

 *

 */

class CheckRequiredFieldsNotEmptyBehavior extends CActiveRecordBehavior {


	private $requiredColumns;

	

	// set intial value of variable, will be set to 0 if one field is empty	

	public $allDataProvided = 1;


	public function __construct()

		{  

			//parent::__construct();

			$this->checkRequiredFieldsNotEmpty();

		} 

	

	

	// used by actionIndex of UserController

	public function checkRequiredFieldsNotEmpty()

	{




		// set required fields for tables

                switch ($model->tableName()) {

			case 'tbl_user':

					$requiredColumns = array(

						//tbl_user_salutation_id,

						$this->owner->first_name,

						$this->owner->last_name,

						/*$model->address_1,

						$model->address_2,

						$model->postcode,

						$model->city,

						$model->tbl_state_id,

						$model->phone,

						$model->email,

						$model->tbl_user_interest_id*/

					);

					break;

						

		}


	   


		// iterate through each field and if one is empty, set $allDataProvided to 0

		foreach ($requiredColumns as $value) {

			if (empty($value)) {

				$allDataProvided = 0;

			}

		}


		// break the reference with the last element, http://php.net/manual/en/control-structures.foreach.php

		unset($value);




		// return value of fucntion

		if ($allDataProvided == 1) {

			$model->allDataProvided == 1;

		} else {

			$model->allDataProvided == 0;

		}

	}	

	

	


}

Solution [1] & [2]


class SomeBehavior extends CBehavior {

	private $owner; 


	public function someBehaviorFunction() {

		// owner is the model (in ur case) to which this behavior shall attached to

		$this->owner = $this->getOwner();	


		if (is_subclass_of($this->owner, 'CActiveRecord')) {

			$attributes = $this->owner->getAttributes();	// here all the attributes of the model 

			$tableName = $this->owner->tableName();			// tableName() must exist in the model u r attaching the behavior with.

			// here do what u wanna do with the attributes

			...

		}

	}

}



Solution [3] here u can send whatever data u want to access in the view


$this->render('view',array('model'=>$model,'otherData'=>$someOtherData,));

Hope this solves ur problem… :)

Most helpful, thanks heaps. One problem though,


if (is_subclass_of($this->owner,'CActiveRecord')){



seem to return false.

If I call $model->allDataProvided; in the view it returns 13.




<?php

/**

 * CheckRequiredFieldsNotEmptyBehavior

 *

 * Used by actionBuy in UserController 

 *

 * Checks whether a set of required fields are not empty 

 *

 * @author 

 *

 */

class CheckRequiredFieldsNotEmptyBehavior extends CActiveRecordBehavior {


	private $requiredColumns;

        private $owner;

	

	// set intial value of variable, will be set to 0 if one field is empty	

	public $allDataProvided = 4;


	public function __construct()

		{  

			$this->checkRequiredFieldsNotEmptyBehaviorFunction();

		} 

	

	

	// used by actionIndex of UserController

	public function checkRequiredFieldsNotEmptyBehaviorFunction()

	{




            // test value

            $this->allDataProvided = 13;


            // owner is the model (in this case) to which this behavior shall be attached to

            $this->owner = $this->getOwner();





            if (is_subclass_of($this->owner,'CActiveRecord')){


                // test value

                $this->allDataProvided = 14;




                // here all the attributes of the model

                $attributes = $this->owner->getAttributes();

                // tableName() must exist in the model we are attaching the behavior with

                $tableName = $this->owner->tableName();








		// set required fields for tables

                switch ($model->tableName()) {

			case 'tbl_user':

					$requiredColumns = array(

						//tbl_user_salutation_id,

						$this->owner->first_name,

						$this->owner->last_name,

						/*$model->address_1,

						$model->address_2,

						$model->postcode,

						$model->city,

						$model->tbl_state_id,

						$model->phone,

						$model->email,

						$model->tbl_user_interest_id*/

					);

					break;

						

		}


	   


		// iterate through each field and if one is empty, set $allDataProvided to 0

		foreach ($requiredColumns as $value) {

			if (empty($value)) {

				$allDataProvided = 0;

			}

		}


		// break the reference with the last element, http://php.net/manual/en/control-structures.foreach.php

		unset($value);







                // return value of fucntion

		if ($this->allDataProvided == 1) {

			$model->allDataProvided == 1;

                        return true;

		} else {

			$model->allDataProvided == 0;

                        return true;

		}


                            $this->allDataProvided = 10;




            }

            // if !(is_subclass_of($this->owner,'CActiveRecord'))

            return false;


            // test value

            $this->allDataProvided = 11;




        }

	

	


}



The ‘CActiveRecord’ is the type of class to which u are attaching this behavior, replace it with the type of ur model.

u are getting 13 as the above condition returns false.

post ur class to which u r attaching this behavior then… (if wont work)

Thanks for your reply. I put the false statement in an { else } condition. But even if I delete it, it still doesn’t pass if (is_subclass_of($this->owner,‘CActiveRecord’)){ . Still returns 13. I’m pretty sure the model is CActiveRecord since it retrieves data from a table. Attached the code. Thanks again.

Behavior


<?php

/**

 * CheckRequiredFieldsNotEmptyBehavior

 *

 * Used by actionBuy in UserController 

 *

 * Checks whether a set of required fields are not empty 

 *

 * @author 

 *

 */

class CheckRequiredFieldsNotEmptyBehavior extends CActiveRecordBehavior {


	private $requiredColumns;

        private $owner;

	

	// set intial value of variable, will be set to 0 if one field is empty	

	public $allDataProvided = 4;


	public function __construct()

		{  

			$this->checkRequiredFieldsNotEmptyBehaviorFunction();

		} 

	

	

	// used by actionIndex of UserController

	public function checkRequiredFieldsNotEmptyBehaviorFunction()

	{


            // owner is the model (in this case) to which this behavior shall be attached to

            $this->owner = $this->getOwner();




            // test value

            $this->allDataProvided = 13;





            if (is_subclass_of($this->owner,'CActiveRecord')){


                // test value

                $this->allDataProvided = 14;




                // here all the attributes of the model

                $attributes = $this->owner->getAttributes();

                // tableName() must exist in the model we are attaching the behavior with

                $tableName = $this->owner->tableName();








		// set required fields for tables

                switch ($this->tableName()) {

			case 'tbl_user':

					$requiredColumns = array(

						//tbl_user_salutation_id,

						$this->owner->first_name,

						$this->owner->last_name,

						/*$model->address_1,

						$model->address_2,

						$model->postcode,

						$model->city,

						$model->tbl_state_id,

						$model->phone,

						$model->email,

						$model->tbl_user_interest_id*/

					);

					break;

						

		}


	   


		// iterate through each field and if one is empty, set $allDataProvided to 0

		foreach ($requiredColumns as $value) {

			if (empty($value)) {

				$this->allDataProvided = 0;

			}

		}


		// break the reference with the last element, http://php.net/manual/en/control-structures.foreach.php

		unset($value);







                 // return value of function

		if ($this->allDataProvided == 1) {

			$this->allDataProvided == 1;

                        return true;

		} else {

			$this->allDataProvided == 0;

                        return true;

		}


                // test value

                $this->allDataProvided = 10;




            } else {

                // if !(is_subclass_of($this->owner,'CActiveRecord'))

                return false;

                $this->allDataProvided = 18;


            }


            // test value

            $this->allDataProvided = 11;




        }

	

	


}

Model




<?php


/**

 * This is the model class for table "tbl_user".

 *

 * The followings are the available columns in table 'tbl_user':

 * @property integer $id

 * @property integer $tbl_user_salutation_id

 * @property string $first_name

 * @property string $last_name

 * @property string $address_1

 * @property string $address_2

 * @property string $city

 * @property integer $postcode

 * @property integer $tbl_state_id

 * @property string $phone

 * @property string $email

 * @property string $password

 * @property integer $tbl_user_interest_id

 * @property integer $tbl_user_role_id

 * @property string $created

 * @property string $modified

 *

 * The followings are the available model relations:

 * @property BuyerDocuments[] $buyerDocuments

 * @property UserInterest $tblUserInterest

 * @property UserRole $tblUserRole

 * @property State $tblState

 * @property UserSalutation $tblSalutation

 * @property SellerCompany[] $tblSellerCompanys

 */

class User extends CActiveRecord

{

	

	// for password repeat field, specific variable since this is no column in the table

	// for details check out Agile-Web-Application-Development-with-Yii11-and-PHP5-eBook09022011_1063898.pdf

	public $password_repeat;

	

	// when updating profile, two new fields that do not exist in db are shown in form

	// http://www.yiiframework.com/forum/index.php?/topic/12229-best-way-to-implement-implicit-change-of-password-solved/

	public $new_password;

	public $new_password_repeat;


        // when updating, email can't be used because 

       // public $new_email;


        // for testing whether all required fields in tbl_user have been filled out as a requirement for selling / buying

        // $model->$allUserDataProvided is declared in model User and set by actionBuy() and actionSell() in UserController

        // by calling method testAllDataProvided in UserController

        public $allUserDataProvided;

	

	/**

	 * Returns the static model of the specified AR class.

	 * @return User the static model class

	 */

	public static function model($className=__CLASS__)

	{

		return parent::model($className);

	}


	/**

	 * @return string the associated database table name

	 */

	public function tableName()

	{

		return 'tbl_user';

	}

	

	public function behaviors(){

		return array(

			'CTimestampBehavior' => array(

				'class' => 'zii.behaviors.CTimestampBehavior',

				'createAttribute' => 'created',

				'updateAttribute' => 'modified',

			),


                    'CheckRequiredFieldsNotEmptyBehavior'=>array(


                            // locate file: is this correct?

                            'class'=>'application.models.behaviors.CheckRequiredFieldsNotEmptyBehavior',

                            // is it really necessary to pass on the model?

                            //'model'=>$this->model,


                        )

		);

                

                return array(

                        

                );                

	}




	/**

	 * @return array validation rules for model attributes.

	 */

	public function rules()

	{

	

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

		// will receive user inputs.

		// different validations scenarios, see here http://php-thoughts.cubedwater.com/2009/validation-scenarios/

		return array(

			

			// scenario: register

			// password_repeat needs to be included for unknown reasons			

			array('email, password_repeat, password, tbl_user_interest_id', 'required', 'on'=>'register'),

			// compares password with password_repeat

			// for details check out Agile-Web-Application-Development-with-Yii11-and-PHP5-eBook09022011_1063898.pdf

			// only in this scenario because password field does not get displayed in scenario update

			array('password', 'compare', 'on'=>'register'),

                        array('email', 'unique', 'on'=>'register'),


                        //

                        //array('email', 'unique'),

                        // when registering set value to user role / permission (2 = registered user)

			array('tbl_user_role_id','default',

			      'value'=>2,

			      'setOnEmpty'=>false,'on'=>'insert'),	

			

			// scenario: update without changing password

			array('tbl_user_salutation_id, first_name, last_name, address_1, city, postcode, tbl_state_id, phone, email, tbl_user_interest_id', 'required', 'on'=>'update'),			

			

			// scenario: default scenario = update, when password is set then scenario = changePassword

			// http://www.yiiframework.com/forum/index.php?/topic/12229-best-way-to-implement-implicit-change-of-password-solved/			

			array('new_password, new_password_repeat', 'length', 'max'=>45),

			array('new_password', 'compare', 'on'=>'changePassword'),

			array('new_password, new_password_repeat', 'safe'),

			

			// scenario: all

			array('tbl_user_salutation_id, postcode, tbl_state_id, tbl_user_interest_id', 'numerical', 'integerOnly'=>true),

			array('first_name, last_name, address_1, address_2, city', 'length', 'max'=>45),

			array('phone', 'length', 'max'=>15),

			array('email', 'length', 'max'=>100),

			array('email', 'email'),

			array('password', 'length', 'max'=>45),

			array('created, modified', 'safe'),

			// The following rule is used by search().

			// Please remove those attributes that should not be searched.

			//array('id, tbl_user_salutation_id, first_name, last_name, address_1, address_2, city, postcode, tbl_state_id, phone, email, password, tbl_user_interest_id, tbl_user_role_id, last_login, created, modified, password_repeat', 'safe'/*, 'on'=>'search'*/),

			// prevents fields from being set to NULL instead of empty			

			/*array('tbl_user_salutation_id, first_name, last_name, address_1, address_2, city, postcode, tbl_state_id, phone', 'default', 'setOnEmpty'=>true, 'value' => 'null'),*/

	


		);

	}


	/**

	 * @return array relational rules.

	 */

	public function relations()

	{

		// NOTE: you may need to adjust the relation name and the related

		// class name for the relations automatically generated below.

		return array(

			'buyerDocuments' => array(self::HAS_MANY, 'BuyerDocuments', 'tbl_user_id'),

			'tblUserInterest' => array(self::BELONGS_TO, 'UserInterest', 'tbl_user_interest_id'),

			//'tblUserRole' => array(self::BELONGS_TO, 'UserRole', 'tbl_user_role_id'),

			'tblState' => array(self::BELONGS_TO, 'State', 'tbl_state_id'),

			'tblSalutation' => array(self::BELONGS_TO, 'UserSalutation', 'tbl_user_salutation_id'),

			'tblSellerCompanys' => array(self::MANY_MANY, 'SellerCompany', 'tbl_user_has_tbl_seller_company(tbl_user_id, tbl_seller_company_id)'),

		);

	}


	/**

	 * @return array customized attribute labels (name=>label)

	 */

	public function attributeLabels()

	{

		return array(

			'id' => 'ID',

			'tbl_user_salutation_id' => 'Salutation',

			'first_name' => 'First Name',

			'last_name' => 'Last Name',

			'address_1' => 'Address 1',

			'address_2' => 'Address 2',

			'city' => 'City',

			'postcode' => 'Postcode',

			'tbl_state_id' => 'State',

			'phone' => 'Phone',

			'email' => 'Email',

			'password' => 'Password',

			'tbl_user_interest_id' => 'Interested in',

			//'tbl_user_role_id' => 'Role',

			'created' => 'Created',

			'modified' => 'Modified',

			'last_login' => 'Last time logged in',

		);

	}


	/**

	 * Retrieves a list of models based on the current search/filter conditions.

	 * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.

	 */

	public function search()

	{

		// Warning: Please modify the following code to remove attributes that

		// should not be searched.


		$criteria=new CDbCriteria;


		$criteria->compare('id',$this->id);

		$criteria->compare('tbl_user_salutation_id',$this->tbl_user_salutation_id);

		$criteria->compare('first_name',$this->first_name,true);

		$criteria->compare('last_name',$this->last_name,true);

		$criteria->compare('address_1',$this->address_1,true);

		$criteria->compare('address_2',$this->address_2,true);

		$criteria->compare('city',$this->city,true);

		$criteria->compare('postcode',$this->postcode);

		$criteria->compare('tbl_state_id',$this->tbl_state_id);

		$criteria->compare('phone',$this->phone,true);

		$criteria->compare('email',$this->email,true);

		//$criteria->compare('password',$this->password,true);

		$criteria->compare('tbl_user_interest_id',$this->tbl_user_interest_id);

		//$criteria->compare('tbl_user_role_id',$this->tbl_user_role_id);

		$criteria->compare('created',$this->created,true);

		$criteria->compare('modified',$this->modified,true);


		return new CActiveDataProvider(get_class($this), array(

			'criteria'=>$criteria,

		));

	}




	/**

	* perform one-way encryption on the password before we store it in

	the database

	*/

	protected function afterValidate()

	{

		parent::afterValidate();

		$this->password = $this->encrypt($this->password);

	}

	public function encrypt($value)

	{

		return md5($value);

	}


	

}



Use




public function attach($owner)

{

    parent::attach($owner);


    $this->checkRequiredFieldsNotEmptyBehaviorFunction();

}



instead of




public function __construct()

{  

    $this->checkRequiredFieldsNotEmptyBehaviorFunction();

}



In the constructor, the owner is still "CheckRequiredFieldsNotEmptyBehavior".

Matt

Thanks guys, for future visitors, this is the code for the behavior. For calling the behavior in the model, see previous post.




<?php

/**

 * CheckRequiredFieldsNotEmptyBehavior

 *

 * Used by actionBuy in UserController 

 *

 * Checks whether a set of required fields are not empty 

 *

 * @author 

 *

 */

class CheckRequiredFieldsNotEmptyBehavior extends CActiveRecordBehavior {


	private $requiredColumns = array();

        private $owner;

        private $tableName;

        

        // set intial value of variable, will be set to 0 if one field is empty

	public $allDataProvided = 1;


	public function attach($owner)

        {

            parent::attach($owner);


            $this->checkRequiredFieldsNotEmptyBehaviorFunction();

        }

	

	

	// used by actionIndex of UserController

	public function checkRequiredFieldsNotEmptyBehaviorFunction()

	{


            // owner is the model (in this case) to which this behavior shall be attached to

            $this->owner = $this->getOwner();


            if (is_subclass_of($this->owner,'CActiveRecord')){


                // here all the attributes of the model

                $attributes = $this->owner->getAttributes();

                // tableName() must exist in the model we are attaching the behavior with

                $tableName = $this->owner->tableName();




		// set required fields for tables

                switch ($tableName) {

			case 'tbl_user':

					$requiredColumns = array(

						$this->owner->tbl_user_salutation_id,

						$this->owner->first_name,

						$this->owner->last_name,

						$this->owner->address_1,

						$this->owner->address_2,

						$this->owner->postcode,

						$this->owner->city,

						$this->owner->tbl_state_id,

						$this->owner->phone,

						$this->owner->email,

						$this->owner->tbl_user_interest_id

					);

					break;

						

		}


	   


		// iterate through each field and if one is empty, set $allDataProvided to 0

                foreach ($requiredColumns as $value) {

                    if (empty($value)) {

				$this->allDataProvided = 0;

			}

		}


		// break the reference with the last element, http://php.net/manual/en/control-structures.foreach.php

		unset($value);


            } else {

                // if !(is_subclass_of($this->owner,'CActiveRecord'))

                return false;

            }




        }

	

	


}



good ur problem solved.

But the way u r doing is a big drawback, an unnecessary data processing & thus performance fall.

As i see u must be using this behavior where ever u r taking the user input & then saving the model or doing some other stuff based on that input.

But calling the behavior function within the attach() will be executed everytime an instance of the model is created no matter u r creating it for user input or displaying its data.

So if u r showing 30 rows in the gridview this behavior function will be executed for each of them. What u r doing inside ur checkRequiredFieldsNotEmptyBehaviorFunction() is not required when viewing the data.

so think over it.

u can still use it anywhere like:

if defined in the model class just this


$model->checkRequiredFieldsNotEmptyBehaviorFunction();

and if not


$model->attachBehavior('check','application.behaviors.CheckRequiredFieldsNotEmptyBehavior');

$model->checkRequiredFieldsNotEmptyBehaviorFunction();

$model->detachBehavior('check');



Awesome. Here the whole code for future visitors of this post:

  1. Create the behavior as a file under protected/models/behaviors



<?php

/**

 * CheckRequiredFieldsNotEmptyBehavior

 *

 * Used by actionBuy in UserController 

 *

 * Checks whether a set of required fields are not empty 

 *

 * @author 

 *

 */

class CheckRequiredFieldsNotEmptyBehavior extends CActiveRecordBehavior {


	private $requiredColumns = array();

        private $owner;

        private $tableName;

        

        // set intial value of variable, will be set to 0 if one field is empty

	public $allDataProvided = 1;


	public function attach($owner)

        {

            parent::attach($owner);


            $this->checkRequiredFieldsNotEmptyBehaviorFunction();

        }

	

	

	// used by actionIndex of UserController

	public function checkRequiredFieldsNotEmptyBehaviorFunction()

	{


            // owner is the model (in this case) to which this behavior shall be attached to

            $this->owner = $this->getOwner();


            if (is_subclass_of($this->owner,'CActiveRecord')){


                // here all the attributes of the model

                $attributes = $this->owner->getAttributes();

                // tableName() must exist in the model we are attaching the behavior with

                $tableName = $this->owner->tableName();




		// set required fields for tables

                switch ($tableName) {

			case 'tbl_user':

					$requiredColumns = array(

						$this->owner->tbl_user_salutation_id,

						$this->owner->first_name,

						$this->owner->last_name,

						$this->owner->address_1,

						$this->owner->address_2,

						$this->owner->postcode,

						$this->owner->city,

						$this->owner->tbl_state_id,

						$this->owner->phone,

						$this->owner->email,

						$this->owner->tbl_user_interest_id

					);

					break;

						

		}


	   


		// iterate through each field and if one is empty, set $allDataProvided to 0

                foreach ($requiredColumns as $value) {

                    if (empty($value)) {

				$this->allDataProvided = 0;

			}

		}


		// break the reference with the last element, http://php.net/manual/en/control-structures.foreach.php

		unset($value);


            } else {

                // if !(is_subclass_of($this->owner,'CActiveRecord'))

                return false;

            }




        }

	

	


}



  1. Call the behavior from the controller:



public function actionSell()

	{


		// load all attributes and methods from db / model User

		// by using the ID set in UserIdentity.php

		// to see how to overwrite Yii::app()->user->id with id instead of email, see Agile-Web-Application-Development-with-Yii11-and-PHP5-eBook09022011_1063898.pdf p. 165

		$model = $this->loadModel(Yii::app()->user->id);




                $model->attachBehavior('check','application.models.behaviors.CheckRequiredFieldsNotEmptyBehavior');

                $model->checkRequiredFieldsNotEmptyBehaviorFunction();

                //$model->detachBehavior('check');

                 

                [...]




  1. Access the output of the behavior in the view for example:



<p>Step 1: Fill out <?php echo CHtml::link("user details",array('user/update'));

?>. <?php

if ($model->allDataProvided == 1) {?>

Done.

<?php } else { ?>

Not done.

<?php } ?>

</p>




Hi Mike,

I think you missed Anupam’s point. You should NOT explicitly call “checkRequiredFieldsNotEmptyBehaviorFunction()” from the attach() method since it will be fired every time the parent model is instantiated.

Your controller looks good. Simply remove the call to that method from your behavior and you should still have all the functionality plus a performance gain. Make sense?

One other thing, I’m not sure what your goals are for this extension so please correct me if I make incorrect assumptions. Firstly, it looks like you are using it to check if required fields are valid. Why not simply use the required input validator?

Also, you behavior is going to become extremely large and bloated if you have more than 1 or 2 tables and you’re doing a switch over the tables. May I suggest that the models should know about their required fields and pass them to the behavior instead of the other way round.




    public function behaviors()

    {

        return array(

            'CheckRequiredFieldsNotEmptyBehavior ' => array(

                'class' => 'application.extensions.CheckRequiredFieldsNotEmptyBehavior ',),

                'requiredFields' => $this->getRequiredFields(),

            ),

        );

    }


    private function getRequiredFields()

    {

        return array(

            $this->tbl_user_salutation_id,

            $this->first_name,

            $this->last_name,

            $this->address_1,

            $this->address_2,

            $this->postcode,

            $this->city,

            $this->tbl_state_id,

            $this->phone,

            $this->email,

            $this->tbl_user_interest_id

        );

    }



Matt

Thanks for your reply Matt. I need this extension for the following reason. Users can sign up with their email and password. Once logged in, users need to provide further information if they want to use our services. I use this function to check whether all required information has been submitted. Depending on the value this check returns, different content will be displayed.

I tried to implement your solution but I haven’t managed to get it working.

I think the $requiredField is an empty array. It fails at the foreach loop and returns “Undefined variable: requiredFields”. Also, I’m not sure if getRequiredFields(); does what I am after. For each of the fields it either needs to return a value or the information that this field is empty. Otherwise I can’t check whether the field is empty. Or maybe I could use the count function instead to see if the number of entries in the array match the number of required fields?

Any chance you could have another look at the code and tell me why the error message appears?

Thanks for your help…

Changes:

UserController: removed calling the action from the controller




                //$model->attachBehavior('check','application.models.behaviors.CheckRequiredFieldsNotEmptyBehavior');

                //$model->checkRequiredFieldsNotEmptyBehaviorFunction();



User Model:




	public function behaviors(){

		// automatically set created and modified timestamp for each record

                return array(

			'CTimestampBehavior' => array(

				'class' => 'zii.behaviors.CTimestampBehavior',

				'createAttribute' => 'created',

				'updateAttribute' => 'modified',

			),

		

                

                        'CheckRequiredFieldsNotEmptyBehavior' => array(

                            'class' => 'application.models.behaviors.CheckRequiredFieldsNotEmptyBehavior',

                            'requiredFields' => $this->getRequiredFields(),

                        )

                        

                );                

	}




        public function getRequiredFields()

        {

            return array(

                $this->tbl_user_salutation_id,

                $this->first_name,

                $this->last_name,

                $this->address_1,

                $this->address_2,

                $this->postcode,

                $this->city,

                $this->tbl_state_id,

                $this->phone,

                $this->email,

                $this->tbl_user_interest_id

            );

        }




Behavior:




<?php

/**

 * CheckRequiredFieldsNotEmptyBehavior

 *

 * Used by actionBuy in UserController 

 *

 * Checks whether a set of required fields are not empty 

 *

 * @author 

 *

 */

class CheckRequiredFieldsNotEmptyBehavior extends CActiveRecordBehavior {


	//private $requiredColumns = array();

        private $owner;

        //private $tableName;

        

        // set intial value of variable, will be set to 0 if one field is empty

	public $allDataProvided = 1;


        public $requiredFields = array ();


	public function attach($owner)

        {

            parent::attach($owner);


            $this->checkRequiredFieldsNotEmptyBehaviorFunction();

        }

	

	

	// used by actionIndex of UserController

	public function checkRequiredFieldsNotEmptyBehaviorFunction()

	{


            // owner is the model (in this case) to which this behavior shall be attached to

            $this->owner = $this->getOwner();


            if (is_subclass_of($this->owner,'CActiveRecord')){


                // here all the attributes of the model

                //$attributes = $this->owner->getAttributes();

                // tableName() must exist in the model we are attaching the behavior with

                //$tableName = $this->owner->tableName();




		// set required fields for tables

                /*switch ($tableName) {

			case 'tbl_user':

					$requiredColumns = array(

						$this->owner->tbl_user_salutation_id,

						$this->owner->first_name,

						$this->owner->last_name,

						$this->owner->address_1,

						$this->owner->address_2,

						$this->owner->postcode,

						$this->owner->city,

						$this->owner->tbl_state_id,

						$this->owner->phone,

						$this->owner->email,

						$this->owner->tbl_user_interest_id

					);

					break;

						

		}*/


	   


                //$requiredFields = array(11,12,13);


                // iterate through each field and if one is empty, set $allDataProvided to 0

                foreach ($requiredFields as $value) {

                    if (empty($value)) {

				$this->allDataProvided = 0;

			}

		}


		// break the reference with the last element, http://php.net/manual/en/control-structures.foreach.php

		unset($value);


            } else {

                // if !(is_subclass_of($this->owner,'CActiveRecord'))

                return false;

            }




        }

	

	


}



The reason the $requiredFields is empty is that the variables aren’t assigned in or before the attach() method. Since you are inheriting from CActiveRecordBehavior, you should override the before/AfterSave() method OR inherit from CComponent.

If you inherit from CActiveRecord, overrride Before/AfterSave(). This will fire on the corresponding CActiveRecord method.

If you inherit from CComponent, call $model->checkRequiredFieldsNotEmptyBehaviorFunction(); from your controller.

I will post some code tomorrow - when I’m sober!

Cheers.

Hi Mike,

I think I know what you’re trying to accomplish. I don’t think you should inherit from CActiveRecordBehavior since that class is intended for you to override on the Before/After methods I.e. beforeSave, AfterDelete etc. Instead, inherit from CBehavior. It should provide all the functionality you need.

Try this:




<?php

/**

 * OptionalFieldBehavior class file.

 *

 * @author Matt Skelton

 * @date 23-Mar-2011

 */


/**

 * Description

 */

class OptionalFieldBehavior extends CBehavior

{

    public $requiredFields = array();


    public function checkOptionalFields()

    {

        $isValid = true;


        foreach ($this->requiredFields as $key => $value)

        {

            if (empty($value))

            {

                $isValid = false;

            }

        }


        return $isValid;

    }

}

?>



Model Class




    public function getRequiredFields()

    {

        return array(

            $this->tbl_user_salutation_id,

            $this->first_name,

            $this->last_name,

            $this->address_1,

            $this->address_2,

            $this->postcode,

            $this->city,

            $this->tbl_state_id,

            $this->phone,

            $this->email,

            $this->tbl_user_interest_id

        );

    }


    public function behaviors()

    {

        return array(

            'FieldValidator' => array(

                'class' => 'site.common.components.behaviors.OptionalFieldBehavior',

                'requiredFields' => $this->getRequiredFields(),

            ),

        );

    }



Controller




if ($model->checkOptionalFields())

{

    // all is valid

}



Only two words. Perfect and thanks.