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

Dar*_*ght 8 php symfony doctrine-orm

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

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

我设置了另一个连接,我已经放弃到DBAL层来对这个模式进行查询,到目前为止一直运行良好.

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

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

谢谢!达拉赫

Dar*_*ght 11

更新

2013年10月3日

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

没有人提供一个例子,为了参考/完整性,我会更新我的答案.我不得不承认,我是不是真的太子港既成事实与定义定制服务时,我最初发布这个答案,但我们的生活和学习.

原始答案保留在下面.

1.创建其他DBAL连接

  • 创建连接fooapp/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%
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

    return array();
}
Run Code Online (Sandbox Code Playgroud)

完成:)感谢Acayrakoskoz他们的反馈.


好的,我想我找到了一个适合我的解决方案.

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

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

  1. 在包含类的包装类中创建另一个DBAL连接config.yml:
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%
Run Code Online (Sandbox Code Playgroud)
  1. 在指定的路径创建包装类:
<?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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

希望这可以帮助!