Yii2. Adding attribute and rule dynamically to model

15,779

Add Dynamic Attributes to a existing Model

When you want to add dynamic attributes during runtime to a existing model. Then you need some custom code, you need: A Model-Class, and a extended class, which will do the dynamic part and which have array to hold the dynamic information. These array will merged in the needed function with the return arrays of the Model-Class.

Here is a kind of mockup, it's not fully working. But maybe you get an idea what you need to do:

class MyDynamicModel extends MyNoneDynamicModel
{

private $dynamicFields = [];
private $dynamicRules = [];

public function setDynamicFields($aryDynamics) {
     $this->dynamicFields = $aryDynamics;
}

public function setDynamicRules($aryDynamics) {
     $this->dynamicRules = $aryDynamics;
}

public function __get($name)
{
    if (isset($this->dynamicFields[$name])) {
        return $this->dynamicFields[$name];
    }

    return parent::__get($name);
}

public function __set($name, $value)
{
if (isset($this->dynamicFields[$name])) {
  return $this->dynamicFields[$name] = $value;
}
return parent::__set($name, $value);
}

public function rules() {
  return array_merge(parent::rules, $this->dynamicRules);
}
}

Full Dynamic Attributes

When all attributes are dynamic and you don't need a database. Then use the new DynamicModel of Yii2. The doc states also:

DynamicModel is a model class primarily used to support ad hoc data validation.

Here is a full example with form integration from the Yii2-Wiki, so i don't make a example here.

Virtual Attributes

When you want to add a attribute to the model, which is not in the database. Then just declare a public variable in the model:

public $myVirtualAttribute;

Then you can just use it in the rules like the other (database-)attributes.

To do Massive Assignment don't forget to add a safe rule to the model rules:

public function rules()
{
    return [
        ...,
        [['myVirtualAttribute'], 'safe'],
        ...
    ];
}

The reason for this is very well explained here: Yii2 non-DB (or virtual) attribute isn't populated during massive assignment?

Share:
15,779

Related videos on Youtube

Eduardo
Author by

Eduardo

A technology lover, a full time learner, awesome coder and ideas generator with experience in development and management.

Updated on September 15, 2022

Comments

  • Eduardo
    Eduardo over 1 year

    I am writing a widget and I want to avoid user adding code to their model (I know it would be easier but using it to learn something new).

    Do you know if it is possible to add an attribute (which is not in your database, so it will be virtual) to a model and add a rule for that attribute?. You have no access to change that model code.

    I know rules is an array. In the past I have merged rules from parent class using array_merge. Can it be done externally? Does Yii2 has a method for that?

    An idea is to extend model provided by the user with a "model" inside my widget an there use:

        public function init() {
          /*Since it is extended this not even would be necessary, 
          I could declare the attribute as usual*/
    
          $attribute = "categories";
          $this->{$attribute} = null; //To create attribute on the fly
    
          parent::init();
        }
    
        public function rules() {
          $rules = [...];
    
          //Then here merge parent rules with mine.
          return array_merge(parent::rules, $rules);
        }
    

    But If I extend it, when I use that model in an ActiveForm in example for a checkbox, it will use my "CustomModel", so I want to avoid that. Any other ideas? How to do it without extending their model?

  • Eduardo
    Eduardo almost 8 years
    Thanks for your answer. Ideally what I want to achieve is adding that virtual attribute $myVirtualAttribute and its rules from outside the model. Extending the model was a possible solution I was thinking about :)
  • devOp
    devOp almost 8 years
    Ah okay. You mean a dynamic attribute.
  • Eduardo
    Eduardo almost 8 years
    Yes, exactly. I will edit my question to use that name
  • Eduardo
    Eduardo almost 8 years
    I see you have updated your answer. My model extends from ActiveRecord but I want to do add it ony Dynamic attribute, can that be achieved?
  • devOp
    devOp almost 8 years
    Yes i did it in yii, i am updating my answer.
  • Eduardo
    Eduardo almost 8 years
    I would like to add you to my skype to talk in general about yii when you have time, is there a chat in stackoverflow? or pm?
  • devOp
    devOp almost 8 years