Dynamic Table Name In Relation

Hi everyone!

I created a “shard table manager” to be able to use my models with a dynamic name. The thing is, when I need to create a relation I have a problem, I can’t dynamically add the table extension to my relation. Here is the code I am using and that is not working:




class StatReport extends ShardedActiveRecord{

...

public function relations()

	{

		// NOTE: you may need to adjust the relation name and the related

		// class name for the relations automatically generated below.

		return array(

			'StatInfos' => array(self::HAS_MANY, 'StatInfo'.$this->getShard(), 'report_id'),

		);

	}

}



It is not working because the model expect the file StatInfo<shard>.php to exist… Is there a way to dynamically allocate a relation with a reference to the StatInfo.php model page?

Thank you for your help!

you could always go back to good old query builder and do a join query

It is an option… But I wanted am looking for a model based solution… If it is possible!

I believe its possible but you probably have to digg into Yii core and figure out how relationships are implemented its a interesting problem I am trying to reproduce this might take me sometime

Thank you!

I have been thinking about this and I came up with a solution that should work! I had to reimplement the CActiveFinder and the CActiveRecord classes. I am not sure if everything I did is clean so here is the code, feel free to comment!

The ShardedActiveRecord class (Reimplementation of CActiveRecord):




class ShardedActiveRecord extends CActiveRecord{

	private $_shard;

	

	public function tableName(){

		return get_class($this) . $this->getShard();

	}

	

	public function setShard($shard) {

		$connection=Yii::app()->db;

		$command = $connection->createCommand("SHOW TABLES LIKE '".get_class($this).$shard."'");

		if(!$command->execute())

			throw new CHttpException(404,'The specified table cannot be found.');

	

		$this->_shard = $shard;

		call_user_func(array(get_class($this), 'model'))->_shard = $shard;

		

		$this->refreshMetaData();

		

		return $this;

	}


	public function getShard() {

		if($this->_shard === null){

			$this->setShard("");

		}

		return $this->_shard;

	}

	

	public function createShardedTable($shard){

		$connection=Yii::app()->db;

		$command = $connection->createCommand("CREATE TABLE IF NOT EXISTS ".get_class($this).$shard." LIKE ".get_class($this));

		$command->execute();

	}

	

	public function beforeSave(){

		return parent::beforeSave();

	}

	

	public function getMergedDataProvider($params, $criteria = null){

		$modelArray = array();

		$model = array();

		foreach ($params as $param){

			$tmpmodel = $this->model()->setShard($param);

			

			if($criteria === null){

				$data = $tmpmodel->findAll();

			}else{

				$data = $tmpmodel->findAll($criteria);

			}

			

			if(count($data) != 0){

				array_push($modelArray, $data);

			}

		}

		

		foreach($modelArray as $ma){

			$model = array_merge($model, $ma);

		}

		return $model;

	}

	

	public function getActiveFinder($with)

	{

		return new ShardedActiveFinder($this,$with);

	}

}



The ShardedActiveFinder class (Reimplementation of CActiveFinder):




class ShardedActiveFinder extends CActiveFinder{

	private $_shard;

	

	public function __construct($model,$with)

	{

		$this->_shard=$model->getShard();

		parent::__construct($model,$with);

	}

	

	public function getModel($className)

	{

		return ShardedActiveRecord::model($className)->setShard($this->_shard);

	}

}



Some feedback would be really appreciated! Thank you.