Make massive assignment work with setters in CActiveRecords too

If you have an ActiveRecord with custom setters like this:




<?php

class MyRecord extends CActiveRecord

{

    ...

    public function setTest($value)

    {

        $this->something = $value;

    }

}



then you can’t assign test with massive assignment:




<?php

$model = new MyRecord;

$model->setAttributes(array(

    'test' => 'testvalue',

));

because in CActiveRecord::setAttributes() we use property_exists(), which does not detect getters/setters:




<?php


    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;

    }



This is an unneccesary limitation i think. It also works for CFormModel so why not make it work for ActiveRecords, too?

Use cases:

  • Deal with HAS_MANY relations, e.g. create/delete entries in the connection table inside the setter

  • "Virtual attributes" for formatting/parsing decimals/dates (i18n)

Makes sense. Post it to github. Ideally with pull-request.

I needed this in something I was working on so I made the change below in case anyone else wants it. Code might be off a bit but seems to be working for me so far.




	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 if(method_exists($this,'set'.ucfirst($name)) && $name != 'attributes' && ucfirst($name) != 'Attribute') {

	            $this->{'set'.ucfirst($name)}($value);

        }

		else

			return false;

		return true;

	}