yii2 之 ActiveRecord 模型

      Active Record 模型是一种设计模式,用面向对象的方式抽象地访问数据的模式。在 Yii2 中,每一个 Active Record 模型对象的实例是 yii\db\ActiveRecord 类或它的子类,它封装了数据库表或视图中的一行记录,并封装了所有逻辑和访问数据库的细节,如果有大部分的业务逻辑,很适合使用这种模式。

1. ActiveRecord 模型概述

       在大多数企业级开发中,都需要用到面向对象方法和关系型数据库。在软件的业务逻辑层和用户界面层,都需要操作对象,而在操作对象后,需要把对象的信息存储至数据库中。因此,在 MVC 模式下开放一个应用程序时,程序员要写很多数据访问层的代码,用来执行增删改查。通常情况下,这些数据访问层的代码基本上都是先传入操作对象,然后设置存储过程,再设置对象与属性对应,最后执行存储过程。这些具有相同模式的代码,在每个软件项目都重复出现,这显然是一种资源的浪费,由此,可以使用 ActiveRecord 模型解决这些问题。

       ActiveRecord (AR)模型是一种流行的对象——关系映射技术。对象——关系映射(Object Relational Mapping,ORM)是一种为解决面向对象与关系型数据库存在的互不匹配现象的技术。ORM 在关系型数据库和对象之间产生一个自动映射,这样在具体的数据库操作中就不需要再与复杂的 SQL 语句打交道。软件设计人员只需要关注业务逻辑中的对象架构,而不是底层重复性的数据库 SQL 语句。

下面是一个 user 表的模型类

<?php
namespace common\models;

use Yii;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;

/**
 * User model
 *
 * @property integer $id
 * @property string $username
 * @property string $password_hash
 * @property string $password_reset_token
 * @property string $email
 * @property string $auth_key
 * @property integer $status
 * @property integer $created_at
 * @property integer $updated_at
 * @property string $password write-only password
 */
class User extends ActiveRecord implements IdentityInterface
{

    /**
     * {@inheritdoc}
     */
    public static function tableName()
    {
        return '{{%user}}';
    }

    /**
     * {@inheritdoc}
     */
    public function behaviors()
    {
        return [
            TimestampBehavior::className(),
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function rules()
    {
        return [
            ['status', 'default', 'value' => self::STATUS_ACTIVE],
            ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
        ];
    }

}

演示下 AR 的新增操作吧

$user = new User(); // 实例化 user 表对应的 ActiveRecord 模型类
$user->username = '小牛'; // 给表中的 username 字段赋值
$user->email = '18810980488@163.com'; // 给表中的 email 字段赋值
$user->save(); // 执行 insert into 语句完成一次插入记录的操作

上面的代码相当于执行了下面的 SQL 语句。

insert into user('username','email') value('小牛','18810980499@163.com');

ActiveRecord 的优点是简单、直观,一个类就包括了数据访问和业务逻辑。减少了软件开发时间和成本,极大的提高了数据的可读性,也简化了代码的调优和测试。

2. 通过查询操作理解 ActiveRecord 类

静态方法 find() 返回了 ActiveRecord 类的静态实例对象,从而可以调用其他的方法,查询实例。

我们打印了一个 one() 方法查询返回的信息,如下:

api\models\UserRole Object
(
    [_attributes:yii\db\BaseActiveRecord:private] => Array
        (
            [role_id] => 1
            [role_name] => 超级管理员
            [role_desc] => 超级管理员
            [role_sort] => 10
            [created_at] => 2019-06-17 15:10:21
            [delete_flg] => 0
            [updated_uid] => 1
            [updated_at] => 2019-06-19 18:12:40
        )

    [_oldAttributes:yii\db\BaseActiveRecord:private] => Array
        (
            [role_id] => 1
            [role_name] => 超级管理员
            [role_desc] => 超级管理员
            [role_sort] => 10
            [created_at] => 2019-06-17 15:10:21
            [delete_flg] => 0
            [updated_uid] => 1
            [updated_at] => 2019-06-19 18:12:40
        )

    [_related:yii\db\BaseActiveRecord:private] => Array
        (
        )

    [_relationsDependencies:yii\db\BaseActiveRecord:private] => Array
        (
        )

    [_errors:yii\base\Model:private] => 
    [_validators:yii\base\Model:private] => 
    [_scenario:yii\base\Model:private] => default
    [_events:yii\base\Component:private] => Array
        (
        )

    [_eventWildcards:yii\base\Component:private] => Array
        (
        )

    [_behaviors:yii\base\Component:private] => Array
        (
        )

)

one()方法找到了一个满足查询条件的行,返回一个实例对象,实例的属性含有数据表行中相应列的值。然后,就可以像读取普通对象的属性那样读取查询结构

$role->role_name; // 输出 “超级管理员”

如果是传统的面向对象语言,如 C++ 或 Java,这里就会报编译错误,因为类没有定义“role_name”成员属性。而对于 PHP 而言,语言有着对动态特性(魔术方法)的支持,当写入【读取】对象属性不存在时,会触发 ActiveRecord 中定义的 set()【get()】 方法,这样的调用就没有任何问题。

3. 通过插入和更新操作理解 ActiveRecord 类

同样使用 save() 方法执行插入和更新操作。如果实例对象是 new 操作符创建的,调用 save() 方法会新增一条数据,而实例对象是 find() 方法的结果,那么调用 save() 将更新表中现有的行。

查看在 vendor\yiisoft\yii2\db\BaseActiveRecord.php 文件中的代码

    /*
     * 保存当前的记录
     * 插入记录到数据表的一行,如果它的 isNewRecord 属性为 true(通常情况下使用 new 运算符来创建记录),
     * 否则,将被用于更新表中的相应行(通常情况下使用 find 方法查找记录
     */
  public function save($runValidation = true, $attributeNames = null)
  {
      if ($this->getIsNewRecord()) {
          return $this->insert($runValidation, $attributeNames);
      }

      return $this->update($runValidation, $attributeNames) !== false;
  }

如上代码所示,通过判断 $this->getIsNewRecord() 方法的返回值,判断执行不同的操作。

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!