I have a problem using MVCTranslator with translations stored in the database.
I configured the translations to use remote_translation, but I can not create a factory for my custom loader.
My files look like this:
module.config.php
'translator' => [
'locale' => 'en_US',
'translation_file_patterns' => [
[
'type' => 'phparray',
'base_dir' => getcwd() . '/data/language',
'pattern' => '%s.php',
'text_domain' => 'default',
],
],
'remote_translation' => [
[
'type' => Model\DatabaseTranslationLoader::class,
'text_domain' => 'default',
]
],
],
Module.php
namespace MyNamespace;
use Zend\ModuleManager\Feature\ConfigProviderInterface;
class Module implements ConfigProviderInterface
{
public function getConfig()
{
return include __DIR__ . '/../config/module.config.php';
}
/*
....
...
....
*/
public function getControllerConfig()
{
return [
'factories' => [
Controller\MyController::class => function($container) {
$translator = $container->get('MvcTranslator');
$translator->getPluginManager()->setFactory(Translator\DatabaseTranslationLoader::class, Factory\DatabaseTranslationLoaderFactory::class);
return new Controller\MyController(
$translator
);
},
],
];
}
}
Translator\DatabaseTranslationLoader.php
namespace MyNamespace\Translator;
use Zend\Db\Adapter\Adapter as DbAdapter;
use Zend\I18n\Translator\Loader\RemoteLoaderInterface;
class DatabaseTranslationLoader implements RemoteLoaderInterface
{
protected $dbAdapter;
public function __construct(DbAdapter $adapter)
{
$this->dbAdapter = $adapter;
}
public function load($locale, $filename)
{
// Database operations
}
Factory\DatabaseTranslationLoaderFactory.php
namespace MyNamespace\Factory\DatabaseTranslation;
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
class DatabaseTranslationLoaderFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$dbAdapter = $container->get(Zend\Db\Adapter\AdapterInterface:class);
return new Translator\DatabaseTranslationLoader($dbAdapter);
}
}
With this configuration, when I try to retrieve database adapter in DatabaseTranslationLoaderFactory receives an exception from the service manager:
Unable to resolve service "Zend\Db\Adapter\Adapter" to a factory; are you certain you provided it during configuration?
It looks like the factory has an empty container (a new ServiceManager instance?).
What am I doing wrong? Does anyone have any idea how to do this? I will be grateful for any suggestions.
EDIT:
As mentioned above, it looks like this is a new serviceMenager instance in the DatabaseTranslationLoaderFactory.
The same error gets when I try to do:
$container->get('router')
or
$container->get('request')
After hours of searching, I found a solution to my problem.
The explanation of the problem was found in Zend\I18n\Translator\Translator.php:
public function setPluginManager(LoaderPluginManager $pluginManager)
{
$this->pluginManager = $pluginManager;
return $this;
}
public function getPluginManager()
{
if (! $this->pluginManager instanceof LoaderPluginManager) {
$this->setPluginManager(new LoaderPluginManager(new ServiceManager));
}
return $this->pluginManager;
}
From the above, getPluginManager by default creates a new LoaderPluginManager instance with a new instance of ServiceManager.
In my case, to have access to the ServiceManager in the DatabaseTranslationLoaderFactory I had to first use the setPluginManager method, as follows:
Module.php
namespace MyNamespace;
use Zend\ModuleManager\Feature\ConfigProviderInterface;
class Module implements ConfigProviderInterface
{
public function getConfig()
{
return include __DIR__ . '/../config/module.config.php';
}
/*
....
...
....
*/
public function getControllerConfig()
{
return [
'factories' => [
Controller\MyController::class => function($container) {
$translator = $container->get('MvcTranslator');
// This line solved my problem
$translator->setPluginManager(new \Zend\I18n\Translator\LoaderPluginManager($container));
$translator->getPluginManager()->setFactory(Translator\DatabaseTranslationLoader::class, Factory\DatabaseTranslationLoaderFactory::class);
return new Controller\MyController(
$translator
);
},
],
];
}
}
I do not know if this solution is correct, but it works.
Maybe it will help someone :)