getChanged(), isChanged() methods in AR

I have a small proposal to implement a way to see what attributes of an ActiveRecord instance have changed. So, when I call



$post=Post::model()->findbyPk(1);


$post->content='something new'; 


$post->getChanged(); //array('content');


$post->isChanged('content');//true


I don't think there is a way know to find out. It could be handy for not reparsing, rehashing, recaching or restripping stuff. Also, if nothing's changed there's no need to execute an update statement to the sql server.

This is probably better to be implemented using a behavior.

http://www.yiiframew…doc/cookbook/9/

It’s possible but it’ll add too much overhead I think, I’ll settle with overriding the __set() method :)

BTW I meant changes in runtime, so between loading a record and saving it. Not in between different requests.

The drawback with modifying __set is that it adds overhead to all AR, even if they don't use this feature.

I modified __set only in the Post model class not in the ActiveRecord class and I called parent::__set to not interfere with the normal stuff.

That should be fine, but then this is no longer a feature request. ;)

I figured it could be useful for others :) For example the hashing of a password or the parsing of a markdown text should only be done when it is changed and only once. If isChanged() were there I could write a validator to implement such behaviour in my rules. Basically something like ‘md5()/parse() if it’s changed else leave it alone’. It’s no big deal though.

Maybe you can write a cookbook article about this?

I'l get right on it. I have some other ideas for articles but am busy enough as it is. I'll use the __set method though.

One more thing, the __set() method and the setAttribute method both both _attributes[$name] to set a value of a field. Wouldn't it be better if there were only one way to change the value of a field.

So



	public function __set($name,$value)


	{


		if(isset($this->getMetaData()->columns[$name]))


			$this->_attributes[$name]=$value;


		else if(isset($this->getMetaData()->relations[$name]))


			$this->_related[$name]=$value;


		else


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


	}


Would become



	public function __set($name,$value)


	{


		if(isset($this->getMetaData()->columns[$name]))


			$this->setAttribute($name,$value); //this line


		else if(isset($this->getMetaData()->relations[$name]))


			$this->_related[$name]=$value;


		else


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


	}


The same goes for the getAttribute/__get. What I showed above, changing the __set method, would have to happen twice, once in the __set, once in the setAttribute to make it fool proof.