如何在yii2 joinWith()中使用WHERE进行预先加载

时间:2016-04-07 09:18:05

标签: activerecord yii yii2 cactivedataprovider

我有表格:documentdocument_contentOne文档可以包含many个内容。

我使用joinWith()方法使用模型关系从document_content表和document获取数据。

执行的查询是:

SELECT document.* FROM document INNER JOIN document_content ON document.id = document_content.document_id WHERE (lang='1') ORDER BY id DESC LIMIT 10

SELECT * FROM document_content WHERE document_id IN (665566, 665034, 664961, 664918, 664910, 664898, 664896, 664893, 664882, 664880)

我的第二个查询有问题。我希望它包含第一个WHERE子句:WHERE (lang='1')

所以我希望yii生成这个查询:

SELECT * FROM document_content WHERE (lang='1') AND document_id IN (665566, 665034, 664961, 664918, 664910, 664898, 664896, 664893, 664882, 664880)

我已经设法以某种方式实现了这一点,但我有代码重复,我不喜欢它。必须有一些更好的方法来做到这一点。这是我的代码有效,但我认为它不是那么好:

/**
 * Returns documents by params.
 * 
 * @param  array $params the query params.
 * @return ActiveDataProvider
 */
public function findDocuments($params)
{
    /** @var $query ActiveQuery */
    $query = Document::find();

    // store params to use in other class methods.
    self::$_params = $params;

    // build dynamic conditions for document table
    $this->buildDocumentQuery($query);

    // build dynamic conditions for document_content table
    $this->buildDocumentContentQuery($query);

    // add conditions that should always apply here
    $dataProvider = new ActiveDataProvider([
        'query' => $query,
        'sort'  => ['defaultOrder' => ['id' => SORT_DESC]],
        'pagination' => [
            'pageSize' => 10,
        ],
    ]);

    return $dataProvider;
}

/**
 * Relation with document_content table.
 * 
 * @return DocumentContent
 */
public function getDocumentContent()
{
    $query = $this->hasMany(DocumentContent::className(), ['document_id' => 'id']);

    if (isset(self::$_params['lang'])) {
        $query->andFilterWhere([
            'lang' => self::$_params['lang'],
        ]);
    }
}

/**
 * Method that is responsible for building query conditions for document_content table.
 * 
 * @param  object $query ActiveQuery instance.
 * @return ActiveQuery
 */
public function buildDocumentContentQuery($query)
{
    if (isset(self::$_params['lang'])) {
        $query->innerJoinWith('documentContent');
    }

    return $query;
}

正如您所看到的,我正在两个地方检查params['lang']。在我的关系方法和buildDocumentContentQuery()方法中。所以我在两个地方重复相同的代码,并且lang param不会是我想要测试的唯一一个,可能有10个或更多。

基本上,我必须做所有这些,因为我无法通过yii2 joinWith()方法发送任何参数。我不知道将WHERE添加到由joinWith()的急切加载生成的查询的最佳方法是什么。我以某种方式使它工作,但我认为这很脏。

有没有人想要更好/更清洁地解决这个问题?

2 个答案:

答案 0 :(得分:0)

型号#文献

public function getDocuments($params)
{
    /** @var $query ActiveQuery */
    $query = Document::find();
    $query->getDocumentContentsByLanguage($params['lang']);
}

public function getDocumentContentsByLanguage($lang = null)
{
    return $this->hasMany(DocumentContent::className(), ['document_id' => 'id'])->where('lang = :lang', [':lang'=>$lang]);
}

答案 1 :(得分:0)

试试这个:

$query = $this
   ->hasMany(DocumentContent::className(), ['document_id' => 'id']);

if (isset(self::$_params['lang']) && self::$_params['lang']==1) {
    $query
       ->joinWith('document')
       ->andWhere([
           Document::tablename().'.lang' => self::$_params['lang']
       ]);
}