如果提供条件,则Doctrine为createQueryBuilder添加条件

时间:2016-03-27 17:29:59

标签: php symfony doctrine-orm query-builder

我有以下功能:

public function latestNews($tags = array(), $categories = array(), $authors = array(), $lang = 'en', $source = '', $limit = 20) {
    return $this->createQueryBuilder('News')
    ->field('tags')->in($tags)
    ->field('categories')->in($category)
    ->field('authors')->in($authors)
    ->field('lang')->equals($lang)
    ->sort('date' -> 'DESC')
    ->field('source')->equals($source)
    ->limit($limit)
    ->getQuery()
    ->execute();
}

我想如果函数调用者提供的变量$tags$categories$authors$source这些变量会影响createQueryBuilder,但如果每个变量都有效它们不是由函数调用者(具有默认值的变量)提供的,它们不会影响createQueryBuilder并使这个条件在查询中保持中立。 一种方法是我用许多if条件进行查询,但它非常混乱。 有没有更好的解决方案?

2 个答案:

答案 0 :(得分:3)

这样的事情可以解决问题:

public function latestNews($tags = array(), $categories = array(), authors = array(), $lang = 'en', $source = '', $limit = 20) {
    $inClauses = ['tags', 'categories', 'authors'];
    $equalClauses = ['lang', 'source'];
    $qb = $this->createQueryBuilder('News');

    foreach ($inClauses as $field) {
        $realVar = ${$field};

        if (!empty($realVar)) {
            $qb->field($field)->in($realVar);
        }
    }

    foreach ($equalClauses as $field) {
        $realVar = ${$field};

        if ($realVar) {
            $qb->field($field)->equals($realVar);
        }
    }

    return $qb
        ->sort('date' -> 'DESC')
        ->limit($limit)
        ->getQuery()
        ->execute();
}

有点难看,但我没有看到更好的选择。

答案 1 :(得分:1)

chalasr的反应很好,但我建议将构建条件的逻辑提取到特定的特征,这样就可以避免代码重复(DRY)。

您可以执行以下操作:

<?php

namespace Xthiago\My\Path;

use \Doctrine\DBAL\Query\QueryBuilder;

trait DoctrineQueryHelper
{
    public function in(QueryBuilder $qb, array $filter, $field)
    {
        if (empty($filter[$field])) {
            return $this;
        }

        $qb->field($field)->in($filter[$field]);

        return $this;
    }

    public function equals(QueryBuilder $qb, array $filter, $field)
    {
        if (empty($filter[$field])) {
            return $this;
        }

        $qb->field($field)->equals($filter[$field]);

        return $this;
    }

    public function lang(QueryBuilder $qb, $value = 'en')
    {
        $qb->field('lang')->equals($value);

        return $this;
    }

    public function limit(QueryBuilder $qb, $value = 20)
    {
        $qb->limit($value);

        return $this;
    }

    // you can create a lot of helper methods here in order to avoid duplicity.
}

然后你的班级以这种方式利用这个特性:

<?php

namespace Xthiago\My\Path;

use \Doctrine\DBAL\Query\QueryBuilder;

class NewsRepository
{
    use DoctrineQueryHelper;

    /**
     * @param array $filter as follow:
     * <code>
     * [
     *  'tags' => [],
     *  'categories' => [],
     *  'authors' => [],
     *  'lang' => 'en',
     *  'source' => '',
     *  'limit' => 20,
     * ]
     * </code>
     *
     * @return array with results.
     */
    public function latestNews(array $filter = []) 
    {
        $qb = $this->createQueryBuilder('News');

        $this->in($qb, $filter, 'tags')
             ->in($qb, $filter, 'categories')
             ->in($qb, $filter, 'authors')
             ->equals($qb, $filter, 'source')
             ->lang($qb, $filter)
             ->limit($qb, $filter);

        return $qb->sort('date', 'DESC')
                  ->getQuery()
                  ->execute();
    }
}