My requirements:
- Moving application specific configurations into separate application bundles (not separate
app/
folders) - Retaining common configurations in the
app/config/config_*.yml
files - Retaining common practices such as calling
app/console
just adding a parameter to specify the application
Steps
- Change your apache2 vhost to add a (conditional?) environment variable
# ... # The RegEx below matches subdomains SetEnvIf Host nth\..+? SYMFONY_APP=nth # ...
- Create
app/NthKernel.php
which extendsAppKernel
- Overwrite
NthKernel::$name = 'nth'
- Overwrite
NthKernel::serialize
,NthKernel::unserialize
to ensure the correct name is kept after serialization/deserialization -
Overwrite
NthKernel::getCacheDir
to ensure the cache dirs are split based on the application name:public function getCacheDir() { return $this->rootDir.'/cache/'.$this->name.'/'.$this->environment; }
- Overwrite the
NthKernel::registerContainerConfiguration
to load configurations based on the application name and environment. In my case I loaded allconfig.yml
files from any installed bundle:public function registerContainerConfiguration(LoaderInterface $loader) { $env = $this->getEnvironment(); foreach ($this->bundles as $bundle) { $dir = $bundle->getPath() . '/Resources/config/'; if (file_exists($path = $dir . 'config_'.$env.'.yml')) { $loader->load($path); } elseif (file_exists($path = $dir . 'config.yml')) { $loader->load($path); } } $dir = __DIR__.'/config/'; if (file_exists($path = $dir . 'config_'.$env.'.yml')) { $loader->load($path); } elseif (file_exists($path = $dir . 'config.yml')) { $loader->load($path); } }
- Change
web/app.php
/web/app_dev.php
to ensure they instantiateNthKernel
andNthCache
based on the environment variable apache is providing (SYMFONY_APP
):$app = ucfirst(getenv('SYMFONY_APP')); require_once __DIR__.'/../app/AppKernel.php'; require_once __DIR__.'/../app/'.$app.'Kernel.php'; //require_once __DIR__.'/../app/AppCache.php'; //require_once __DIR__.'/../app/'.$app.'Cache.php'; $kernel = $app.'Kernel'; $kernel = new $kernel('dev', true); $kernel->loadClassCache(); //$cache = $app.'Cache'; //$kernel = new $cache($kernel);
- Change
app/console
to allow you to specify which application you need to use$app = ucfirst($input->getParameterOption(array('--app', '-a'), getenv('SYMFONY_APP'))); $env = $input->getParameterOption(array('--env', '-e'), getenv('SYMFONY_ENV') ?: 'dev'); // ... /* Move require_once after you initialized the `$app` variable */ require_once __DIR__.'/AppKernel.php'; require_once __DIR__.'/'.$app.'Kernel.php'; $kernel = $app.'Kernel'; $kernel = new $kernel($env, $debug); $application = new Application($kernel); $application ->getDefinition() ->addOption( new InputOption( '--app', '-a', InputOption::VALUE_REQUIRED, 'The Application name.', $kernel->getName() ) );
- Use
app/console
by specifying the application you need to useapp/console --app=nth --env=dev debug:router app/console --app=nth --env=dev debug:container
Other resources:
JoliCode wrote this article on the topic.
Their approach on the problem seems more idiomatic — creating a structure application specific subfolders (apps/nth
) each with its own AppKernel
, apps/nth/cache
and apps/nth/config
etc..
Hello,
I followed joliCode multiapp example and was looking your post because I’m interested only for console part. I mean I would like only use a common console for all app and specify –app option when typing commands.
To do that, in addition to have my two app folders (app1/ and app2/) shown in the joliCode example, I renamed back global directory apps -> app and put back inside AppCache ..AppKernel .. console .. etc…
At this point I can use my global app/console file.
I tried to modify only part 8 & 9 of your blog post regarding console file changes but it don’t like any global console command now :
Fatal error: Call to a member function getParameterOption() on a non-object in D:\clients\courtier-web\remere\www\app\console on line 8
Call Stack:
0.0004 130512 1. {main}() D:\clients\courtier-web\remere\www\app\console:0
Line 8 is about :
$app = ucfirst($input->getParameterOption(array(‘–app’, ‘-a’), getenv(‘SYMFONY_APP’)));
Any advices to accomplish this ?
Thanks anyway !
LikeLike
The
$input
variable seems to be null, why? In the same file around liner number 8 you should have an initialization of the$input
variable like$input = new ArgvInput();
and another line trying to retrieve the environment$env = $input->getParameterOption(array('--env', '-e'), getenv('SYMFONY_ENV') ?: 'dev');
.If that’s not present inside your console file then please cut/paste the entire console file so we can debug a bit. What version of Symfony are you running?
LikeLike
Hello and thanks for answer,
my bad, I placed this two lines in the wrong place.
I’m using symfony 2.7.7 (latest).
Here is the console file (which runs correctly now) :
The only addtional change I made currently is inside vhosts :
ServerName cw-multiapp-app1
DocumentRoot d:/clients/www/web/app1
CustomLog d:/clients/logs/access.log combined
ErrorLog d:/clients/logs/error.log
Same on the second vhost pointing to app2.
It looks like console commands with –app option does not have the correct behavior at this point.
Thanks again for further help.
LikeLike
You either use
app/console --app=app1 ...
or theapp/console -a=app1
, usingapp/console -app=app1
won’t work.Your apache (vhost) configuration has no effect on the console command. It’s not relevant except for when you’re accessing your applications through the browser based on the specified subdomain.
LikeLike
Thanks again,
The command still have no effect.
Using : php app/console generate:bundle –app=app1 for example.
The bundle is declared on default AppKernel (app/AppKernel.php, not in app/app1/AppKernel.php)
LikeLike
I’ve reread the
app/console
file you pasted more carefully.You need replace the line which includes the default AppKernel (
require_once 'app/app1/AppKernel.php'
) with a line which includes your AppKernel (require_once 'app/AppKernel.php'
).LikeLike
It looks like console have already the good path
…
require_once DIR.’/bootstrap.php.cache’;
require_once DIR.’/AppKernel.php’;
…
LikeLike
__DIR__ === 'app/'
because__FILE__ === 'app/console'
so it doesn’t have the correct path… it’s not includingapp/app1/AppKernel.php
, it’s including the default kernel.LikeLike
Sorry for misunderstanding here Mihai, but I still do not understand 2 things.
You told me just above I have to replace :
‘app/app1/AppKernel.php’ to
‘app/AppKernel.php’ in my app/console file.
There’s no reference anywhere to “app/app1/…” currently, it contains already “DIR.’/AppKernel.php'”
Also, there’s no ‘app/app1/AppKernel.php’ in my project but ‘app/app1/App1Kernel.php’ or ‘app/app2/App2Kernel.php’.
Anyway, none of this kernel’s are called by my console php file.
The second thing I do not understand is that you seem in your last message telling me to include that other kernel’s.
Which is done here :
require_once DIR.’/bootstrap.php.cache’;
require_once DIR.’/AppKernel.php’;
require_once DIR.’/app1/App1Kernel.php’;
require_once DIR.’/app2/App2Kernel.php’;
But it didn’t change anything when generating a bundle using –app=app1 option. Symfony still declare bundle in main AppKernel, not the app1/App1Kernel one.
Thanks again.
LikeLike
Well the whole point of having separate
AppKernel
is to have separate bundles loaded and separate configurations loaded so I assumed that you need to load a particular AppKernel based on the--app=appX
flag.If you’re going to load all bundles into the default AppKernel then you don’t need to change absolutely anything in the console file.
LikeLike
Finally got it !
I added a conditional test in my console file :
And additionally, I correct RootDir for console having the right path, depends of the app currently selected. It was needed to override getRootDir kernel method in each app :
Thanks again for help Mihai.
LikeLike
That’s true, my goal is to load different bundles depending of the kernel loaded :D
LikeLike
Hi Mihai,
This is wonderful blog post.
I started to make api centric multiple application symfony app inspired on joilcode, I separated api and frontend properly. bin/console approach is almost same with yours.
Just One problem I have let me explain it.
php bin/console –app=api works perfectly!
but I also want to make api|frontend machine with the same machine, that because I cannot specify default value to –app parameter but it breaks the composer. Is there any way to use composer as
composer install –app=api ? I couldn’t find how to pass app argument to bin/console. Do you have any idea ?
LikeLike
You can either export the environment variable before running composer up (such as
export SYMFONY_APP=api
) or you can setup a default value in the console file.LikeLike
Then I may put a bash script which wrap the composer, and SYMFONY_APP=api before composer execution may good solution. Thanks.
LikeLike
Hello! Thats sounds better than damienalexandre’s approach for me. But now I don’t understand how to specify different security.yml files for different applications? The goal is to compleatly separate Sonata admin bundles from other application parts, application users and admin users are different entites and never cross with each other, so I want to separate security settings for admin section off of the main application settings. Forthermore in future there will be another admin system for other aspect of application so it needs its own security settings (i.e. admin users, roles, voters).
If I will be able to separate security settings than this approach will be perfect for me.
LikeLike
A default
config.yml
file explicitly includessecurity.yml
.If you want separate
security.yml
files per install then just move the security include fromconfig.yml
to an yml file included by your app.LikeLike
0 Pingbacks