将两个简单的SQL查询转换为Doctrine

时间:2013-02-19 02:27:56

标签: php mysql doctrine-orm dql

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

我正在转换一个简单的应用程序,用于将我的技能从我自己的自定义数据库访问模式转换为Doctrine。我选择Doctrine有很多原因,其中最重要的原因是我经常在我的日常工作中使用它。我也喜欢Doctrine通常是一个非常薄(出现)的图层,它仍然可以保留不变的功能。

我已将数据库中users表的数据访问层转换为Doctrine。 除了一些细节之外,它是非常不起眼的(简单的吸气剂和制定者):

  • 我需要有一些特定查询的自定义存储库和
  • 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);
}

其中$this->db为精简PHP PDO wrapper$this->wrap does magic,返回零/单/多行并将其转换为data objects

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

我发现这些Stackoverflow问题曾经尝试构建我的查询,但是我在错误之后遇到错误,而且我不确定兔子洞需要走多远:

SQL Multiple sorting and grouping
Order by multiple columns with Doctrine
Doctrine: Multiple (whereIn OR whereIn) query?
Doctrine - or where?

我的自定义存储库目前看起来像这样,但我不能说它甚至接近正确,因为我一直在摆弄它很长一段时间,它只是我认为可能有用的一个大杂烩:< / p>

<?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 / Query Builder。

同样,我希望这两个SQL查询很容易转换为Doctrine / DQL。我想这样做而不需要通过Doctrine的原始SQL(我链接的许多已接受的答案建议)。这一定很容易。 有谁知道如何构建优雅的Doctrine查询?

2 个答案:

答案 0 :(得分: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推送自己的自定义函数:)

答案 1 :(得分:1)

除了@ Broncha上面的回答(通过添加嵌套CONCAT'CONCAT(u.fname, CONCAT(\' \', u.lname))'帮助解决错误),可以通过加入所需的实体来修复另一个函数,然后添加{{ 1}}关于连接的子句如下:

WHERE