在Symfony2中组织可重用DBAL查询的最佳实践?

时间:2011-11-23 11:03:59

标签: php symfony doctrine-orm

我正在研究Symfony2项目。在大多数情况下,它是完全标准的;我正在使用ORM层通过我的实体与数据库连接。没问题。

但是,我确实需要对系统中其他地方的现有模式中的少数几个表进行不频繁的查询,其中包含我称之为“参考”的信息:货币转换率等等。我SELECT只能访问此架构。

我设置了另一个连接,我一直在使用DBAL层来对这个模式进行查询,到目前为止,该模式一直运行良好。

我的问题是,虽然不常见,但我想我需要在我的应用中的多个地方重复我的一些DBAL查询;我想将这些查询重构为某种存储库,它们更容易使用/测试/等。我考虑过为表创建实体,但我认为在这种情况下这样做太过分了。我是否认为您需要实体来创建存储库?

相反,我想知道是否有'Symfony方式'来做到这一点?好看又优雅的东西:)

谢谢! 达拉赫

2 个答案:

答案 0 :(得分:11)

更新

2013年10月3日

原谅我编辑一个两年前的答案......然而,有几个人质疑现有的方法,虽然它有效(并且适用于我的特定用例),但定义服务当然是 Symfony方式

没人提供一个例子,为了参考/完整性,我会更新我的答案。我不得不承认,当我最初发布这个答案时,我并不是真的 au fait 定义自定义服务,但我们生活和学习。

原始答案保留在下面。

1。创建其他DBAL连接

  • foo
  • 中创建连接app/config/config.yml
  • 在这种情况下不需要参数wrapper_class(参见原始答案)。
doctrine:
    dbal:
        connections:
            default:
                driver:   %database_driver%
                host:     %database_host%
                dbname:   %database_name%
                user:     %database_user%
            foo:
                driver:   %foo_driver%
                host:     %foo_host%
                dbname:   %foo_name%
                user:     %foo_user%

2。配置服务

  • 假设YAML格式。
  • 将配置添加到src/Acme/TestBundle/Resources/config/services.yml
  • 注意,我们将以上定义的DBAL foo_connection注入服务。
services:
    foo_query_service:
        class: Acme\TestBundle\Services\FooQueryService
        arguments:
            - @doctrine.dbal.foo_connection

3。为已配置的服务创建类

  • src/Acme/TestBundle/Services/FooQueryService.php
  • 创建以下课程
<?php

namespace Acme\TestBundle\Services;

use DateTime;
use Doctrine\DBAL\Connection;

class FooQueryService
{
    private $connection;

    public function __construct(Connection $connection)
    {
        $this->connection = $connection;
    }

    public function findBarByDate(DateTime $date)
    {
        $stmt = $this->connection->prepare('SELECT * FROM bar WHERE date = :date');
        $stmt->bindValue('date', $date, 'datetime');
        $stmt->execute();

        return $stmt->fetch();
    }
}

4。最后,在您需要的地方使用您的查询!

例如,在控制器中......

/**
 * @Route("/", name="home")
 * @Template()
 */
public function indexAction()
{
    $date = new \DateTime();

    $result = $this->get('foo_query_service')
        ->findBarByDate($date);

    return array();
}

完成:)感谢Acayrakoskoz提供反馈。


好的,我认为在这种情况下我找到了一个适合我的解决方案。

我实际上又看了一下创建实体/管理器 - 实际上,关于将特定实体映射到多个管理器的Symfony2文档似乎缺乏。在这种情况下,它似乎仍然是一种过度杀伤的方法(并且'参考'模式非常混乱)。

幸运的是,可以为DBAL连接指定包装类,并将查询抽象为特定方法。

  1. 使用config.yml中的包装类创建其他DBAL连接:
  2. doctrine:
        orm:
            connections:
                default:
                    driver:   %driver%
                    host:     %host%
                    dbname:   %name%
                    user:     %user%
                foo:
                    wrapper_class: 'Acme\TestBundle\Doctrine\DBAL\FooConnection'
                    driver:   %foo_driver%
                    host:     %foo_host%
                    dbname:   %foo_name%
                    user:     %foo_user%
    
    1. 在指定的路径上创建包装类:
    2. <?php
      
      namespace Acme\TestBundle\Doctrine\DBAL\FooConnection;
      use Doctrine\DBAL\Connection;
      
      class FooConnection extends Connection
      {
          // custom query...
          public function findBarByDate(\DateTime $date)
          {
              $stmt = $this->prepare('SELECT * FROM bar WHERE date = :date');
              $stmt->bindValue('date', $date, 'datetime');
              $stmt->execute();  
      
              return $stmt->fetch();
          }
      }
      

      请注意,包装类必须扩展\Doctrine\DBAL\Connection

      1. 在您需要的地方使用您的查询:
      2. $date   = new \DateTime();
        $conn   = $this->getDoctrine()->getConnection('foo');
        $result = $conn->findBarByDate($date);
        

        希望这有帮助!

答案 1 :(得分:0)

哇,你的回答意味着你在每张桌子的相同位置都有你的所有疑问。

我不喜欢这个包装器,我更喜欢有服务。每个表或每个捆绑一个服务,这取决于您是否有很多表以及您希望如何组织查询。

然后我将所需的连接作为服务的参数传递,这就是全部。