Yii 1.1: cdynamicrecord

CDynamicRecord allows a single model class access to multiple tables of the same type across multiple databases.
4 followers

CDynamicRecord

Code is available on Github https://github.com/charlesportwoodii/CDynamicRecord.

Github will always have the most up to date documentation and source code. Always reference there for the latest details.

Read & Learn More on My Blog https://www.erianna.com


CDynamicRecord

CDynamicRecord is an ActiveRecord implementation for Yii that allows for an abstract class to connect to multiple databases tables of the same type across multiple databases using the same ActiveRecord method calls as you would for a normal ActiveRecord class. This means that you can have multiple models of the same class connecting to two different databases at the same time.

Why I Built This

I built this because I wanted 1 codebase for the entire project and didn't want to have multiple classes with a slightly altered CDbConnectionString in order to access them. This was easier than that. I didn't want to instantiate a new copy of the application every time I wanted to make another db copy.


FAIR WARNING

You need to follow all of these instructions exactly in order to get CDynamicRecord to work. The instructions look very complex, but they really aren't. You can do it. =)


For example, suppose you had two databases with the same structure, db1 and db2. Each database has a table called foo which has distinct, nonrelated data, so you're structure looks something like this:

- db1
   \ - foo
- db2
   \ - foo

Since both tables are identical and only have different data, accessing them requires EITHER two distinct ActiveRecord classes, each one configured for the appropriate database. Alternatively you could use this class which would allow you to access BOTH databases independently of one another without having to create a new class Foo model for each database. That is what CDynamicRecord is for.

Installation

  • Clone CDynamicRecord.php to your Application/Protected/Components folder.
  • Create a structure only copy of your database with the appropriate permissions and access. For example, I've named the strucutre only copy of my database db_base/
- db_base
- db1
   \ - foo
- db2
   \ - foo
  • Create a default db configuration which has access to db_base.
  • Modify CDynamicRecord::overrideDbConnection() and replace the following line:
# MODIFY YOUR CDBCONNECTIONSTRING HERE

With

Yii::app()->db->connectionString = // CONNECTION STRING INFORMATION

The variable

CDynamicModel::$dbConnectionString

Is publicly accessible inside the model, and will contain any information you want to pass into the model for connection information at call time. You should use it to define how you want to connect to your database.

It is YOUR responsibility to define HOW you want to connect to the database.

  • Create a new class Foo and have it extend CDynamicRecord, and modify model() so that it looks as follows.
    public static function model($dbConnection, $className=__CLASS__)
    {
        return parent::model($dbConnection, $className);
    }

Usage

After setting everything up, CDynamicRecord behaves exactly like CActiveRecord with the expection that you must specify the connection details at call time. Calls then look like this:

Foo::model($connection)->findAll();
$foo = new Foo($connection2);
$foo->relation->findAll();

$connection can be whatever you want, it just needs to be defined. It could be an array containing the data, or a flat out string.

Relations

Relations will still work the same, but depending upon their usage you may need to change a few things.

IF you plan on accessing a related model (Bar), and you have no intention on calling Bar by itself. Then Bar should extend CActiveRecord, and in Foo you can define normal relations. Yii magically carries over the CDbConnectionString across the instances for you.

OTHERWISE, if you intend to access models in the same database, but also want to retain the ability to call them by themselves, then Bar should extend CDynamicModel, and Foo should have a getter defined as follows.

// This is an example for access Bar from Foo

public function getBar()
{
    return Bar::model($this->$dbConnectionString);
}

Examples

This is an example using a model Foo which connects to a table db*/foo

Database
db_base // Structure copy only
    \ - foo
db_1    // Contains data
    \ - foo
db_2    // Data of same structure of db_1/foo, but is different.
    \ - foo
Foo Model
<?php // Application/Protected/Models/Foo.php
class Foo extends CDynamicRecord
{
    public static function model($dbConnection, $className=__CLASS__)
    {
        return parent::model($dbConnection, $className);
    }
}
CDynamicRecord::overrideDbConnection()

Just update overrideDbConnection()

<?php
class CDynamicRecord extends CActiveRecord
{
    [...]
     /**
     * This method allows us to customize how we want our connection string to be manipulated
     * It takes the value of CiiModelDynamic::$dbConnectionString for manipulation
     * @return true
     */
    private function overrideDbConnection()
    {
        Yii::app()->db->setActive(false);
        Yii::app()->db->connectionString = str_replace('base', $this->dbConnectionString, Yii::app()->db->connectionString);
        Yii::app()->db->setActive(true);

        return true;
    }
    [...]
}

With this configuration, db_base, db_1, and db_2 use the same credentials. The same user can access each of them as defined in my default db connection string in my Application/Protected/Config/main.php file.

So now, I can do this:

$foo = Foo(1);
$foo2 = Foo(2);
$foo3 = Foo::model(1);

Be the first person to leave a comment

Please to leave your comment.

Create extension
Downloads
No downloadable files yet