Skip to content

[Config][FrameworkBundle/Translation][Router] Interchangeable ConfigCache #5912

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class CompilerDebugDumpPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
// this does not really mean a ConfigCache, but just a way of atomically
// writing to a file?
$cache = new ConfigCache($this->getCompilerLogFilename($container), false);
$cache->write(implode("\n", $container->getCompiler()->getLog()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class ContainerBuilderDebugDumpPass implements CompilerPassInterface
public function process(ContainerBuilder $container)
{
$dumper = new XmlDumper($container);
// this does not really mean a ConfigCache, but just a way of atomically
// writing to a file?
$cache = new ConfigCache($container->getParameter('debug.container.dump'), false);
$cache->write($dumper->dump());
}
Expand Down
94 changes: 64 additions & 30 deletions src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php
Original file line number Diff line number Diff line change
Expand Up @@ -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\ConfigCacheFactory;
use Symfony\Component\Config\ConfigCacheInterface;

/**
* Translator.
Expand All @@ -26,6 +28,7 @@ class Translator extends BaseTranslator
protected $container;
protected $options;
protected $loaderIds;
protected $configCacheFactory;

/**
* Constructor.
Expand Down Expand Up @@ -62,6 +65,30 @@ public function __construct(ContainerInterface $container, MessageSelector $sele
parent::__construct(null, $selector);
}

/**
* Sets the configCacheFactory
*
* @param ConfigCacheFactoryInterface $configCacheFactory
*/
public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory)
{
$this->configCacheFactory = $configCacheFactory;
}

/**
* Returns the configCacheFactory set by setConfigCacheFactory or a BC default implementation
*
* @return ConfigCacheFactoryInterface $configCacheFactory
*/
private function getConfigCacheFactory()
{
if (!$this->configCacheFactory) {
$this->configCacheFactory = new ConfigCacheFactory($this->options['debug']);
}

return $this->configCacheFactory;
}

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -89,32 +116,44 @@ 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;
}

}

/* 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();

parent::loadCatalogue($locale);
parent::loadCatalogue($locale);

$fallbackContent = '';
$current = '';
foreach ($this->computeFallbackLocales($locale) as $fallback) {
$fallbackContent .= sprintf(<<<EOF
$fallbackContent = '';
$current = '';
foreach ($this->computeFallbackLocales($locale) as $fallback) {
$fallbackContent .= sprintf(<<<EOF
\$catalogue%s = new MessageCatalogue('%s', %s);
\$catalogue%s->addFallbackCatalogue(\$catalogue%s);


EOF
,
ucfirst($fallback),
$fallback,
var_export($this->catalogues[$fallback]->all(), true),
ucfirst($current),
ucfirst($fallback)
);
$current = $fallback;
}
,
ucfirst($fallback),
$fallback,
var_export($this->catalogues[$fallback]->all(), true),
ucfirst($current),
ucfirst($fallback)
);
$current = $fallback;
}

$content = sprintf(<<<EOF
$content = sprintf(<<<EOF
<?php

use Symfony\Component\Translation\MessageCatalogue;
Expand All @@ -125,18 +164,13 @@ protected function loadCatalogue($locale)
return \$catalogue;

EOF
,
$locale,
var_export($this->catalogues[$locale]->all(), true),
$fallbackContent
);

$cache->write($content, $this->catalogues[$locale]->getResources());

return;
}
,
$locale,
var_export($this->catalogues[$locale]->all(), true),
$fallbackContent
);

$this->catalogues[$locale] = include $cache;
$cache->write($content, $this->catalogues[$locale]->getResources());
}

protected function initialize()
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Component/Config/ConfigCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ConfigCache
class ConfigCache implements ConfigCacheInterface
{
private $debug;
private $file;
Expand Down
43 changes: 43 additions & 0 deletions src/Symfony/Component/Config/ConfigCacheFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?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\Config;

/**
* Default implementation of ConfigCacheFactoryInterface
*
* @author Benjamin Klotz <bk@webfactory.de>
*/
class ConfigCacheFactory implements ConfigCacheFactoryInterface
{
protected $debug;

/**
* Constructor.
*
* @param bool $debug Whether to enable debugging or not
*/
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;
}

}
31 changes: 31 additions & 0 deletions src/Symfony/Component/Config/ConfigCacheFactoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?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\Config;

/**
* Interface for ConfigCacheFactory
*
* @author Benjamin Klotz <bk@webfactory.de>
*/
interface ConfigCacheFactoryInterface
{

/**
* Factory Method
*
* @param string $file The absolute cache path
* @param callback $callback The callback to be executed when the cache needs to be filled (i. e. is not fresh). The cache will be passed as the only parameter.
* @return ConfigCacheInterface $configCache
*/
public function cache($file, $callback);

}
46 changes: 46 additions & 0 deletions src/Symfony/Component/Config/ConfigCacheInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?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\Config;

/**
* Interface for ConfigCache
*
* @author Benjamin Klotz <bk@webfactory.de>
*/
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 in the cache
* @param array $metadata An array of ResourceInterface instances
*
* @throws \RuntimeException When cache file can't be wrote
*/
public function write($content, array $metadata = null);

}
70 changes: 52 additions & 18 deletions src/Symfony/Component/Routing/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Config\ConfigCache;
use Symfony\Component\Config\ConfigCacheFactoryInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Routing\Generator\ConfigurableRequirementsInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
Expand Down Expand Up @@ -65,6 +66,7 @@ class Router implements RouterInterface
* @var LoggerInterface|null
*/
protected $logger;
protected $configCacheFactory;

/**
* Constructor.
Expand Down Expand Up @@ -199,6 +201,30 @@ public function getContext()
return $this->context;
}

/**
* Sets an configCacheFactory-implementation
*
* @param configCacheFactoryInterface $configCacheFactory The implementation
*/
public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory)
{
$this->configCacheFactory = $configCacheFactory;
}

/**
* Returns the configCacheFactory set by setConfigCacheFactory or a BC default implementation
*
* @return ConfigCacheFactoryInterface $configCacheFactory
*/
private function getConfigCacheFactory()
{
if (!$this->configCacheFactory) {
$this->configCacheFactory = new \Symfony\Component\Config\ConfigCacheFactory($this->options['debug']);
}

return $this->configCacheFactory;
}

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -231,17 +257,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($class)) {
$dumper = new $this->options['matcher_dumper_class']($this->getRouteCollection());
$routerOptions = $this->options;
$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 ($routerOptions, $self, $class) {
$dumper = new $routerOptions['matcher_dumper_class']($self->getRouteCollection());

$cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
}
$options = array(
'class' => $class,
'base_class' => $routerOptions['matcher_base_class'],
);

$cache->write($dumper->dump($options), $self->getRouteCollection()->getResources());
}
);

require_once $cache;

Expand All @@ -263,17 +293,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($class)) {
$dumper = new $this->options['generator_dumper_class']($this->getRouteCollection());
$routerOptions = $this->options;
$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 ($routerOptions, $self, $class) {
$dumper = new $routerOptions['generator_dumper_class']($self->getRouteCollection());

$cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
}
$options = array(
'class' => $class,
'base_class' => $routerOptions['generator_base_class'],
);

$cache->write($dumper->dump($options), $self->getRouteCollection()->getResources());
}
);

require_once $cache;

Expand Down