7

他のコマンドに依存して新しいデータベースを生成し、そのスキーマを構築するコマンドを作成しています。これまでのところ、config.ymlファイルを読み取り、新しい接続情報を追加し、ファイルを書き戻すことに成功しています。同じコマンドで、symfonyコマンドを実行してデータベースとschema:updateを作成しようとしています。これは私たちが問題に直面しているところです。次のエラーが発生します。

[InvalidArgumentException]「mynewdatabase」という名前のDoctrineORMManagerが存在しません。

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

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

1 に答える 1

5

これが機能しない理由は、DICがコンパイルプロセスを経て、現在実行中のプロセスに含まれるPHPファイルに書き込まれるためです。あなたがここで見ることができるもの:

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

サービス定義を変更してからカーネルを「再起動」してこれらの変更をコンパイルしようとすると、コンパイルされたファイルが2回目に含まれることはなく(require_once)、古いコンパイル済みの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);

免責事項:これは非常にハッキーな感じがします。私は他の解決策/回避策を聞くことにオープンです。

于 2013-02-04T23:07:11.010 に答える