PHP: composer does not belong in production!

Edit: read carefully until the end, the PR has been reverted and changed, the logic regarding composer.json not belonging to production does not change though!

Most PHP project now use composer to manage their dependencies, and sometimes even more than that. Actually, when it’s missing on legacy projects, that’s the first thing I am adding!
While this is such a great tool, I’m often leaving both the composer.json and composer.lock files in production, just because I don’t bother removing them in my deployment pipeline… so do most of my fellow developers/ops.
Because we developers and IT professionals are always forced to improve our processes, I did a proper deployment of a Symfony 4 project on Microsoft Azure using a Gitlab Pipeline, where I build a docker image that does not contain composer files.


Once deployed, I got a file not found error, while searching for src/config/bundles.php in src/Kernel.php : $contents = require $this->getProjectDir().'/config/bundles.php 
Here, $this->getProjectDir is supposed to give the absolute path of the project directory, but sends back null on my production (hence the src/ above).
The method getProjectDir is defined in Symfony\Component\HttpKernel\Kernel , and is defined as follow :

/**
* Gets the application root dir (path of the project's composer file).
*
*
@return string The project root dir
*/
public function getProjectDir()
{
if (null === $this->projectDir) {
$r = new \ReflectionObject($this);
$dir = $rootDir = \dirname($r->getFileName());
while (!file_exists($dir.'/composer.json')) {
if ($dir === \dirname($dir)) {
return $this->projectDir = $rootDir;
}
$dir = \dirname($dir);
}
$this->projectDir = $dir;
}

return $this->projectDir;
}

So how to deal with that if you do not have a composer.json file?

According to a 2 years old issue [kernel.project_dir (getProjectDir()) silently returns incorrect path without composer.json], the official answer is: override the method in your own kernel:

public function getProjectDir()
{
return dirname(__DIR__);
}

Obviously this works well, but:

  • it requires for the developer to get the error, analyse it, and then fix it
  • it introduces an extra step, which is bad DX (developer experience) as kids say nowadays
  • it couples the framework to another tool (you could use Symfony without composer at all, if you were crazy 😁)

To fix this problem, I did two small PRs on the framework (probably some of the smallest it ever had).

$kernel = new Kernel(
$_SERVER['APP_ENV'],
(bool) $_SERVER['APP_DEBUG'],
dirname(__DIR__)
);

Now you will be able to remove your composer.json and composer.lock files from your Symfony’s production with not path problems!


The PR has now been reverted, as considered by no good for developer experience by some of the contributors (requiring more than two changes — bin/console and public/index.php but not only, any test kernel in any third party package as well).

My take on this is that the responsibility of providing the path (which is a dependency of the class Kernel) belongs to the caller from an Object Oriented Programming point of view. Here the class rely on its environment, which is in my opinion something that should be done in entrypoints or bootstrap, before arriving in an OOP code.

The PR I proposed was not fixing the whole problem though, because it was considering that existing calls should not change for now, hence the parameter being optional.

I opened another PR which is way less satisfying from an engineering point of view: https://github.com/symfony/recipes/pull/564


How about you? Are you removing these files or leaving them most of the time, and if leaving, why?