diff --git a/UPGRADE-3.4.md b/UPGRADE-3.4.md index 7164e789a808..0c481286db2a 100644 --- a/UPGRADE-3.4.md +++ b/UPGRADE-3.4.md @@ -143,6 +143,9 @@ HttpKernel tags: ['console.command'] ``` + * The `getCacheDir()` method of your kernel should not be called while building the container. + Use the `%kernel.cache_dir%` parameter instead. Not doing so may break the `cache:clear` command. + Process ------- diff --git a/UPGRADE-4.0.md b/UPGRADE-4.0.md index 218958d1f968..842dca7b68ca 100644 --- a/UPGRADE-4.0.md +++ b/UPGRADE-4.0.md @@ -510,6 +510,9 @@ HttpKernel by Symfony. Use the `%env()%` syntax to get the value of any environment variable from configuration files instead. + * The `getCacheDir()` method of your kernel should not be called while building the container. + Use the `%kernel.cache_dir%` parameter instead. Not doing so may break the `cache:clear` command. + Ldap ---- diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php index 3bec217e30af..3429d99ed1f8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php @@ -19,6 +19,7 @@ use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface; use Symfony\Component\HttpKernel\KernelInterface; +use Symfony\Component\HttpKernel\RebootableInterface; use Symfony\Component\Finder\Finder; /** @@ -33,6 +34,7 @@ class CacheClearCommand extends ContainerAwareCommand { private $cacheClearer; private $filesystem; + private $warning; /** * @param CacheClearerInterface $cacheClearer @@ -112,6 +114,12 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->filesystem->rename($realCacheDir, $oldCacheDir); } else { $this->warmupCache($input, $output, $realCacheDir, $oldCacheDir); + + if ($this->warning) { + @trigger_error($this->warning, E_USER_DEPRECATED); + $io->warning($this->warning); + $this->warning = null; + } } if ($output->isVerbose()) { @@ -167,17 +175,23 @@ protected function warmup($warmupDir, $realCacheDir, $enableOptionalWarmers = tr { // create a temporary kernel $realKernel = $this->getApplication()->getKernel(); - $realKernelClass = get_class($realKernel); - $namespace = ''; - if (false !== $pos = strrpos($realKernelClass, '\\')) { - $namespace = substr($realKernelClass, 0, $pos); - $realKernelClass = substr($realKernelClass, $pos + 1); - } - $tempKernel = $this->getTempKernel($realKernel, $namespace, $realKernelClass, $warmupDir); - $tempKernel->boot(); + if ($realKernel instanceof RebootableInterface) { + $realKernel->reboot($warmupDir); + $tempKernel = $realKernel; + } else { + $this->warning = 'Calling "cache:clear" with a kernel that does not implement "Symfony\Component\HttpKernel\RebootableInterface" is deprecated since version 3.4 and will be unsupported in 4.0.'; + $realKernelClass = get_class($realKernel); + $namespace = ''; + if (false !== $pos = strrpos($realKernelClass, '\\')) { + $namespace = substr($realKernelClass, 0, $pos); + $realKernelClass = substr($realKernelClass, $pos + 1); + } + $tempKernel = $this->getTempKernel($realKernel, $namespace, $realKernelClass, $warmupDir); + $tempKernel->boot(); - $tempKernelReflection = new \ReflectionObject($tempKernel); - $tempKernelFile = $tempKernelReflection->getFileName(); + $tempKernelReflection = new \ReflectionObject($tempKernel); + $tempKernelFile = $tempKernelReflection->getFileName(); + } // warmup temporary dir $warmer = $tempKernel->getContainer()->get('cache_warmer'); @@ -186,6 +200,20 @@ protected function warmup($warmupDir, $realCacheDir, $enableOptionalWarmers = tr } $warmer->warmUp($warmupDir); + // fix references to cached files with the real cache directory name + $search = array($warmupDir, str_replace('\\', '\\\\', $warmupDir)); + $replace = str_replace('\\', '/', $realCacheDir); + foreach (Finder::create()->files()->in($warmupDir) as $file) { + $content = str_replace($search, $replace, file_get_contents($file), $count); + if ($count) { + file_put_contents($file, $content); + } + } + + if ($realKernel instanceof RebootableInterface) { + return; + } + // fix references to the Kernel in .meta files $safeTempKernel = str_replace('\\', '\\\\', get_class($tempKernel)); $realKernelFQN = get_class($realKernel); @@ -198,16 +226,6 @@ protected function warmup($warmupDir, $realCacheDir, $enableOptionalWarmers = tr )); } - // fix references to cached files with the real cache directory name - $search = array($warmupDir, str_replace('\\', '\\\\', $warmupDir)); - $replace = str_replace('\\', '/', $realCacheDir); - foreach (Finder::create()->files()->in($warmupDir) as $file) { - $content = str_replace($search, $replace, file_get_contents($file), $count); - if ($count) { - file_put_contents($file, $content); - } - } - // fix references to container's class $tempContainerClass = $tempKernel->getContainerClass(); $realContainerClass = $tempKernel->getRealContainerClass(); diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index ca26a6c5bdde..be467b407b00 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 3.4.0 ----- + * added `RebootableInterface` and implemented it in `Kernel` * deprecated commands auto registration * added `AddCacheClearerPass` * added `AddCacheWarmerPass` diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 8c70005d2857..df795fcd33db 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -43,7 +43,7 @@ * * @author Fabien Potencier */ -abstract class Kernel implements KernelInterface, TerminableInterface +abstract class Kernel implements KernelInterface, RebootableInterface, TerminableInterface { /** * @var BundleInterface[] @@ -61,6 +61,7 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $loadClassCache; private $projectDir; + private $warmupDir; const VERSION = '3.4.0-DEV'; const VERSION_ID = 30400; @@ -127,6 +128,16 @@ public function boot() $this->booted = true; } + /** + * {@inheritdoc} + */ + public function reboot($warmupDir) + { + $this->shutdown(); + $this->warmupDir = $warmupDir; + $this->boot(); + } + /** * {@inheritdoc} */ @@ -373,7 +384,7 @@ public function setClassCache(array $classes) @trigger_error(__METHOD__.'() is deprecated since version 3.3, to be removed in 4.0.', E_USER_DEPRECATED); } - file_put_contents($this->getCacheDir().'/classes.map', sprintf('warmupDir ?: $this->getCacheDir()).'/classes.map', sprintf('getCacheDir().'/annotations.map', sprintf('warmupDir ?: $this->getCacheDir()).'/annotations.map', sprintf('= 70000) { @trigger_error(__METHOD__.'() is deprecated since version 3.3, to be removed in 4.0.', E_USER_DEPRECATED); } + $cacheDir = $this->warmupDir ?: $this->getCacheDir(); - if (!$this->booted && is_file($this->getCacheDir().'/classes.map')) { - ClassCollectionLoader::load(include($this->getCacheDir().'/classes.map'), $this->getCacheDir(), $name, $this->debug, false, $extension); + if (!$this->booted && is_file($cacheDir.'/classes.map')) { + ClassCollectionLoader::load(include($cacheDir.'/classes.map'), $cacheDir, $name, $this->debug, false, $extension); } } @@ -536,7 +548,8 @@ protected function getContainerBaseClass() protected function initializeContainer() { $class = $this->getContainerClass(); - $cache = new ConfigCache($this->getCacheDir().'/'.$class.'.php', $this->debug); + $cacheDir = $this->warmupDir ?: $this->getCacheDir(); + $cache = new ConfigCache($cacheDir.'/'.$class.'.php', $this->debug); $fresh = true; if (!$cache->isFresh()) { if ($this->debug) { @@ -580,8 +593,8 @@ protected function initializeContainer() if ($this->debug) { restore_error_handler(); - file_put_contents($this->getCacheDir().'/'.$class.'Deprecations.log', serialize(array_values($collectedLogs))); - file_put_contents($this->getCacheDir().'/'.$class.'Compiler.log', null !== $container ? implode("\n", $container->getCompiler()->getLog()) : ''); + file_put_contents($cacheDir.'/'.$class.'Deprecations.log', serialize(array_values($collectedLogs))); + file_put_contents($cacheDir.'/'.$class.'Compiler.log', null !== $container ? implode("\n", $container->getCompiler()->getLog()) : ''); } } @@ -636,7 +649,7 @@ protected function getKernelParameters() 'kernel.environment' => $this->environment, 'kernel.debug' => $this->debug, 'kernel.name' => $this->name, - 'kernel.cache_dir' => realpath($this->getCacheDir()) ?: $this->getCacheDir(), + 'kernel.cache_dir' => realpath($cacheDir = $this->warmupDir ?: $this->getCacheDir()) ?: $cacheDir, 'kernel.logs_dir' => realpath($this->getLogDir()) ?: $this->getLogDir(), 'kernel.bundles' => $bundles, 'kernel.bundles_metadata' => $bundlesMetadata, @@ -682,7 +695,7 @@ protected function getEnvParameters() */ protected function buildContainer() { - foreach (array('cache' => $this->getCacheDir(), 'logs' => $this->getLogDir()) as $name => $dir) { + foreach (array('cache' => $this->warmupDir ?: $this->getCacheDir(), 'logs' => $this->getLogDir()) as $name => $dir) { if (!is_dir($dir)) { if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) { throw new \RuntimeException(sprintf("Unable to create the %s directory (%s)\n", $name, $dir)); @@ -786,9 +799,6 @@ protected function dumpContainer(ConfigCache $cache, ContainerBuilder $container @chmod($dir.$file, 0666 & ~umask()); } - // track changes made to the container directory - $container->fileExists(dirname($dir.$file)); - $cache->write($rootCode, $container->getResources()); } diff --git a/src/Symfony/Component/HttpKernel/RebootableInterface.php b/src/Symfony/Component/HttpKernel/RebootableInterface.php new file mode 100644 index 000000000000..58d9ef59e448 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/RebootableInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel; + +/** + * Allows the Kernel to be rebooted using a temporary cache directory. + * + * @author Nicolas Grekas + */ +interface RebootableInterface +{ + /** + * Reboots a kernel. + * + * The getCacheDir() method of a rebootable kernel should not be called + * while building the container. Use the %kernel.cache_dir% parameter instead. + * + * @param string|null $warmupDir pass null to reboot in the regular cache directory + */ + public function reboot($warmupDir); +}