如何控制在符号1.4任务中从database.yml中选择哪个连接


How to control which connection is selected from the database.yml in a symfony1.4 task

(有关更好的问题,请参阅下面的编辑)如何在symfony1.4任务中仅使用通用Doctrine_Query::create()创建查询来控制选择哪个连接(来自database.yml中的右侧环境部分)?

我使用的是一个数据库yml,它看起来像这样:

prod:
  doctrine:
    class: sfDoctrineDatabase
    param:
      dsn: mysql://some:pass@domain:port/database
  log:
    class: sfDoctrineDatabase
    param:
      dsn: mysql://some:pass@domain:port/database
  auth:
    class: sfDoctrineDatabase
    param:
      dsn: mysql://some:pass@domain:port/database
dev:
  doctrine:
    class: sfDoctrineDatabase
    param:
      dsn: mysql://some:otherpass@domain:port/database
  log:
    class: sfDoctrineDatabase
    param:
      dsn: mysql://some:otherpass@domain:port/database
  auth:
    class: sfDoctrineDatabase
    param:
      dsn: mysql://some:otherpass@domain:port/database

我希望能够控制在调用类似的东西时使用这些数据库定义中的哪一个

$query = Doctrine_Query::create()
        ->select('*')
        ->from('Products p')
        ->where('p.id = ?', $productID)
        ->limit(1);
$OfpFlPr = $query->execute()->getFirst();

目前我无法像$query = Doctrine_Query::create($conn);那样设置连接。

如有任何帮助,我们将不胜感激!


编辑:

我在使用Doctrine_Query::create()的软件中有很多更深层次的代码(没有连接参数)。它似乎通过web请求选择了正确的环境和连接。但我不知道它是如何做到这一点的,所以我可以让CLI命令以相同的方式工作(它们目前没有选择正确的连接和环境)。这就是为什么我需要知道如何控制"自动"使用哪个连接(默认选择)。

问题:

所以我想最后我的问题是:

当代码作为symfony CLI命令执行时,我如何控制在使用Doctrine_Query::create()的较低级别代码中默认选择哪个连接

$query = Doctrine_Query::create($doctrineManager->getConnection('doctrine'))
    ->select('*')
    ->from('Products p')
    ->where('p.id = ?', $productID)
    ->limit(1);

应该起作用。根据您从哪里选择Product,参数可能是"条令"、"日志"或"授权"。

你能详细说明一下为什么你"无法以这种方式设置连接"吗?

编辑:

所以,如果我做对了,您需要在cli命令中指定environment,使用database.yml中右侧部分的dsn连接字符串。您可以为cli命令使用env选项

$this->addOption('env', null, sfCommandOption::PARAMETER_OPTIONAL, 'Specify environment', 'prod'); 

到任务配置。

默认情况下,任务是用以下代码生成的:

$databaseManager = new sfDatabaseManager($this->configuration);
$connection = $databaseManager->getDatabase($options['connection'])->getConnection();

这只初始化一个连接,而不初始化上下文。相反,将其替换为:

sfContext::createInstance(new frontendConfiguration($options['env'], true));

这将使用任务的application选项创建上下文。您可能想要为其设置默认值,将任务的configure()方法更改为具有:

    $this->addOptions(array(
        new sfCommandOption('application', null, sfCommandOption::PARAMETER_REQUIRED, 'The application name', 'frontend'),
        // ...
    ));

注意,我添加了frontend来初始化前端应用程序。也可以调整env选项的默认值。

我实际问题的原因

在使用一个干净创建的任务进行了一些深度调试之后,我终于找到了罪魁祸首。Symfony 1.4似乎在实际运行预期任务之前,先运行tasks目录中每个任务的configure方法。

不幸的是,一些不知情的恶作剧者(前同事*)将一些硬编码的上下文初始化包含在这样的方法中:

// inside a task
protected function configure() {
    // context was initialized
    $configuration    = ProjectConfiguration::getApplicationConfiguration('app_name', 'prod', true);
    $context          = sfContext::createInstance($configuration);
    // so the following was available in the configure method
    $save_path = sfConfig::get('sf_app_config_dir');
    // rest of configure method implementation 
    // ...
}

这搞砸了除生产环境外的所有其他环境中所有cronjob的数据库设置(幸运的是)。

我通过做这样的事情来解决这个问题:

protected function configure() {
    $configuration    = ProjectConfiguration::getApplicationConfiguration('app_name', 'prod', true);
    // removed the context creation
    $configuration->activate(); // this makes the sfConfig::get() work
    $save_path = sfConfig::get('sf_app_config_dir');
    // rest of configure method implementation 
    // ...
}

回答我的问题

我还发现,当涉及到控制Doctrine_Query::create()使用哪个数据库连接时,您可以通过在更高级别的函数上使用类似的东西来进行一些控制:

// for making sure the 'auth' database settings are used as a default
Doctrine_Manager::getInstance()->setCurrentConnection('auth');

然而,这并不能控制"environment section"用于为数据库选择正确配置/dsn的内容。这是通过做这样的事情来完成的:

// somewhere in the execute method
$env              = 'dev'; // the environment section name; 
$configuration    = ProjectConfiguration::getApplicationConfiguration('app_name', $env, true);
$context          = sfContext::createInstance($configuration);

正如Alex Blex和Marek的回答中正确暗示的那样。使用任务"选项"使其支持他们建议的多种环境是有意义的。

*:我的前同事,我几乎不会对他生气,因为这个问题不太可能,而且有违直觉;)