Skip to content

[RFC] [Config] Use a Factory for ConfigCache instances #7781

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 3 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
84 changes: 62 additions & 22 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\DefaultConfigCacheFactory;
use Symfony\Component\Config\ConfigCacheInterface;

/**
* Translator.
Expand All @@ -30,6 +32,11 @@ class Translator extends BaseTranslator
);
protected $loaderIds;

/**
* @var ConfigCacheFactoryInterface|null
*/
private $configCacheFactory;

/**
* Constructor.
*
Expand Down Expand Up @@ -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}
*/
Expand Down Expand Up @@ -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(<<<EOF
$fallbackContent = '';
$current = '';
foreach ($this->computeFallbackLocales($locale) as $fallback) {
$fallbackSuffix = ucfirst(str_replace('-', '_', $fallback));

$fallbackContent .= sprintf(<<<EOF
\$catalogue%s = new MessageCatalogue('%s', %s);
\$catalogue%s->addFallbackCatalogue(\$catalogue%s);

Expand All @@ -114,7 +143,7 @@ protected function loadCatalogue($locale)
$current = $fallback;
}

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

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

EOF
,
$locale,
var_export($this->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()
Expand All @@ -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;
}

}
2 changes: 1 addition & 1 deletion src/Symfony/Component/Config/ConfigCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ConfigCache
class ConfigCache implements ConfigCacheInterface
{
private $debug;
private $file;
Expand Down
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 a ConfigCache factory. This factory creates
* an instance of ConfigCacheInterface and initializes the
* cache if necessary.
*
* @author Matthias Pigulla <mp@webfactory.de>
*/
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);
}
44 changes: 44 additions & 0 deletions src/Symfony/Component/Config/ConfigCacheInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?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 Matthias Pigulla <mp@webfactory.de>
*/
interface ConfigCacheInterface
{
/**
* Gets the cache file path.
*
* @return string The cache file path
*/
public function __toString();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIU, this is only for BC reasons. So, it should be deprecated in 2.7 so that we can remove it in 3.0.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to make sure I don't get you wrong: For example here __toString() is used to require the cache file. You want to replace this with an explicit method instead of __toString() and make that method part of the interface?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly. Having a __toString() method in an interface looks weird to me. So, replacing that with a getPath() method or something similar seems better to me.


/**
* 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);
}
48 changes: 48 additions & 0 deletions src/Symfony/Component/Config/DefaultConfigCacheFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?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 for ConfigCacheFactoryInterface
* that will create an instance of ConfigCache.
*
* @author Matthias Pigulla <mp@webfactory.de>
*/
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;
}
}
Loading