2013-02-04 9 views
5

新しいデータベースを生成してそのスキーマを構築するために、他のコマンドに依存するコマンドを作成しています。これまでconfig.ymlファイルを読み込み、新しい接続情報を追加し、ファイルを書き戻すことに成功しました。同じコマンドでsymfonyコマンドを実行してデータベースとschema:updateを作成しようとしています。これが私たちが問題に取り組んでいるところです。symfony 2:コマンド内部から更新された設定にアクセスする

このコマンドを2回実行すると、更新された設定ファイルがアプリケーションに新しく読み込まれるため、エラーは発生しません。 config.ymlファイルに書き込んだ後に手動でdoctrineコマンドを実行すると、エラーなしで動作します。

私たちはデータベースのcreateコマンドとupdateコマンドを実行している時点で、メモリに保存されている現在のカーネルバージョンのconfig.yml/database.ymlを使用していると考えています。私たちは、アプリケーション/カーネルの設定(shutdown()、boot()など)を再起動するために、さまざまな方法を試みました。ここでは、コードです:

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); 
    } 
} 

答えて

3

DICは、コンパイルプロセスを通過し、その後、現在実行中のプロセスの中に含まれているPHPファイルに書き込まれているので、これは動作しない理由はあります。あなたは、サービスの定義を変更して、これらの変更をコンパイルするには、「リブート」にカーネルをしようとすると、それがコンパイルされたファイルをもう一度(するrequire_once)が含まれません

https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpKernel/Kernel.php#L562

を、それ:あなたはここで見ることができます古いコンパイルされたサービス定義を含むすでに含まれているDICクラスの別のインスタンスを作成するだけです。

私が考えることができる最も簡単な方法は、単にあなたのAppKernelを拡張する空のKernelクラスを作成することです。これと同じように:あなたは新しいサービス定義を保存した後、あなたのコマンドで次に

<?php 

namespace Test\MyBundle\Command; 

class FakeKernel extends \AppKernel 
{ 
} 

、あなたはこのカーネルを起動することができ、それはの一部として「FakeKernel」名前を使用して、新しいDICのクラスを再コンパイルしますファイル名は、それにはが含まれます。そのような:

$kernel = new \Test\MyBundle\Command\FakeKernel($input->getOption('env'), true); 
$application = new \Symfony\Bundle\FrameworkBundle\Console\Application($kernel); 

は、その後、新しいDICで実行されます。この新しいアプリケーションに対するあなたのサブコマンドを実行します。

$application->run($db_create_input, $output); 

免責事項:これは非常にハック感じています。私は他の解決策や回避策について聞いています。

+0

あなたの提案はスポットライトです。 AdminBundleの下に新しい 'Services'フォルダを作成し、新しい 'CommandKernal'クラスをそこに配置しました。それは魅力のように働いた。ありがとうメトリックトン! – lewsid

関連する問題