Adding properties to model

In addition on this topic: http://www.yiiframew…php?topic=225.0

I would like to know, how I can add properties dynamically to a model?

What I want to do is, that I define an array with fields like that:

class News extends CActiveRecord

{

  public $arrTranslationField = array('strTitleEn', 'strTitleDe');

 

  …

}

and now I want to get is:

$this->strTitleEn

$this->strTitleDe

I don't do add these properties by doing:

public $strTitleEn;

public $strTitleDe;

because, later in the code, I think I need to wiork with the array. It’s in preparation for soilving the problem described here: http://www.yiiframew…pic,1510.0.html

I have the same requirement of BitMatix, I want to add to the model attributes some other properties that are in a array (the array is set in a method of the controller), so I wouldn’t define them fixed as public variable in the model but I would read the array and creates dinamically the new attributes, I tried to create the properties in the init() of the model in this way but then when I try to use them I have an error, this is the code:




public function init()

{

    parent::init();


    //Set the array with the additional properties

    $listField= Yii::app()->controller->initField();


    if ($listField !== array()) { 

      foreach ($listField as $name=>$value){

         //Initialize the new variable

         $this->$value=null;

      }

    }


  }




Is this possible and is this the right way?

I verified that $this->$value is correctly set in the init(), but when I try to use it for example in the views I get the error message:

"Myclass"."additionalfield" is not defined.

I’m not 100% sure I’m answering your question correctly, but you could do the following. This is similar to how Yii handles its own model properties.




class MyModel extends CActiveRecord

{

  protected $allowedAttributes = array(

    'reference1',

    'reference2',

  );

  protected $attributeValues = array();


  public function __get($name)

  {

    if(in_array($name, $this->allowedAttributes)) {

      return $this->attributeValues[$name];

    } else {

      return parent::__get($name);

    }

  }


  public function __set($name, $value)

  {

    if(in_array($name, $this->allowedAttributes)) {

      return $this->attributeValues[$name] = $value;

    } else {

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

    }

  }

}



For the love of Google, don’t forget to add the parent calls to __get and __set, otherwise everything will break.

This is probably not necessary if the data you’re accepting is safe.

Thank Datashaman that’s the right solution by overriding __get and __set, then I set values of array $attributeValues where I need (in my case: model->init() and controller->loadclass())

I think I don’t need the check on $allowedAttributes array as I add the extra fields in safeAttributes method (always dinamically) so I modify the code in:




class MyModel extends CActiveRecord

{

  protected $attributeValues = array();


  public function __get($name)

  {

    if(array_key_exists($name, $this->attributeValues))

      return $this->attributeValues[$name];

    } else {

      return parent::__get($name);

    }

  }


  public function __set($name, $value)

  {

    if(array_key_exists($name, $this->attributeValues))

      return $this->attributeValues[$name] = $value;

    } else {

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

    }

  }

}



Learned that setters don’t return a value, so the returns above are superfluous. Odd behaviour, IMO. Native assignment returns the value assigned, but setters don’t. So you can’t chain these like so: $a = $b = $this->property;