Model For Dynamic Table Name

Hi all.

Thanks for reading. I’m not a newbie, but not very experimented with Yii and I need to create some tables using this schema (MovMMYYYY ==> Mov012012, Mov022012… Mov012013, etc)

So, how can I handle this in Yii? I was reading some posts about this but nobody have a concrete solution. Does anybody knows how to do it?

Thank you in advance.

Dear Friend

We have to declare static properties in model and we can change them dynamically.

We have a Model Person.

Then we can use the same model for student,teacher and staff.

Person.php




class Person extends CActiveRecord

{   

        public static $table;

	

	public function tableName()

	{

		return self::$table;

	}

...................

...................



At run time we can now assign a new table by the follwing way.




$table="teacher";

if(class_exists("Person"))

    Person::$table=$table; //or $this->table; It may be a property of another component or obtained from user input.



I hope I helped a bit.

Regards.

Many thanks you helped me out a lot.

Have a look here:

http://www.yiiframework.com/extension/dynamic-active-record/

When adapting this to the example of "Persons" model:

  1. The table structure for both students and teachers must be identical.

  2. You will need to create an empty database table called "Persons", sharing this structure as well. It is necessary for CGridView as a table schema source. No data will be ever written to this table but you will get errors from CGridView unless such a "dummy" table exists.

Conseqently, your "Persons" model will have to look like:


<?php


class Persons extends CActiveRecord

{


    protected $_tableName;

    protected $_md;




    public function __construct($scenario = 'insert', $tableName = null)

    {

        $this->_tableName = $tableName;

        parent::__construct($scenario);

    }


    protected function instantiate($attributes)

    {

        return new Lista(null, $this->tableName());

    }




    public function getMetaData()

    {

        if ($this->_md !== null)

            return $this->_md;

        else

            return $this->_md = new CActiveRecordMetaData($this);

    }


    public function tableName()

    {

        if (!$this->_tableName)

            $this->_tableName = parent::tableName();

        return $this->_tableName;

    }


    public static function forTable($tableName, $scenario = 'insert')

    {

        return new Lista($scenario, $tableName);

    }


    // Rest of model code below

This way you may replicate all the functionality of the Yii active record using dynamic table names in model. For instance in the "Persons" controller you use it like this:




//$tableName is either "students" or "teachers"

public function loadModel($id, $tableName)

{

   $model = Persons::forTable($tableName);

   $model = $model->findByPk($id);

   if($model === null)

      throw new CHttpException(404,'The requested page does not exist.');

   return $model;

}

Rgs,

Dear Friend

Here is one implementation of the above concept.

I have created a module person.

modules/person/PersonModule.php




<?php


class PersonModule extends CWebModule

{   

	

	public $table;

    

	public function init()

	{


		$this->setImport(array(

			'application.modules.person.models.*',

			'application.components.person.components.*',

		));


		if(class_exists("Profile"))

		    Profile::$table=$this->table;

	}


//below are the default things generated by GII

	public function beforeControllerAction($controller, $action)

	{

		if(parent::beforeControllerAction($controller, $action))

		{    

			return true;

		}

		else

			return false;

	}

}




Now I am having

  1. Model Profile == modules/person/models/Profile.php

  2. Controller ProfileController == modules/person/models/ProfileController.php

3.views == modules/person/models/views/profile.

All the things are generated bi GII from a table person in database.

Table person was deleted after creating these files.

modules/person/models/Profile.php




class Profile extends CActiveRecord

{      

        public static $table;

	

	public function tableName()

	{

		return self::$table;

	}


//Rest of the contents of AR.........



In main.php I am instantiating the new applications in the follwing way.





	'modules'=>array(

		...................................................

                ...................................................

		'student'=>array('class'=>'application.modules.person.PersonModule','table'=>'student'),

		'teacher'=>array('class'=>'application.modules.person.PersonModule','table'=>'teacher'),

               ......................................................

               ......................................................

	),




Now we have created two application student and teacher.

Now we can list,view ,update and delete actions in the following way.




index.php?r=student/profile/view&id=1






index.php?r=teacher/profile/create






index.php?r=teacher/profile/update&id=4



I think the only prerequsite here the structure of tables student and teacher should be same as person.

There is no need for the presence of a table with class name.

When ActiveRecord try to create metadata, it invokes AR::tablename() rather than using the classname.

Regards.

Respect!

Though I am a bit reluctant in case of instantiating new applications in config file.

This is NOT dynamic way!

I really like when the code is flexible and if you need a new table - you can declare it in a dynamic way rather than pre-declaring it in configuration.

Your solution is very nice, especially I like avoiding invoiking classname while creating metadata, but… in fact you create a dummy database table just once and is easy and you maintain full flexibility…

Imagine my appliaction (a bulk email sender application) where each and every new campaign you upload a new distribution list (list of e-mail addresses) to the server, so you have a new table created dynamically every day.

Dear Friend

Yes you are absolutely correct.

When there are plethora of tables using a single model,instantiating applications in config file is poor approach.

This is was done to just to bit explain things.

Regards.

And would you be so kind, Seenivasan, to explain me better why CGridView is trying to collect metadata from the classname table? I was a bit surprised when I found providing a table name in a model is not enough for CGridView widget and that it still tries to refer to a table which name is equal to a model name.