You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Yii1转Yii2:CDbCriteria替代方案及代码迁移咨询

Yii 1 to Yii 2 Migration: CDbCriteria Replacement & Query Best Practices

Hey there! Let's walk through migrating your Yii 1 code to Yii 2, and answer your question about ActiveQuery vs Query.


1. Full Code Rewrite for Yii 2

First, let's fix up your code to fit Yii 2's conventions. Note that Yii 2 removes CDbCriteria and replaces it with ActiveQuery (for ActiveRecord-based queries) or the general Query class. Also, the model() method is no longer needed in Yii 2—we use static find() instead.

Assumptions

I'll assume your model class is named Logs (mapped to the logs table) and it extends yii\db\ActiveRecord.

Rewritten Code

<?php

namespace app\models;

use yii\db\ActiveRecord;
use yii\data\ActiveDataProvider;
use Yii;

class Logs extends ActiveRecord
{
    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'logs';
    }

    /**
     * Search method replacement for Yii 2
     * Replaces CDbCriteria with ActiveQuery
     */
    public function search()
    {
        // Initialize ActiveQuery tied to our Logs model
        $query = Logs::find();

        // Use andFilterWhere to mimic CDbCriteria->compare() behavior
        // It automatically skips empty values, just like compare()
        $query->andFilterWhere(['id' => $this->id])
            ->andFilterWhere(['like', 'hashkey', $this->hashkey])
            ->andFilterWhere(['like', 'ch', $this->ch])
            ->andFilterWhere(['like', 'cimi', $this->cimi])
            ->andFilterWhere(['like', 'dir', $this->dir])
            ->andFilterWhere(['like', 'ourl', $this->ourl])
            ->andFilterWhere(['like', 'imob', $this->imob])
            ->andFilterWhere(['like', 'tStart', $this->tStart])
            ->andFilterWhere(['like', 'tAnswer', $this->tAnswer])
            ->andFilterWhere(['like', 'tEnd', $this->tEnd])
            ->andFilterWhere(['like', 'state', $this->state])
            ->andFilterWhere(['like', 'omob', $this->omob])
            ->andFilterWhere(['like', 'date', $this->date]);

        // Return ActiveDataProvider with our query
        return new ActiveDataProvider([
            'query' => $query,
        ]);
    }

    /**
     * Get incoming calls (fixed Yii 2 DB access + added date filter support)
     */
    public function getInCalls($fromDate = false, $toDate = false)
    {
        $sql = "SELECT id, date as Date, ch as Channel, dir as Direction, ourl as Twinkle, imob as IncomingCall, state as State 
                FROM logs 
                WHERE tAnswer LIKE '%+%'";

        // Add date filter if parameters are provided
        if ($fromDate && $toDate) {
            $sql .= " AND date BETWEEN :fromDate AND :toDate";
        }

        $sql .= " GROUP BY date ORDER BY date DESC";

        $command = Yii::$app->db->createCommand($sql);

        // Bind parameters to prevent SQL injection
        if ($fromDate && $toDate) {
            $command->bindValues([
                ':fromDate' => $fromDate,
                ':toDate' => $toDate,
            ]);
        }

        return $command->queryAll();
    }

    /**
     * Get outgoing calls (fixed Yii 2 DB access + added date filter support)
     */
    public function getOutCalls($fromDate = false, $toDate = false)
    {
        $sql = "SELECT id, date as Date, ch as Channel, dir as Direction, ourl as Twinkle, state as State, omob as OutgoingCall 
                FROM logs 
                WHERE state LIKE 'Mobile%' AND (omob LIKE '07%' OR omob LIKE '+%')";

        if ($fromDate && $toDate) {
            $sql .= " AND date BETWEEN :fromDate AND :toDate";
        }

        $sql .= " GROUP BY date ORDER BY date DESC";

        $command = Yii::$app->db->createCommand($sql);

        if ($fromDate && $toDate) {
            $command->bindValues([
                ':fromDate' => $fromDate,
                ':toDate' => $toDate,
            ]);
        }

        return $command->queryAll();
    }

    /**
     * Get missed calls (fixed Yii 2 DB access + added date filter support)
     */
    public function getMissedCalls($fromDate = false, $toDate = false)
    {
        $sql = "SELECT id, date as Date, ch as Channel, state as State, imob as Missed, ourl as Agent 
                FROM logs 
                WHERE tEnd LIKE '%+%' AND imob IS NOT NULL AND state LIKE '%Lan%' AND tAnswer NOT LIKE '%+%' AND (imob LIKE '07%' OR imob LIKE '+%')";

        if ($fromDate && $toDate) {
            $sql .= " AND date BETWEEN :fromDate AND :toDate";
        }

        $sql .= " GROUP BY date ORDER BY date DESC";

        $command = Yii::$app->db->createCommand($sql);

        if ($fromDate && $toDate) {
            $command->bindValues([
                ':fromDate' => $fromDate,
                ':toDate' => $toDate,
            ]);
        }

        return $command->queryAll();
    }
}

Key Changes Explained

  • search() Method: Replaced CDbCriteria with ActiveQuery (via Logs::find()). andFilterWhere() acts exactly like CDbCriteria->compare()—it skips empty filter values automatically.
  • DB Access: Changed Yii::app()->db to Yii::$app->db (Yii 2's way of accessing application components).
  • Date Filters: Added support for your unused $fromDate/$toDate parameters with parameter binding to avoid SQL injection.
  • Removed model(): Yii 2 uses static Logs::find() instead of Logs::model().

2. ActiveQuery vs Query: Which is Better?

Let's break down the use cases for each:

ActiveQuery (Best for Your search() Method)

  • Tied to ActiveRecord: Returns Logs model instances instead of raw arrays. This means you can use model methods, validation, and associations directly on the results.
  • Built-in Convenience: Works seamlessly with ActiveDataProvider (used in GridViews/ListViews), and supports Yii 2's query builders for safe, readable conditions.
  • Ecosystem Integration: Leverages ActiveRecord features like attribute labels, events, and behaviors.

Query (Better for Raw Data Queries)

  • General-Purpose: A lower-level class that returns raw arrays/scalars. Great for complex queries that don't need to map to a model, or when you want maximum control over the result format.
  • Flexibility: Can be used for cross-table queries, aggregations, or cases where you don't need ActiveRecord overhead.

Recommendation for Your Code

  • Use ActiveQuery for the search() method—it's the standard approach in Yii 2 for filtering and displaying model data in UI components.
  • For your getInCalls()/getOutCalls()/getMissedCalls() methods:
    • If you just need raw array data (like you did in Yii 1), sticking with createCommand() (as I did above) or using Query is fine.
    • If you want to work with Logs model instances instead of arrays, you could rewrite these methods to use ActiveQuery (e.g., Logs::find()->select(...)->where(...)).

内容的提问来源于stack exchange,提问作者xbile

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:44:07