[HttpKernel][FrameworkBundle] Add RebootableInterface, fix and un-deprecate cache:clear with warmup

This commit is contained in:
Nicolas Grekas 2017-08-04 14:41:57 +02:00
parent f751ac9ac1
commit a4fc49294e
6 changed files with 98 additions and 33 deletions

View File

@ -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
-------

View File

@ -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
----

View File

@ -19,6 +19,7 @@ use Symfony\Component\EventDispatcher\EventDispatcher;
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 @@ EOF
$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 @@ EOF
{
// 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 @@ EOF
}
$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 @@ EOF
));
}
// 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();

View File

@ -4,6 +4,7 @@ CHANGELOG
3.4.0
-----
* added `RebootableInterface` and implemented it in `Kernel`
* deprecated commands auto registration
* added `AddCacheClearerPass`
* added `AddCacheWarmerPass`

View File

@ -43,7 +43,7 @@ use Symfony\Component\ClassLoader\ClassCollectionLoader;
*
* @author Fabien Potencier <fabien@symfony.com>
*/
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 @@ abstract class Kernel implements KernelInterface, TerminableInterface
$this->booted = true;
}
/**
* {@inheritdoc}
*/
public function reboot($warmupDir)
{
$this->shutdown();
$this->warmupDir = $warmupDir;
$this->boot();
}
/**
* {@inheritdoc}
*/
@ -373,7 +384,7 @@ abstract class Kernel implements KernelInterface, TerminableInterface
@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('<?php return %s;', var_export($classes, true)));
file_put_contents(($this->warmupDir ?: $this->getCacheDir()).'/classes.map', sprintf('<?php return %s;', var_export($classes, true)));
}
/**
@ -381,7 +392,7 @@ abstract class Kernel implements KernelInterface, TerminableInterface
*/
public function setAnnotatedClassCache(array $annotatedClasses)
{
file_put_contents($this->getCacheDir().'/annotations.map', sprintf('<?php return %s;', var_export($annotatedClasses, true)));
file_put_contents(($this->warmupDir ?: $this->getCacheDir()).'/annotations.map', sprintf('<?php return %s;', var_export($annotatedClasses, true)));
}
/**
@ -424,9 +435,10 @@ abstract class Kernel implements KernelInterface, TerminableInterface
if (\PHP_VERSION_ID >= 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 @@ abstract class Kernel implements KernelInterface, TerminableInterface
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 @@ abstract class Kernel implements KernelInterface, TerminableInterface
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 @@ abstract class Kernel implements KernelInterface, TerminableInterface
'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 @@ abstract class Kernel implements KernelInterface, TerminableInterface
*/
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 @@ abstract class Kernel implements KernelInterface, TerminableInterface
@chmod($dir.$file, 0666 & ~umask());
}
// track changes made to the container directory
$container->fileExists(dirname($dir.$file));
$cache->write($rootCode, $container->getResources());
}

View File

@ -0,0 +1,30 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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 <p@tchwork.com>
*/
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);
}