The MVC paradigm, adopted in symfony from top to bottom, brings highly decoupled components meant to be used independently.
In a symfony application, modules are flexible and allow complex manipulations like :
- forwarding to another module/action and delegate request processing
- rendering a module/action in isolation (like an email generation module)
Unfortunately, this agility is only available inside a project context. You cannot use a module from another project.
Here is a trick to ‘load’ components (modules, libs, validators or whatever) from an external project.
Project configurations and contexts
The Application configuration object is defined early in the process chain. sfContext loads it and creates a sfContext instance for the current application.
Since symfony 1.1, sfContext is not a singleton anymore. It is now possible to have several context instances.
You can create a configuration object for the external project/application, add a sfContext instance to the stack, and switch between them using the sfContext::switchTo() method.
sfContext::createInstance($configuration) sfContext::switchTo('another_app');
ExternalProjectFilter
Let’s create a filter that will handle all this job early in the process chain.
In /apps/yourapp/config/filters.yml:
rendering: ~
security: ~
external:
class: ExternalProjectFilter
param:
sf_root_dir: /var/www/external_project_dir
sf_app: external_app_name
sf_env: dev
sf_debug: true
cache: ~
common: ~
execution: ~
Now let’s write the ExternalProjectFilter class in /lib/ExternalProjectFilter.class.php
class ExternalProjectFilter extends sfFilter { public function execute($filterChain) { if ($this->isFirstCall()) { $current_app = sfConfig::get('sf_app'); $configuration = ProjectConfiguration::getApplicationConfiguration( $this->getParameter('sf_app'), $this->getParameter('sf_env'), $this->getParameter('sf_debug'), $this->getParameter('sf_root_dir') ); // Add an instance of the external project on the current context sfContext::createInstance($configuration); // Add the external project's database connection settings Propel::setConfiguration(sfPropelDatabase::getConfiguration()); Propel::initialize(); // Autoload external project files $autoload = sfSimpleAutoload::getInstance(); $autoload->addDirectory( $this->getParameter('sf_root_dir').'/lib'); $autoload->register(); // Switch back to the current context sfContext::switchTo($current_app); } $filterChain->execute(); } }
Example
In /apps/yourapp/modules/article/template/indexSuccess.php
... sfContext::switchTo('external_app_name'); echo sfContext::getInstance()->getController()->getPresentationFor('customer', 'index'); sfContext::switchTo('your_app_name'); ...
Limitations
Projects cannot share the same default database connection name ‘propel’. The trick is to explicitly name the database in your schema/databases.yml :
schema.xml
<?xml version="1.0" encoding="UTF-8"?> <database name="project" package="lib.model" defaultIdMethod="native" noXsd="true"> <table name="article">
databases.yml
all: project: class: sfPropelDatabase param: dsn: mysql://user:pass@host/db encoding: utf8
-
1
Pingback on Oct 12th, 2008 at 11:38 pm
[...] Using a module from another project [...]

October 15, 2008 at 9:33 am
why not sharing this module in a plugin?
October 15, 2008 at 9:44 am
There is still some coupling between two projects. When I began to work on the multiple sfContext instances solution, I thought each instances would be clearly independant and would embed all what a project need to run, but it is not the case.
As you can see, I have to manually add autoloading, propel connections, and perhaps I’m missing stuff like logging, internationalization or whatever.
I think by now, this solution is too much tricky to stand as a real compatible plugin.
November 1, 2008 at 11:23 am
Thanks Nicolas
This was very helpful to me.
In my case I had two applications in one project and I wanted to use in project 2 some module action of project 1.
My apps are set to use different session cookie names and that was a problem because sfSessionStorage was initialized twice – one time for each app. After that session_regenerate_id() brokes my session of project 2.
To make things wokring again I added ‘no_session’ environment to project 1 and I disabled session by setting storage factory to a class which implements sfSessionStorage methods as empty methods.
Then I used ‘no_session” environment when creating Context for project 1 in project 2.
Best regards