0

首先,我想为这个问题的长度道歉;如果没有很多背景,我不知道如何正确地提出我的问题。请多多包涵。

我正在将一个用于磨练我的技能的简单应用程序从我自己的自定义数据库访问模式转换为 Doctrine。我选择 Doctrine 有很多原因,其中最重要的是我在日常工作中经常使用它。我也喜欢 Doctrine 通常是一个非常薄(出现)的层,它既不碍事,又增加了很多功能。

我已将users数据库中表的数据访问层转换为 Doctrine。它非常不起眼(只是 getter 和 setter),除了一些细节:

  • 我需要有一个自定义存储库来处理一些特定的查询和
  • User对象在构造函数中有一个默认ArrayCollection实例化

namespace model\entities;

/**
 * @Entity(repositoryClass="model\repositories\UserRepository")
 * @Table(name="users")
 */
class User{
    /* snip variables */

    /**
     * @OneToOne(targetEntity="Authentication", mappedBy="user", cascade="persist")
     */
    private $authentication;

    /**
     * @OneToMany(targetEntity="Contact", mappedBy="user", cascade="persist")
     */
    private $contacts;

    public function __construct() {
        $this->contacts = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /* snip getters and setters */  
}

在我的旧模式中,我有两个自定义查询选择了users表的一个子集。

他们是:

public function search( $term = null ){
    if( !$term ){
        $sql = "SELECT *
                FROM
                " . $this->tableName . "
                ORDER BY
                    lname ASC,
                    fname ASC";
        $res = $this->db->q($sql);
    }
    else{
        $sql = "SELECT *
                FROM
                " . $this->tableName . "
                WHERE
                    lname LIKE ?
                    OR fname LIKE ?
                    OR CONCAT(fname, ' ', lname) LIKE ?
                ORDER BY
                    lname ASC,
                    fname ASC";
        $values = array( '%' . $term . '%', '%' . $term . '%', '%' . $term . '%' );
        $res = $this->db->qwv( $sql, $values );
    }

    return $this->wrap( $res );
}

和:

public function getAllWithRestrictions(){
    $sql = "SELECT *
            FROM
            " . $this->tableName . "
            WHERE
                userid IN
                (
                    SELECT
                        userid
                    FROM
                        " . $this->uiPre . "authentications
                    WHERE
                        resetPassword = 1
                        OR disabled = 1
                )";
    $res = $this->db->q( $sql );

    return $this->wrap($res);
}

where$this->db是一个瘦PHP PDO 包装器$this->wrap通过返回零/单/多行并将它们转换为数据对象来发挥作用。

现在,我认为这很容易转换为 Doctrine。如果getAllWithRestrictions它只是一个->where,->orWhere集,对吧?我不知道了。

我发现了这些 Stackoverflow 问题,我曾经尝试构建我的查询,但我一个接一个地遇到错误,我不确定我需要走多远的兔子洞:

SQL 多重排序和分组
使用 Doctrine Doctrine 按多列排序
:多重(whereIn OR whereIn)查询?
教义——还是在哪里?

我的自定义存储库目前看起来像这样,但我不能说它甚至接近正确,因为我已经摆弄了很长时间,而且它只是我认为可能有用的大杂烩:

<?php
namespace model\repositories;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr;

class UserRepository extends EntityRepository{
    public function search( $term ){
        if( !$term ){
            return $this
                    ->_em
                    ->createQuery('SELECT u FROM model\entities\User u')
                    ->addOrderBy( 'u.lname' )
                    ->addOrderBy( 'u.fname' )
                    ->getResult();
        }
        else{
            $qb     = $this->_em->createQueryBuilder();

            $qb ->select(array('u'))
                ->from('model\entities\User', 'u')
                ->where( $qb->expr()->like( 'u.lname', '?1' ) )
                ->orWhere( $qb->expr()->like( 'u.fname', '?2' ) )
                ->orWhere( $qb->expr()->like( 'CONCAT(u.fname, \' \', u.lname)', '?3' ) )
                ->addOrderBy( 'u.lname' )
                ->addOrderBy( 'u.fname' )
                ->setParameters(
                    array(
                        1 => $term,
                        2 => $term,
                        3 => $term
                    )
                );

            $query = $qb->getQuery();
            return $query->getResult();
        }
    }

    public function getAllWithRestrictions(){
        $qb     = $this->_em->createQueryBuilder();

        $qb ->select(array('u'))
            ->from('model\entities\User', 'u')
            ->add('where', $qb->expr()->orx(
               $qb->expr()->eq('u.disabled', '1'),
               $qb->expr()->eq('u.resetPassword', '1')
           ));

        $query = $qb->getQuery();
        return $query->getResult();
    }
} 

编辑:我刚刚意识到我正在getAllWithRestrictions对错误的表进行查询(应该是authentications。)无论如何,这是导致我现在出现问题的搜索方法。但是,我还需要知道如何做类似的事情$qb->expr()->eq('u.Authentication.disabled = '1'),但我不知道 DQL 是如何工作的。

我现在遇到的特定错误是

  • Fatal error: Uncaught exception 'Doctrine\ORM\Query\QueryException' with message 'SELECT u FROM model\entities\User u WHERE u.lname LIKE ?1 OR u.fname LIKE ?2 OR CONCAT(u.fname, ' ', u.lname) LIKE ?3 ORDER BY u.lname ASC, u.fname ASC'

其次是

  • Doctrine\ORM\Query\QueryException: [Syntax Error] line 0, col 99: Error: Expected Doctrine\ORM\Query\Lexer::T_CLOSE_PARENTHESIS, got ','

但是根据我构建 DQL/查询生成器的方式,我遇到了许多不同的问题。

同样,我希望这两个 SQL 查询能够简单地转换为 Doctrine / DQL。我想在不通过 Doctrine 诉诸原始 SQL 的情况下做到这一点(正如我链接的许多已接受的答案所建议的那样)。这一定很容易。 有谁知道如何构建优雅的 Doctrine 查询?

4

2 回答 2

1

根据CONCAT学说中的函数解析器,它只需要用逗号分隔的2个参数,

//Doctrine/ORM/Query/AST/Functions/ConcatFunction.php
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);

$this->firstStringPrimary = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$this->secondStringPrimary = $parser->StringPrimary();

$parser->match(Lexer::T_CLOSE_PARENTHESIS);

所以这

->orWhere( $qb->expr()->like( 'CONCAT(u.fname, \' \', u.lname)', '?3' ) )

应该

->orWhere( $qb->expr()->like( 'CONCAT(u.fname, u.lname)', '?3' ) )

这不会引发任何错误,但可能不是您真正需要的。在这种情况下,您将不得不为CONCAT:)滚动您自己的自定义函数

于 2013-02-19T03:53:44.330 回答
1

除了上面@Broncha 的答案(通过添加嵌套的CONCATlike来帮助解决错误'CONCAT(u.fname, CONCAT(\' \', u.lname))')之外,其他功能可以通过加入所需的实体来修复,然后WHERE在加入上添加子句,如下所示:

$qb ->select(array('u'))
    ->from('model\entities\User', 'u')
    ->leftJoin('u.authentication', 'a')
    ->add('where', $qb->expr()->orx(
        $qb->expr()->eq('a.disabled', '1'),
        $qb->expr()->eq('a.resetPassword', '1')
    ));
于 2013-02-20T01:21:24.217 回答