Doctrine 查询生成器和 Silex

Doctrine Query Builder and Silex

在我的 Silex 项目中,我使用了数据库抽象层包中的 Doctrine Query Builder。

"doctrine/dbal": "^2.5"

我是这样注册到我的应用程序容器中的。

/**
 * Make a connection to the database.
 */
$app['db'] = function() use($app) {
    $connectionParams = [
        'dbname' => $_ENV['DBNAME'],
        'user' => $_ENV['DBUSER'],
        'password' => $_ENV['DBPASS'],
        'host' => $_ENV['DBHOST'],
        'driver' => $_ENV['DBDRIVER'],
    ];

    return \Doctrine\DBAL\DriverManager::getConnection($connectionParams);
};

/**
 * Instantiate the query builder
 */
$app['db.builder'] = function() use($app) {
    return new \Doctrine\DBAL\Query\QueryBuilder($app['db']);
};

当我想查询数据库记录时,我使用存储库模式,然后将查询生成器实例注入存储库,然后我在存储库中使用查询生成器,我的存储库是这样创建的。

$app['repository.user'] = function() use($app) {
    return new App\Repositories\UserRepository($app['db.builder']);
};

$app['repository.book'] = function() use($app) {
    return new App\Repositories\BookRepository($app['db.builder']);
};

在用户存储库中,我查询一个用户以获取 ID,然后我查询图书存储库以查找属于该用户的图书,但是问题是当我在图书存储库中使用查询生成器时它已经填满了以前的用户 table。我是否需要重置查询构建器实例,或者我在将查询构建器注册到容器中时做错了什么。

QueryBuilder 已注册为常规服务,因此只会创建它的一个实例。如果您在查询某些书籍之前恰好将任何用户数据填充到其中,就是这样。

为避免此问题,您可以将 db.builder 定义为工厂服务*。这样,每次请求时,都会创建一个新实例:

$app['db.builder'] = $app->factory(function () use ($app) {
    return new \Doctrine\DBAL\Query\QueryBuilder($app['db']);
});

http://silex.sensiolabs.org/doc/master/services.html 阅读有关 Silex 中服务定义的更多信息。

*http://silex.sensiolabs.org/doc/master/services.html#factory-services

默认情况下服务是共享的,因此当您请求某些服务时 $app['xxx'] 会返回相同的副本。您应该对容器说 returns 服务是在每次调用时获取新实例的工厂。

$app['db.builder'] = $app->factory(function() use($app) {
    return new \Doctrine\DBAL\Query\QueryBuilder($app['db']);
});

在任何情况下,查询生成器将在第二次调用存储库后填充一些内容,在您的情况下,存储库保留并使用查询生成器的一个副本。最好将 db 保留在您的存储库中,添加方法以获取新的查询构建器,并在 select 来自数据库的数据的方法中使用它。

$app['repository.book'] = function() use($app) {
    return new App\Repositories\BookRepository($app['db']);
};

class \App\Repositories\BookRepository
{
    protected $db;
    protected $table = 'book';

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

    public function getQueryBuilder()
    {
        $qb = new \Doctrine\DBAL\Query\QueryBuilder($this->db);
        $qb->from($this->table);
        return $qb;
    }

    public function find1()
    {
        $qb = $this->getQueryBuilder();
        $qb...;
        return...;
    }

    public function find2()
    {
        $qb = $this->getQueryBuilder();
        $qb...;
        return...;
    }
}

或者转向 Doctrine ORM