4

So, I am having quiet a big SAAS web application build on top of Symfony 3. What started off with about 10 - 20 applications, has now grown to over 500+ applications. The vendor directory alone already per application is 150+ MB in size.

All those applications have their own database. I would like to keep it this way. However, I believe it would be nice if some code is being shared. Take the vendor and src directory for example. It's the same across every application, but yet all of them are "loaded" individually in OpCache. I believe that in sense of resources, it would be best if these directories would be shared.

Both Composer and Symfony don't really seem to support multi-instance applications with shared directories that much. I was wondering however if someone had any clues to achieve what I had in mind or that my plan is just not feasible?

The configuration is different per application (parameters.yml) and the web directory contains different stylesheets per application. So they need to be separated from the rest.

I've been thinking of using the environment setting for this, but it doesn't feel right that we have environment "test", "dev", "application1", "application2", etc. config_prod.yml suddenly also becomes unusable then.

Is my way of thinking wrong? Any suggestions on how to achieve this? Or should I just go with a complete separate instances?

(Our application is using SemVer and it would even be nice if we have shared code for version 1.0.0., version 1.1.0 etc. So that's even a next layer on top. But perhaps that is the next step.)

edit: To clarify a bit more; In essence you could say that the web directory and var directory are both none-sharable. The web directory contains custom stylesheets and is the main entry point. The var directory contains cache files, which are different per application depending on their database settings. Finally you also have the custom parameter file, which is different per application to store the database credentials.

I tried symlinking, but composer is not really happy with that. Also, when using symlinks, the working directory is always the real used directory, not the actual directory you are symlinked from. I also tried with custom settings in the vhost file of the application. Overriding the cache and kernel directories are possible, but again you loose the actual directory you are symlinking from.

3
  • Just an idea: Opcache uses real-path, you could replace files if same with a symlink to the "parent". Scripted after composer install and you can relief from that perhaps... Commented Jun 20, 2017 at 14:27
  • Yeah I tried that. However composer doesn't support that the vendor directory is symlinked by multiple applications. It saves the path somewhere in one of the autoloaders. Commented Jun 20, 2017 at 19:16
  • I don't mean the vendor folder but the code in there of the packages. And not the packages but under that level all files that are the same. Linke compare two directory trees recursively and if the file is the same, replace it with a symlink. opcache then will use the realpath. That must be done in a script so that you can reset by eradicating the vendor-folder, re-install with composer and then re-run the compare & link script. Commented Jun 20, 2017 at 19:20

1 Answer 1

1

You'll need to create custom configuration directories and/or files and then adjust your AppKernel to point to the correct one based on whatever criteria you're using. For example, if you were going off of a subdomain: First, update your frontend controller to have a new super global. There is probably a better way to do this, and I'd recommend looking into that..

// web/app.php
use Symfony\Component\HttpFoundation\Request;

/** @var \Composer\Autoload\ClassLoader $loader */
$loader = require __DIR__.'/../app/autoload.php';
include_once __DIR__.'/../var/bootstrap.php.cache';

list($scheme, $host) = explode('.',$_SERVER['SERVER_NAME']);
define(APP_CONFIG_FILENAME, sprintf('%s.yml', $host));

$kernel = new AppKernel('prod', false);
$kernel->loadClassCache();
//$kernel = new AppCache($kernel);

// When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter
//Request::enableHttpMethodParameterOverride();
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

Now in your AppKernel, use this new superglobal

// app/AppKernel.php
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;

class AppKernel extends Kernel
{
    public function registerContainerConfiguration(LoaderInterface $loader)
    {
        $loader->load($this->getProjectDir().'/app/config/' . APP_CONFIG_FILENAME . '.yml');
    }
}

And then in your example1.yml

# app/config/mysubdomain.yml
imports:
    - { resource: 'parameters_example1.yml' }
    - { resource: 'routing_example1.yml' }
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for your response, but I don't think this completely resolves the problem. As noticed, there is a separate database per application. This means that also the cache cannot be shared between applications. I'll update my main post.
So you'd simply change your cache config settings as well in your config_{x}.yml and what the database parameters are in parameters_{x}.yml - and for caching you'd have to setup a non file-system store, or a custom cache handler for something like redis, or if you wanted; database driven cache with pdo like this: symfony.com/doc/master/components/cache/adapters/… or a separate pdo session handler: symfony.com/doc/current/doctrine/pdo_session_storage.html
Apart from the fact if you are right or not (I believe you make it sound easier then it actually is, because I cannot store anything in a yml file due to caching), it still doesn't solve the issue of having the vendor and src directory (And probably more) in a shared directory.
I apologize if I make it sound too easy, but I've actually done this, so I know it works. the vendor and src being shared is the entire point of a multi-site setup like this.
Hi Jake. Alright. Cool to hear :) I'll try it out myself too. Just how did you share the vendor / src directory then? Because when you use a symlink, the actual working directory changes to the directory of where the files are actually located.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.