build a model dynamically , attributes ??

Hi

I’m building dynamically a model that extends CformModel


function __construct(){

      $survey = new SurveyModel();

      foreach ($survey->oMeetingSurvey[get_class($this)] as $key => $value) {

          echo 'public $'.$key.';<br/>';

          $this->$key = '';

      }

      parent::__construct();

    }

then in the process it needs to use $model->attributes

which should be an arrays whit a classic model(not build dyn.)

but with my dynamic version it just doesn’t have the intended value.

maybe someone has a brilliant idea ?

I’ve done something similar. I overwrite _get and _set in my model like this:




public function __get($name) {

 if(TCFormHelper::startsWith($name, 'name_')){

 $lang = substr($name,-2);

 $relName = 'articleName_'.$lang;

 	

 if(isset($this->$relName->translation))

   return $this->$relName->translation;

 else 

  return null;

 }

 elseif(TCFormHelper::startsWith($name, 'price_')){

  $iso = substr($name,-3);

  $relName = 'articlePrice_'.$iso;

  if(isset($this->$relName->cua_price))

   return $this->$relName->cua_price;

  else 

   return '';

  }

  else

   $return = parent::__get($name);

    	

  return $return;

}

     

public function __set($name, $value)

{

  if(TCFormHelper::startsWith($name, 'name_') || TCFormHelper::startsWith($name, 'price_') ){

    $this->$name = $value;

  } 

  else

    parent::__set($name, $value);

}



This generates model-properties for article-name in different languages and price-values in different currencies e.g.:


$article->name_en

$article->name_fr


$article->price_EUR

$article->price_USD

The validation-rules and relations are also generated dynamically.

Then I can directly access this dynamic fields in e.g. a CActiveForm.

Following code generates input-fields for every available system-language:




<?php foreach(array_keys(Yii::app()->params['i18n']) as  $lang): ?>

<div class="row">

  <?php echo $form->labelEx($model,Article::getI18nName($lang)); ?>

  <?php echo $form->textField($model,Article::getI18nName($lang)); ?>

  <?php echo $form->error($model,Article::getI18nName($lang)); ?>

</div>

<?php endforeach;?>



I would suggest extending approach used by Yii for table attributes using metadata.

  1. Have an array / CMap where you can store data using key / value pair.

  2. Overwrite __set & __get methods to check in the array / CMap defined otherwise call parent’s __set / __get

here are two very interesting reads about this topic:

in the Yii perspective :

http://www.yiiframework.com/wiki/167/understanding-virtual-attributes-and-get-set-methods

http://smartart.it/2011/11/05/how-yii-virtual-attributes-work

more general php :

http://krisjordan.com/dynamic-properties-in-php-with-stdclass