diff --git a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php index b4b3acdfb47b9..1c6dfcdc136b4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php +++ b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php @@ -14,7 +14,9 @@ use Symfony\Component\Translation\Translator as BaseTranslator; use Symfony\Component\Translation\MessageSelector; use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\Config\ConfigCache; +use Symfony\Component\Config\ConfigCacheFactoryInterface; +use Symfony\Component\Config\DefaultConfigCacheFactory; +use Symfony\Component\Config\ConfigCacheInterface; /** * Translator. @@ -30,6 +32,11 @@ class Translator extends BaseTranslator ); protected $loaderIds; + /** + * @var ConfigCacheFactoryInterface|null + */ + private $configCacheFactory; + /** * Constructor. * @@ -60,6 +67,16 @@ public function __construct(ContainerInterface $container, MessageSelector $sele parent::__construct(null, $selector); } + /** + * Sets the ConfigCache factory to use. + * + * @param ConfigCacheFactoryInterface $configCacheFactory + */ + public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory) + { + $this->configCacheFactory = $configCacheFactory; + } + /** * {@inheritdoc} */ @@ -87,18 +104,30 @@ protected function loadCatalogue($locale) return parent::loadCatalogue($locale); } - $cache = new ConfigCache($this->options['cache_dir'].'/catalogue.'.$locale.'.php', $this->options['debug']); - if (!$cache->isFresh()) { - $this->initialize(); + $self = $this; + $cache = $this->getConfigCacheFactory()->cache($this->options['cache_dir'].'/catalogue.'.$locale.'.php', function ($cache) use ($self, $locale) { + $self->fillCache($cache, $locale); + }); + + if (!isset($this->catalogues[$locale])) { + $this->catalogues[$locale] = include $cache; + } - parent::loadCatalogue($locale); + } + + /* This method is only public to allow it to be called from a callback (prior PHP 5.4?) */ + public function fillCache(ConfigCacheInterface $cache, $locale) + { + $this->initialize(); - $fallbackContent = ''; - $current = ''; - foreach ($this->computeFallbackLocales($locale) as $fallback) { - $fallbackSuffix = ucfirst(str_replace('-', '_', $fallback)); + parent::loadCatalogue($locale); - $fallbackContent .= sprintf(<<computeFallbackLocales($locale) as $fallback) { + $fallbackSuffix = ucfirst(str_replace('-', '_', $fallback)); + + $fallbackContent .= sprintf(<<addFallbackCatalogue(\$catalogue%s); @@ -114,7 +143,7 @@ protected function loadCatalogue($locale) $current = $fallback; } - $content = sprintf(<<catalogues[$locale]->all(), true), - $fallbackContent - ); - - $cache->write($content, $this->catalogues[$locale]->getResources()); + , + $locale, + var_export($this->catalogues[$locale]->all(), true), + $fallbackContent + ); - return; - } - - $this->catalogues[$locale] = include $cache; + $cache->write($content, $this->catalogues[$locale]->getResources()); } protected function initialize() @@ -147,4 +171,20 @@ protected function initialize() } } } + + /** + * Provides the ConfigCache factory implementation, falling back to a + * default implementation if necessary. + * + * @return ConfigCacheFactoryInterface $configCacheFactory + */ + private function getConfigCacheFactory() + { + if (!$this->configCacheFactory) { + $this->configCacheFactory = new DefaultConfigCacheFactory($this->options['debug']); + } + + return $this->configCacheFactory; + } + } diff --git a/src/Symfony/Component/Config/ConfigCache.php b/src/Symfony/Component/Config/ConfigCache.php index cbb198427260f..aea19d9c746df 100644 --- a/src/Symfony/Component/Config/ConfigCache.php +++ b/src/Symfony/Component/Config/ConfigCache.php @@ -22,7 +22,7 @@ * * @author Fabien Potencier */ -class ConfigCache +class ConfigCache implements ConfigCacheInterface { private $debug; private $file; diff --git a/src/Symfony/Component/Config/ConfigCacheFactoryInterface.php b/src/Symfony/Component/Config/ConfigCacheFactoryInterface.php new file mode 100644 index 0000000000000..5a5fb0371ffd7 --- /dev/null +++ b/src/Symfony/Component/Config/ConfigCacheFactoryInterface.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Config; + +/** + * Interface for a ConfigCache factory. This factory creates + * an instance of ConfigCacheInterface and initializes the + * cache if necessary. + * + * @author Matthias Pigulla + */ +interface ConfigCacheFactoryInterface +{ + /** + * Creates a cache instance and (re-)initializes it if necessary. + * + * @param string $file The absolute cache file path + * @param callable $callable The callable to be executed when the cache needs to be filled (i. e. is not fresh). The cache will be passed as the only parameter to this callback. + * @return ConfigCacheInterface $configCache The cache instance. + */ + public function cache($file, $callable); +} diff --git a/src/Symfony/Component/Config/ConfigCacheInterface.php b/src/Symfony/Component/Config/ConfigCacheInterface.php new file mode 100644 index 0000000000000..b3401912ccaf6 --- /dev/null +++ b/src/Symfony/Component/Config/ConfigCacheInterface.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Config; + +/** + * Interface for ConfigCache + * + * @author Matthias Pigulla + */ +interface ConfigCacheInterface +{ + /** + * Gets the cache file path. + * + * @return string The cache file path + */ + public function __toString(); + + /** + * Checks if the cache is still fresh. + * + * @return Boolean true if the cache is fresh, false otherwise + */ + public function isFresh(); + + /** + * Writes cache. + * + * @param string $content The content to write into the cache + * @param ResourceInterface[] $metadata An array of ResourceInterface instances + * + * @throws \RuntimeException When the cache file cannot be written + */ + public function write($content, array $metadata = null); +} diff --git a/src/Symfony/Component/Config/DefaultConfigCacheFactory.php b/src/Symfony/Component/Config/DefaultConfigCacheFactory.php new file mode 100644 index 0000000000000..178f3993f0af3 --- /dev/null +++ b/src/Symfony/Component/Config/DefaultConfigCacheFactory.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Config; + +/** + * Default implementation for ConfigCacheFactoryInterface + * that will create an instance of ConfigCache. + * + * @author Matthias Pigulla + */ +class DefaultConfigCacheFactory implements ConfigCacheFactoryInterface +{ + /** @var bool Debug flag passed to the ConfigCache */ + private $debug; + + /** + * Constructor. + * + * @param bool $debug The debug flag to pass to ConfigCache. + */ + public function __construct($debug) + { + $this->debug = $debug; + } + + /** + * {@inheritdoc} + */ + public function cache($file, $callback) + { + $cache = new ConfigCache($file, $this->debug); + + if (!$cache->isFresh()) { + call_user_func($callback, $cache); + } + + return $cache; + } +} diff --git a/src/Symfony/Component/Routing/Router.php b/src/Symfony/Component/Routing/Router.php index 62abec387245f..15637aca96a1f 100644 --- a/src/Symfony/Component/Routing/Router.php +++ b/src/Symfony/Component/Routing/Router.php @@ -12,7 +12,8 @@ namespace Symfony\Component\Routing; use Symfony\Component\Config\Loader\LoaderInterface; -use Symfony\Component\Config\ConfigCache; +use Symfony\Component\Config\ConfigCacheFactoryInterface; +use Symfony\Component\Config\DefaultConfigCacheFactory; use Psr\Log\LoggerInterface; use Symfony\Component\Routing\Generator\ConfigurableRequirementsInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; @@ -70,6 +71,11 @@ class Router implements RouterInterface, RequestMatcherInterface */ protected $logger; + /** + * @var ConfigCacheFactoryInterface|null + */ + private $configCacheFactory; + /** * Constructor. * @@ -203,6 +209,16 @@ public function getContext() return $this->context; } + /** + * Sets the ConfigCache factory to use. + * + * @param ConfigCacheFactoryInterface $configCacheFactory The factory to use. + */ + public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory) + { + $this->configCacheFactory = $configCacheFactory; + } + /** * {@inheritdoc} */ @@ -249,17 +265,21 @@ public function getMatcher() } $class = $this->options['matcher_cache_class']; - $cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']); - if (!$cache->isFresh()) { - $dumper = $this->getMatcherDumperInstance(); + $baseClass = $this->options['matcher_base_class']; + $self = $this; - $options = array( - 'class' => $class, - 'base_class' => $this->options['matcher_base_class'], - ); + $cache = $this->getConfigCacheFactory()->cache($this->options['cache_dir'].'/'.$class.'.php', + function($cache) use ($self, $class, $baseClass) { + $dumper = $self->getMatcherDumperInstance(); - $cache->write($dumper->dump($options), $this->getRouteCollection()->getResources()); - } + $options = array( + 'class' => $class, + 'base_class' => $baseClass, + ); + + $cache->write($dumper->dump($options), $self->getRouteCollection()->getResources()); + } + ); require_once $cache; @@ -281,17 +301,21 @@ public function getGenerator() $this->generator = new $this->options['generator_class']($this->getRouteCollection(), $this->context, $this->logger); } else { $class = $this->options['generator_cache_class']; - $cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']); - if (!$cache->isFresh()) { - $dumper = $this->getGeneratorDumperInstance(); + $baseClass = $this->options['generator_base_class']; + $self = $this; - $options = array( - 'class' => $class, - 'base_class' => $this->options['generator_base_class'], - ); + $cache = $this->getConfigCacheFactory()->cache($this->options['cache_dir'].'/'.$class.'.php', + function($cache) use ($self, $class, $baseClass) { + $dumper = $self->getGeneratorDumperInstance(); - $cache->write($dumper->dump($options), $this->getRouteCollection()->getResources()); - } + $options = array( + 'class' => $class, + 'base_class' => $baseClass, + ); + + $cache->write($dumper->dump($options), $self->getRouteCollection()->getResources()); + } + ); require_once $cache; @@ -308,7 +332,7 @@ public function getGenerator() /** * @return GeneratorDumperInterface */ - protected function getGeneratorDumperInstance() + public function getGeneratorDumperInstance() { return new $this->options['generator_dumper_class']($this->getRouteCollection()); } @@ -316,8 +340,23 @@ protected function getGeneratorDumperInstance() /** * @return MatcherDumperInterface */ - protected function getMatcherDumperInstance() + public function getMatcherDumperInstance() { return new $this->options['matcher_dumper_class']($this->getRouteCollection()); } + + /** + * Provides the ConfigCache factory implementation, falling back to a + * default implementation if necessary. + * + * @return ConfigCacheFactoryInterface $configCacheFactory + */ + private function getConfigCacheFactory() + { + if (null === $this->configCacheFactory) { + $this->configCacheFactory = new DefaultConfigCacheFactory($this->options['debug']); + } + + return $this->configCacheFactory; + } }