Using Multiple Databases in Symfony with Propel
By marc • Apr 22nd, 2008 • Category: Featured, Symfony
There comes a time in your symfony development career when you will need to connect to multiple databases from within one application. At first it may not be obvious how to configure symfony correctly to handle a couple different databases or database servers. Let me show you just how simple it is with Propel!
Keep in mind that the examples below are just a simplified overview to show the basic concepts. There are numerous ways that this can be expanded upon to work with specific server configurations.
Configuration
The first thing that we need to do is properly configure the database configuration files (schema.yml & databases.yml). So here is an example of how these two files can be configured for a basic application:
schema.yml
-
-
articles:
-
_attributes: { phpName: Article }
-
idMethod: native
-
id:
-
type: INTEGER
-
title:
-
type: VARCHAR
-
created_at:
-
type: TIMESTAMP
-
updated_at:
-
type: TIMESTAMP
-
-
categories:
-
_attributes: { phpName: Category }
-
idMethod: native
-
id:
-
type: INTEGER
-
category:
-
type: VARCHAR
-
parent_id:
-
type: VARCHAR
-
created_at:
-
type: TIMESTAMP
-
updated_at:
-
type: TIMESTAMP
-
-
# etc…..
As you can see, this schema.yml file looks exactly the same as one for a single database application. In most of my applications I usually have many of the same tables in various databases, so in this case I can just put all the schema definitions in one schema file and use the “propel” connection name.
databases.yml
-
all:
-
propel:
-
class: sfPropelDatabase
-
param:
-
dsn: mysql://USERNAME:PASSWORD@DB_HOST_1/DB_NAME
-
-
slave:
-
class: sfPropelDatabase
-
param:
-
dsn: mysql://USERNAME:PASSWORD@DB_HOST_2/DB_NAME
The main thing to consider is that you probably always want a connection named “propel”. This is necessary for certain things to work correctly such as “symfony propel-build-model”, etc especially since the schema.yml uses that connection name.
Switching Connections
Now when you want to use your different connections, you just have to let Propel know which connection you want to use. By default, Propel uses the “propel” connection if no other connection is explicitly set on a query. Here is how you would go about using your two connections defined in the databases.yml file described above:
-
// get all articles from the slave database
-
$c = new Criteria();
-
$articles = ArticlePeer::doSelect($c, Propel::getConnection('slave'));
-
-
// save an article in the master database (explicitly setting the connection name)
-
$article = new Article();
-
$article->setTitle('Symfony Rocks!!!');
-
-
$article->save(Propel::getConnection('propel');
This is just a very basic demonstration of the concepts used to switch the database connections. There are many ways that this would be expanded to handle various environments. For example, if you had a classic set up of a master database with N number of slaves, it would probably be best to create a behaviour or something to override the update/insert/delete methods of the models so that they are only performed on the master database and the selects would be performed only on the slaves. Users with this type of set up may want to take a look at sfPropelLoadbalancerPlugin which seems to accomplish this goal.
This is at least easier for me.
Create an application for every database connection, then merge all of their models into your application. After that delete all the temporary applications. And that’s it. Just make sure their connection name in database.yml are unique from each other.
I found your site on faves.com bookmarking site.. I like it ..gave it a fave for you..ill be checking back later
Thanks for the posting, I have a comment though. I notice with your statement here and others I’ve found about the need to name a connection ‘propel:’ for things to work such as propel-build-model. This doesn’t seem right and the application I’m building does not have this designation and everything is fine. My schema.yml, databases.yml and propel.ini are basically in synch with the name I used and it is not ‘propel’.
From what I can see, propel.ini is what drives the connection for things such as ‘propel-build-model’ and ‘propel-insert-sql’ giving you the need to have one connection defined in that file for the action you are taking. The only thing that I can see that is confusing this issue is in propel.ini we have to set things such as ‘propel.project’ and ‘propel.database’ but I do not believe that directly means a connection in databases.yml or schema.yml called ‘propel’ it’s just that it’s settings for propel to use.
Example:
## from Schema.yml
data_connection_master:
status:
_attributes: { phpName: my_status, package: lib.model.my_administrator }
code: { type: integer, required: true, primaryKey: true }
type: { type: varchar, size: 50, required: true, primaryKey: true }
created: { type: timestamp }
modified: { type: timestamp }
…….
##from databases.yml
all:
data_connection_master:
class: sfPropelDatabase
param:
phptype: mysql # Database vendor
hostspec: localhost
database: data_connection_master
username: symfonyuser
password: symfonyuser
port: 3306
encoding: utf8 # Default charset for table creation
persistent: true # Use persistent connections
…….
#from propel.ini
propel.database = mysql
propel.database.createUrl = mysql://symfonyuser:symfonyuser@localhost:3306/
propel.database.url = mysql://symfonyuser:symfonyuser@localhost:3306/data_connection_master
Since things work fine for me without having a connection called ‘propel’ I’m pretty sure I’m right. I’d appreciate hearing the perspective and experience of someone else on this.
Thanks for this nice article. I needed this information because I’m developing a new version of a community project. Of course I need al existing data transferred to the new tables, for which this solution is made!