diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/AbstractHttpCacheCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/AbstractHttpCacheCommand.php new file mode 100644 index 0000000000000..ee78fa3a72c22 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Command/AbstractHttpCacheCommand.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Command; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\HttpKernel\KernelInterface; +use Symfony\Component\HttpKernel\HttpCache\HttpCache; + +abstract class AbstractHttpCacheCommand extends ContainerAwareCommand +{ + /** + * @return array + */ + protected function getDefinitionArray() + { + return array( + new InputArgument('uri', InputArgument::OPTIONAL, 'A full uri, including the scheme, host, path and query string'), + new InputOption('kernel_class_name', '', InputOption::VALUE_OPTIONAL, 'Name of the HttpCache kernel', 'AppCache'), + ); + } + + /** + * @return string cache dir + * @throws \RuntimeException + */ + protected function getCacheDir() + { + $cacheDir = $this->getContainer()->getParameter('kernel.cache_dir').'/http_cache'; + if (!is_readable($cacheDir)) { + throw new \RuntimeException(sprintf('Unable to write in the "%s" directory', $cacheDir)); + } + + return $cacheDir; + } + + /** + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\HttpKernel\KernelInterface $kernel + * @return \Symfony\Component\HttpKernel\HttpCache\HttpCache + * @throws \RuntimeException + */ + protected function getCacheKernel(InputInterface $input, KernelInterface $kernel) + { + $kernelClassName = $input->getOption('kernel_class_name'); + if (!class_exists($kernelClassName)) { + throw new \RuntimeException(sprintf('Kernel class "%s" not loadable', $kernelClassName)); + } + + $cacheKernel = new $kernelClassName($kernel); + if (! $cacheKernel instanceof HttpCache) { + throw new \RuntimeException(sprintf('Kernel ("%s") is not an instance of HttpCache', get_class($kernel))); + } + + return $cacheKernel; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/HttpCacheCleanupCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/HttpCacheCleanupCommand.php new file mode 100644 index 0000000000000..f346d77242e03 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Command/HttpCacheCleanupCommand.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Command; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\HttpFoundation\Request; + +/** + * TODO: this command is a bit all over the place + * imho there should be a command for releasing locks and purging stale data + * and it should be able to do this for all cache entries or just a specific uri + * note sure if this should be two separate or just one command + * also this will require further changes to Store/StoreInterface + */ +class HttpCacheCleanupCommand extends AbstractHttpCacheCommand +{ + /** + * @see Command + */ + protected function configure() + { + $this + ->setName('http:cache:cleanup') + ->setDefinition($this->getDefinitionArray()) + ->setDescription('Cleans up locked files in the http cache') + ->setHelp(<<%command.name% command cleans up all locked entries in the http cache +for a given environment and debug mode: + +php %command.full_name% --env=dev +php %command.full_name% --env=prod --no-debug +EOF + ) + ; + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $kernel = $this->getContainer()->get('kernel'); + $cacheKernel = $this->getCacheKernel($input, $kernel); + + $uri = $input->getArgument('uri'); + if (empty($uri)) { + $output->writeln(sprintf('Cleaning up the http cache for the %s environment with debug %s', $kernel->getEnvironment(), var_export($kernel->isDebug(), true))); + $cacheKernel->getStore()->cleanup(); + return 0; + } + + $output->writeln(sprintf('Cleaning up the http cache for the uri %s and the %s environment with debug %s', $uri, $kernel->getEnvironment(), var_export($kernel->isDebug(), true))); + + $store = $cacheKernel->getStore(); + $request = Request::create($uri); + if ($store->isLocked($request)) { + $output->writeln(sprintf('Removed lock for the uri %s', $uri)); + $store->unlock($request); + } + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/HttpCacheClearCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/HttpCacheClearCommand.php new file mode 100644 index 0000000000000..2127385dbb61c --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Command/HttpCacheClearCommand.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Command; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class HttpCacheClearCommand extends AbstractHttpCacheCommand +{ + /** + * @see Command + */ + protected function configure() + { + $this + ->setName('http:cache:clear') + ->setDefinition($this->getDefinitionArray()) + ->setDescription('Clears the http cache') + ->setHelp(<<%command.name% command clears the application http cache for a given environment +and debug mode: + +php %command.full_name% --env=dev +php %command.full_name% --env=prod --no-debug +EOF + ) + ; + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $kernel = $this->getContainer()->get('kernel'); + $cacheKernel = $this->getCacheKernel($input, $kernel); + + $uri = $input->getArgument('uri'); + if (empty($uri)) { + $output->writeln(sprintf('Clearing the http cache for the %s environment with debug %s', $kernel->getEnvironment(), var_export($kernel->isDebug(), true))); + $filesystem = $this->getContainer()->get('filesystem'); + $cacheDir = $this->getCacheDir(); + $filesystem->remove($cacheDir); + return 0; + } + + $output->writeln(sprintf('Clearing the http cache for the uri %s and the %s environment with debug %s', $uri, $kernel->getEnvironment(), var_export($kernel->isDebug(), true))); + + $store = $cacheKernel->getStore(); + $store->purge($uri); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/HttpCacheInfoCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/HttpCacheInfoCommand.php new file mode 100644 index 0000000000000..2a67b230fb3d7 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Command/HttpCacheInfoCommand.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Command; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\HttpFoundation\Request; + +class HttpCacheInfoCommand extends AbstractHttpCacheCommand +{ + /** + * @see Command + */ + protected function configure() + { + $this + ->setName('http:cache:info') + ->setDefinition($this->getDefinitionArray()) + ->setDescription('Provides information about entries in the http cache') + ->setHelp(<<%command.name% command provides information about entries in the http cache +for a given environment and debug mode: + +php %command.full_name% --env=dev +php %command.full_name% --env=prod --no-debug +EOF + ) + ; + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $kernel = $this->getContainer()->get('kernel'); + $cacheKernel = $this->getCacheKernel($input, $kernel); + + $uri = $input->getArgument('uri'); + + $output->writeln(sprintf('Reading information from the http cache for the uri %s and the %s environment with debug %s', $uri, $kernel->getEnvironment(), var_export($kernel->isDebug(), true))); + + $store = $cacheKernel->getStore(); + $request = Request::create($uri); + $txt = $store->isCached($request) ? ('cached'.($store->isLocked($request) ? ' and locked' : ' and unlocked')) : 'not cached'; + $output->writeln(sprintf('Location (is %s): %s', $txt, $store->getLocation($request))); + } +} diff --git a/src/Symfony/Component/HttpKernel/HttpCache/Store.php b/src/Symfony/Component/HttpKernel/HttpCache/Store.php index b0662db99d062..6076e5a782f77 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/Store.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/Store.php @@ -106,6 +106,11 @@ public function isLocked(Request $request) return is_file($this->getPath($this->getCacheKey($request).'.lck')); } + public function isCached(Request $request) + { + return is_file($this->getLocation($request)); + } + /** * Locates a cached Response for the Request provided. * @@ -361,6 +366,11 @@ private function save($key, $data) @chmod($path, 0666 & ~umask()); } + public function getLocation(Request $request) + { + return $this->getPath($this->getCacheKey($request)); + } + public function getPath($key) { return $this->root.DIRECTORY_SEPARATOR.substr($key, 0, 2).DIRECTORY_SEPARATOR.substr($key, 2, 2).DIRECTORY_SEPARATOR.substr($key, 4, 2).DIRECTORY_SEPARATOR.substr($key, 6); diff --git a/src/Symfony/Component/HttpKernel/HttpCache/StoreInterface.php b/src/Symfony/Component/HttpKernel/HttpCache/StoreInterface.php index 29a54d8725445..227fea81e11b9 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/StoreInterface.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/StoreInterface.php @@ -80,6 +80,24 @@ public function unlock(Request $request); */ public function isLocked(Request $request); + /** + * Returns whether or not a cache entry exists. + * + * @param Request $request A Request instance + * + * @return Boolean true if cache entry exists, false otherwise + */ + public function isCached(Request $request); + + /** + * Returns the location where the cache entry is stored + * + * @param Request $request A Request instance + * + * @return string Location of the cache entry for the given Request + */ + public function getLocation(Request $request); + /** * Purges data for the given URL. *