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

Reply via email to