Php Symfony 2:从命令内部访问更新的配置
我们正在创建一个命令,该命令依赖于其他命令来生成新数据库并构建其模式。到目前为止,我们已经成功地让它读取config.yml文件,添加新的连接信息,并写回该文件。在同一个命令中,我们尝试运行symfony命令来创建数据库和模式:update。这就是我们遇到问题的地方。我们得到以下错误: [InvalidArgumentException]命名为“mynewdatabase”的条令ORM管理器 不存在 如果我们再次运行该命令,则不会出现错误,因为更新的配置文件已重新加载到应用程序中。如果我们在写入config.yml文件后手动运行条令命令,它也可以正常工作 我们认为,在我们运行数据库创建和更新命令的命令中,它仍然使用存储在内存中的当前内核版本的config.yml/database.yml。我们已经尝试了许多不同的方法来重新初始化应用程序/内核配置(调用shutdown()、boot()等),但运气不好。代码如下:Php Symfony 2:从命令内部访问更新的配置,php,symfony,doctrine-orm,symfony-2.1,Php,Symfony,Doctrine Orm,Symfony 2.1,我们正在创建一个命令,该命令依赖于其他命令来生成新数据库并构建其模式。到目前为止,我们已经成功地让它读取config.yml文件,添加新的连接信息,并写回该文件。在同一个命令中,我们尝试运行symfony命令来创建数据库和模式:update。这就是我们遇到问题的地方。我们得到以下错误: [InvalidArgumentException]命名为“mynewdatabase”的条令ORM管理器 不存在 如果我们再次运行该命令,则不会出现错误,因为更新的配置文件已重新加载到应用程序中。如果我们在写入
namespace Test\MyBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Yaml\Yaml;
class GeneratorCommand extends ContainerAwareCommand
{
protected function configure()
{
$this
->setName('generate')
->setDescription('Create a new database.')
->addArgument('dbname', InputArgument::REQUIRED, 'The db name')
;
}
/*
example: php app/console generate mynewdatabase
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
//Without this, the doctrine commands will prematurely end execution
$this->getApplication()->setAutoExit(false);
//Open up app/config/config.yml
$yaml = Yaml::parse(file_get_contents($this->getContainer()->get('kernel')->getRootDir() .'/config/config.yml'));
//Take input dbname and use it to name the database
$db_name = $input->getArgument('dbname');
//Add that connection to app/config/config.yml
$yaml['doctrine']['dbal']['connections'][$site_name] = Array('driver' => '%database_driver%', 'host' => '%database_host%', 'port' => '%database_port%', 'dbname' => $site_name, 'user' => '%database_user%', 'password' => '%database_password%', 'charset' => 'UTF8');
$yaml['doctrine']['orm']['entity_managers'][$site_name] = Array('connection' => $site_name, 'mappings' => Array('MyCustomerBundle' => null));
//Now put it back
$new_yaml = Yaml::dump($yaml, 5);
file_put_contents($this->getContainer()->get('kernel')->getRootDir() .'/config/config.yml', $new_yaml);
/* http://symfony.com/doc/current/components/console/introduction.html#calling-an-existing-command */
//Set up our db create script arguments
$args = array(
'command' => 'doctrine:database:create',
'--connection' => $site_name,
);
$db_create_input = new ArrayInput($args);
//Run the symfony database create arguments
$this->getApplication()->run($db_create_input, $output);
//Set up our schema update script arguments
$args = array(
'command' => 'doctrine:schema:update',
'--em' => $site_name,
'--force' => true
);
$update_schema_input = new ArrayInput($args);
//Run the symfony database create command
$this->getApplication()->run($update_schema_input, $output);
}
}
这不起作用的原因是,DIC经过一个编译过程,然后被写入一个PHP文件,该文件随后包含在当前运行的过程中。你可以在这里看到: 如果您更改服务定义,然后尝试“重新启动”内核以编译这些更改,那么它将不会再次包含已编译的文件(需要_一次),并且它将使用旧的已编译服务定义创建已包含的DIC类的另一个实例 我能想到的解决这个问题的最简单方法是创建一个空的内核类,它只是扩展了AppKernel。像这样:
<?php
namespace Test\MyBundle\Command;
class FakeKernel extends \AppKernel
{
}
然后针对将与新DIC一起运行的新应用程序运行sub命令:
$application->run($db_create_input, $output);
免责声明:这感觉很粗糙。我愿意听取其他解决方案/变通办法。Matt你的建议很贴切。最后,我在AdminBundle下创建了一个新的“Services”文件夹,并在其中添加了一个新的“CommandKernal”类。它就像一个符咒。谢谢一公吨!
$application->run($db_create_input, $output);