pass id to constructor

Hi,

I’ve got some legacy code I’m trying make work with Active Record and Yii.

The old code often passes the primary key data of an object to the constructor when creating it, as in:




$p = new Person(1253); //1253 is the id of the person we want.



I’ve created a class that extends CActiveRecord and overridden constructor like so:




public function __construct($arg) {

  

   parent::__construct($scenario); 

   if(!empty($arg)) {

      $this->id = $arg;

      $this->refresh();

   }

}



but oddly, the script seems to die because of this line:

  $this->id = $arg;

it doesn’t like me assigning anything to a model attribute inside the constructor.

Is there anyway around this? or is using refresh this the wrong approach? I simply want to look up a record from the database at the time of construction.

Many thanks for your help,

-Charlie




$p = new Person();

$p->refresh(12345);



will be better

If you have to retrive from database a model, use Person::model()->findByPk($id);

The solutions you’ve provided would create a completely separate object - not populate the attributes of the class while it’s being constructed.

I might need to clarify what I’m doing. I’m trying to take an large codebase that was not developed with Yii and make it work with Yii’s Active Record.

Currently there are a lot of legacy model classes. They all extend one ORM class - let’s call it: DataObject

So Person extends DataObject.

Rather than recoding all the legacy models - and the code that uses those models - to work with ActiveRecord and Yii - I thought I could just recode DataObject - so that it becomes a wrapper for ActiveRecord. DataObject would now extend ActiveRecord - any old methods in DataObject would be rewritten to use ActiveRecord calls and all the old code would still work, but I’d be able to start using the existing models in Yii (because they now extend ActiveRecord, through this DataObject class).

In our old DataObject class, you could pass the id of a record to the constructor like this:




$p = new Person(1253);



and it would build the new Person object with the data for record #1253 already populated. Going forward, you’re right, we’ll use the normal active records calls to do this. But the old code has to work - and I don’t want to have to rewrite all of it at once.

So how can I override the CActiveRecord constructor so that when the old code passes the id to the constructor, it’ll create an object with the data for that row populated.

The current issue I’m having is that I can’t seem to assign ActiveRecord attributes in the overridden constructor.




class DataObject extends CActiveRecord {

  public function __construct($arg) {

  

     parent::__construct($scenario); 

     if(!empty($arg)) {

       $this->id = $arg;

       $this->refresh();

     }

  }

}



Yii bails without an error on




$this->id=$arg



Is there some other way to look up the values of an object from within the constructor?

I think the solution for this might be helpful to others who are trying to phase Yii in to their existing codebase.

So after looking into it further it looks like what’s happening is that the magic __set method in CActiveRecord creates the model if the metadata for the object are not set. This in turn calls the constructor on the object, and it results in an infinite loop (?) - which is why Yii is bailing with no error.

So in other words:

We’re trying to assign a value to $this->id before the metadata to support it have been created.

We’ve almost found a solution but there’s one last hitch and I’m on the fence as to whether to create a new forum topic or not…

Seems like the following should work:




Class DataObject extends CActiveRecord {


       var $arg = ''; // a place to store the constructor argument for use once the object's been fully created


	public function __construct($arg = NULL) {

		parent::__construct($scenario);

		$this->arg = $arg; // since this variable is declared above, it does not call

                                   // the magic __set method, which is what was causing the problem

	}

	

	public function init() {

		$this->id = $args[0]; // will have to sort out getting the actual 

                                      // primary key name here, it might not be id

		$this->refresh();

	}

}



This seems like it ought to work, but it doesn’t… because init is only run if $scenario is set.

But when I try to set scenario to anything but ‘null’ such as…




	public function __construct($arg = NULL) {

                $scenario = 'insert';

		parent::__construct($scenario);

		$this->arg = $arg; // since this variable is declared above, it does not call

                                   // the magic __set method, which is what was causing the problem

	}



…Yii bails. At this point all I need to solve this issue is a way to pass a non-null scenario to the CActiveRecord constructor - but for some reason, it won’t accept ‘insert’ as a parameter - even thought this is default value assigned in the CActiveRecord constructor.

This may be worth a try




public function init() {

  $this->id = $args[0]; // will have to sort out getting the actual 

                                      // primary key name here, it might not be id

  $this->setScenario(null);

  $this->refresh();

}



/Tommy