/ yii2

yii2-ar

Active Record (活动记录,以下简称 AR)提供了一个面向对象的接口, 用以访问和操作数据库中的数据。一个 AR 类关联一张数据表, 每个 AR 对象对应表中的一行,对象的属性(即 AR 的特性Attribute)映射到数据行的对应列。 即一条活动记录(AR 对象)对应数据表的一行,AR 对象的属性则映射该行的相应列。 您可以直接以面向对象的方式来操纵数据表中的数据,

例如,假定 Customer AR 类关联着 customer 表, 且该类的 name 属性代表 customer 表的 name 列。 你可以写以下代码来哉 customer 表里插入一行新的记录:

$customer = new Customer();
$customer->name = 'Qiang';
$customer->save();

对于 MySql,上面的代码和使用下面的原生 SQL 语句是等效的,但显然前者更直观, 更不易出错,并且面对不同的数据库系统(DBMS, Database Management System)时更不容易产生兼容性问题。

$db->createCommand('INSERT INTO `customer` (`name`) VALUES (:name)', [
    ':name' => 'Qiang',
])->execute();

查询数据

定义 ActiveRecord 类后,你可以从相应的数据库表中查询数据。 查询过程大致如下 3 个步骤:

  1. 通过 yii\db\ActiveRecord::find() 方法创建一个新的 query object;
  2. Build the query object by calling query building methods;
  3. Call a query method to retrieve data in terms of Active Record instances.
// 返回 ID 为 123 的客户:
// SELECT * FROM `customer` WHERE `id` = 123
$customer = Customer::find()
    ->where(['id' => 123])
    ->one();

// 取回所有活跃客户并以他们的 ID 排序:
// SELECT * FROM `customer` WHERE `status` = 1 ORDER BY `id`
$customers = Customer::find()
    ->where(['status' => Customer::STATUS_ACTIVE])
    ->orderBy('id')
    ->all();

// 取回活跃客户的数量:
// SELECT COUNT(*) FROM `customer` WHERE `status` = 1
$count = Customer::find()
    ->where(['status' => Customer::STATUS_ACTIVE])
    ->count();

// 以客户 ID 索引结果集:
// SELECT * FROM `customer`
$customers = Customer::find()
    ->indexBy('id')
    ->all();

只获取特定字段 Customer::find()->select(['id','name'])->where()->all();

默认属性值

某些表列可能在数据库中定义了默认值。有时,你可能想预先填充具有这些默认值的 AR 实例的 Web 表单。 为了避免再次写入相同的默认值, 您可以调用 loadDefaultValues() 来填充 DB 定义的默认值 进入相应的 AR 属性:

$customer = new Customer();
$customer->loadDefaultValues();
// $customer->xyz 将被 “zyz” 列定义的默认值赋值

批量赋值

$values = [
    'name' => 'James',
    'email' => 'james@example.com',
];

$customer = new Customer();

$customer->attributes = $values;
$customer->save();

属性类型转换

在查询结果填充 yii\db\ActiveRecord 活动记录时,将自动对其属性值执行类型转换,基于数据库表模式中的信息。这允许从数据表中获取数据, 声明为整型的,使用 PHP 整型(integer)填充 AR 实例,布尔值(boolean)的也用布尔值填充 AR 实例,等等。

但是,类型转换机制有几个限制:

  • float 值不被转换,并且将被表示为字符串,否则它们可能会使精度降低。
  • integer 值的转换取决于您使用的操作系统的整数容量。尤其是: 声明为“无符号整型”或“大整型”的列的值将仅转换为 64 位操作系统的 PHP 整型, 而在 32 位操作系统中 - 它们将被表示为字符串。

值得注意的是,只有在从查询结果填充 ActiveRecord 实例时才执行属性类型转换。而从 HTTP 请求加载的值 or set directly via property access,都不会自动转换。

在为ActiveRecord数据保存准备SQL语句时,也将使用表模式,确保值以正确的类型绑定到查询。 但是,在保存过程中,ActiveRecord实例属性值不会被转换。

保存关联关系

$customer = Customer::findOne(123);
$order = new Order();
$order->subtotal = 100;
// ...

// 为 Order 设置属性以定义与 "customer" 的关联关系
$order->customer_id = $customer->id;
$order->save();

AR 提供了 link() 方法,可以更好地完成此任务:

$customer = Customer::findOne(123);
$order = new Order();
$order->subtotal = 100;
// ...

// 等同于 $order->customer_id = $customer->id;
$order->link('customer', $customer);
$customer->orders; // 获得 `Order` 对象的数组
$customer->getOrders(); // 返回 ActiveQuery 类的实例

// 动态关联查询(Dynamic Relational Query)
// 由于关联方法返回 yii\db\ActiveQuery 的实例,因此你可以在执行 DB 查询之前, 使用查询构建方法进一步构建此查询。例如,
$customer = Customer::findOne(123);

// SELECT * FROM `order` WHERE `customer_id` = 123 AND `subtotal` > 200 ORDER BY `id`
$orders = $customer->getOrders()
    ->where(['>', 'subtotal', 200])
    ->orderBy('id')
    ->all();

数据转换

class Customer extends ActiveRecord
{
    // ...

    public function getBirthdayText()
    {
        return date('Y/m/d', $this->birthday);
    }
    
    public function setBirthdayText($value)
    {
        $this->birthday = strtotime($value);
    }
}

Now in your PHP code, instead of accessing $customer->birthday, you would access $customer->birthdayText, which will allow you to input and display customer birthdays in the format of 'YYYY/MM/DD'.

Dirty Attribute

$model->getDirtyAttributes());