I would like to be able to manually set kernel.root instead of having it magically determined for me.
*If there an easy way to do this without extending Kernel that I have overlooked, please let me know. I sometimes overlook obvious/simple solutions.* The use case would be a standalone application that wants to load/interact with arbitrary kernels at various locations and/or kernels that are not actually located in `app/`. A specific example is my kernel based CLI applications. I provide a default Kernel implementation in the event that the user does not specify their own (if `app/CustomKernel.php` does not exist, it just instantiates the default CustomKernel). This default CustomKernel lives deep in my application's package and lives under *vendor/* (or potentially even inside a phar) so it is not a suitable candidate from which kernel.root should be generated. Currently the root is set in the constructor by calling getRootDir(). getRootDir() looks at the location of the kernel (by reflection) to find the directory in which the class exists. The only way I've been able to change this is by extending Kernel and setting rootDir int he constructor before calling parent::__construct(). My current solution is close to the following: class CustomKernel extends Kernel { public function __construct($environment, $debug, $rootDir = null) { if (null !== $rootDir) { $this->rootDir = $rootDir; } parent::__construct($environment, $debug); } } A scan of HttpKernel shows me that name depends on rootDir and there are lots of access directly to $this->name and $this->rootDir so I'm not sure it would be safe to set rootDir in any other way than by making it a constructor argument without making some heavy changes to Kernel. Also, FWIW, I'm not oblivious to the @api tag in the Kernel constructor. =) Nevertheless, I'd like to discuss a solution involving adding an optional constructor argument. My naive implementation would be the following: abstract class Kernel implements KernelInterface, TerminableInterface { /** * Constructor. * * @param string $environment The environment * @param Boolean $debug Whether to enable debugging or not * @param string $rootDir Kernel root directory * * @api */ public function __construct($environment, $debug, $rootDir = null) { $this->environment = $environment; $this->debug = (Boolean) $debug; $this->booted = false; $this->rootDir = $rootDir ?: $this->getRootDir(); $this->name = $this->getName(); $this->classes = array(); if ($this->debug) { $this->startTime = microtime(true); } $this->init(); } } The other method I've considered is making name/rootDir could be made private, not have them be set in the constructor, and add setRootDir to Kernel that would allow someone to set the rootDir if it hasn't already been accessed. All calls to $this->name and $this->rootDir would need to be made to $this->getName() and $this->getRootDir(). My native implementation would be the following: private $rootDirIsFrozen = false; public function getRootDir() { if ($this->rootDirIsFrozen) { return $this->rootDir; } if (null === $this->rootDir) { $r = new \ReflectionObject($this); $this->rootDir = str_replace('\\', '/', dirname($r->getFileName())); } $this->rootDirIsFrozen = true; return $this->rootDir; } public function setRootDir($rootDir) { if ($this->rootDirIsFrozen) { throw \LogicException("Trying to set root directory after it has already been accessed is not allowed"); } $this->rootDir = $rootDir; } Something similar could be done for name as well since name relies on rootDir. I am not sure whether or not name needs to be able to be set, but if so it could be handled in the same way. This second solution would be more intrusive to the system but could probably be done w/o breaking @api on the constructor. I haven't experimented with this, so I'm not sure if there are places where name or rootDir are accessed in the constructor/init that are not obvious. It *looks * safe enough, though. I've found most parts of Kernel pretty easy to move around; the only really difficult thing to deal was being able to override the root directory. There *are* workarounds but I'd love to see if I can get some of this functionality in core if at all possible so I can simplify my code and share this functionality with other people who might want to deal with kernels in locations other than where Symfony Standard expects to find them. So my questions: - Is there an easy way to do this that I've overlooked that does not involve extending Kernel? - Have I shown a strong enough need for being able to set kernel.root manually instead of relying on magic that this can be introduced to core? - If so, which method should I pursue? Introduce an optional constructor argument or the getter/setter solution? - Does adding an optional arguments constitute breaking @api? -- If you want to report a vulnerability issue on symfony, please send it to security at symfony-project.com You received this message because you are subscribed to the Google Groups "symfony developers" group. To post to this group, send email to symfony-devs@googlegroups.com To unsubscribe from this group, send email to symfony-devs+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/symfony-devs?hl=en