Yii Framework Forum: Create property inside a model - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Create property inside a model Rate Topic: -----

#1 User is offline   manilodisan 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 80
  • Joined: 17-September 09
  • Location:Bucharest

Posted 01 December 2009 - 06:42 AM

Currently there's no way to create a property inside a model method:
$this->$dynamicVar = 'some value';

This is because the setter is overridden by CActiveRecord. I need this to allow custom fields inside the register model such as name, age etc etc whatever the admin needs from new users so it's a dynamic value all the time. Has anyone encountered this problem?
0

#2 User is offline   Sander 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 169
  • Joined: 03-November 09
  • Location:Amsterdam, Netherlands

Posted 01 December 2009 - 07:13 AM

I'm not really sure I understand you correctly, but if I do, you could try:
$this->__set($dynamicVar, 'some value');


If that's not what you mean, please describe your problem in a little more detail :)
0

#3 User is offline   manilodisan 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 80
  • Joined: 17-September 09
  • Location:Bucharest

Posted 01 December 2009 - 05:45 PM

That's what I mean allright. The problem is that this magic function is overridden by CActiveRecord which of course is extended by my model:
public function __set($name,$value)
{
	if($this->setAttribute($name,$value)===false)
	{
		if(isset($this->getMetaData()->relations[$name]))
			$this->_related[$name]=$value;
		else
			parent::__set($name,$value);
	}
}

public function setAttribute($name,$value)
{
	if(property_exists($this,$name))
		$this->$name=$value;
	else if(isset($this->getMetaData()->columns[$name]))
		$this->_attributes[$name]=$value;
	else
		return false;
	return true;
}


As you can see, setAttribute returns false when you try to create a model property on the fly because property_exists($this,$name) returns false isset($this->getMetaData()->columns[$name]) returns false as well so the magic function __set does not set the property. So the function calls parent::__set($name,$value); so it goes to this:

public function __set($name,$value)
{
	$setter='set'.$name;
	if(method_exists($this,$setter))
		return $this->$setter($value);
	else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
	{
		// duplicating getEventHandlers() here for performance
		$name=strtolower($name);
		if(!isset($this->_e[$name]))
			$this->_e[$name]=new CList;
		return $this->_e[$name]->add($value);
	}
	else if(is_array($this->_m))
	{
		foreach($this->_m as $object)
		{
			if($object->getEnabled() && (property_exists($object,$name) || $object->canSetProperty($name)))
				return $object->$name=$value;
		}
	}
	if(method_exists($this,'get'.$name))
		throw new CException(Yii::t('yii','Property "{class}.{property}" is read only.',
			array('{class}'=>get_class($this), '{property}'=>$name)));
	else
		throw new CException(Yii::t('yii','Property "{class}.{property}" is not defined.',
			array('{class}'=>get_class($this), '{property}'=>$name)));
}


The conclusion is, we can't create properties inside a model. Should I create my own setter for this model? Is this safe?

Posted Image
0

#4 User is offline   Sander 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 169
  • Joined: 03-November 09
  • Location:Amsterdam, Netherlands

Posted 02 December 2009 - 03:38 AM

I think I'd try something like this:

private $dynamicAttributes = array();

public function __set($attr, $value) {
    if(parent::__set($attr, $value)===false) {
        $this->dynamicAttributes[$attr] = $value;
    }
}

public function __get($attr) {
    return $this->__isset($attr) ? parent::__get($attr) : $this->dynamicAttributes[$attr];
}


Would that work for you?
2

#5 User is offline   manilodisan 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 80
  • Joined: 17-September 09
  • Location:Bucharest

Posted 02 December 2009 - 06:56 AM

Thanks, I appreciate it. Here's what I ended up with:

	public function __get ( $name ) {
		if ( isset ( $this->dynAttributes [ $name ] ) ) return $this->dynAttributes [ $name ];
		else
			return parent::__get ( $name );
	}

	public function __set ( $attr, $value ) {
		try {
			parent::__set ( $attr, $value );
		} catch ( CException $e ) {
			$this->dynAttributes [ $attr ] = $value;
		}
	}


I use a try catch because CComponent throws an exception if __set fails.
0

#6 User is offline   Sander 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 169
  • Joined: 03-November 09
  • Location:Amsterdam, Netherlands

Posted 02 December 2009 - 07:07 AM

Cool, that looks fine :)
0

#7 User is offline   nexus246 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 12
  • Joined: 02-December 09

Posted 02 December 2009 - 01:50 PM

For
private $somevalue;

in model class def this works for me:
function setSomevalue($value) {
  $this->somevalue = $value;
}
function getSomevalue($value) {
  return $this->somevalue;
}

0

#8 User is offline   manilodisan 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 80
  • Joined: 17-September 09
  • Location:Bucharest

Posted 02 December 2009 - 07:52 PM

View Postnexus246, on 02 December 2009 - 01:50 PM, said:

For
private $somevalue;

in model class def this works for me:
function setSomevalue($value) {
  $this->somevalue = $value;
}
function getSomevalue($value) {
  return $this->somevalue;
}


That's because you already declared it in the class: private $somevalue;

I retrieve those fields based on admin's settings so I can't declare them. I must create them on the fly. Try setting $this->somevalue = $value; without having it declared previously using private $somevalue;
0

#9 User is offline   Gonzalo M. 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 5
  • Joined: 05-March 14

Posted 19 March 2014 - 10:18 AM

Check this out:
Understanding Virtual Attributes and get/set methods

if you create a method like this in your model class:
class Person extends CActiveRecord {
   public function getFullName()
   {
      return $this->firstname . " " . $this->lastname;
   }
   ...
}


You can call it like normal ways:
// in a view somewhere
echo $form->dropDownList($model, 'personid',
    CHtml::listData( Person::model()->findAll(), 'id', 'fullname' )
);

$x = $model->fullname;
$x = $model->getFullname();        // same thing

0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users