# 活动记录

活动记录定义了一个抽象类,该抽象类继承于模型类,类中定义了一些与数据库表交互的接口方法。你可以定义一个与数据表对应的类继承活动记录类,从而通过读写类实例来操作数据表记录。

# \dce\db\active\ActiveRecord;

活动记录抽象类

定义数据表实体类(后续示例若无特殊说明,则表示已此类为基础模型类)

namespace tests\model;

use dce\db\active\DbActiveRecord;
use dce\db\entity\DbField;
use dce\db\entity\schema\FieldType;
use dce\model\Property;
use dce\model\Validator;

/**
 * Class Member
 * @package tests\model
 * @property MemberGroup $group
 * @property MemberTag[] $memberTags
 * @property Tag[] $tags
 */
class Member extends DbActiveRecord {
    public const SCENARIO_REGISTER = 'register';

    #[ Property('用户ID'), DbField(FieldType::BIGINT, primary: true, increment: true), ]
    public int $mid;

    #[ Property('分组ID'), DbField(FieldType::TINYINT), Validator(Validator::RULE_INTEGER), ]
    public int $groupId;

    #[ Property('用户名'), DbField(FieldType::VARCHAR, 16),
        Validator(Validator::RULE_STRING, [self::SCENARIO_DEFAULT, self::SCENARIO_REGISTER], max: 16, min: 3),
        Validator(Validator::RULE_REQUIRED, self::SCENARIO_REGISTER), 
    ]
    public string $username;

    #[ Property('密码'), DbField(FieldType::VARCHAR, 128), ]
    public string $password;

    #[ Property('注册时间'), DbField(FieldType::DATETIME), Validator(Validator::RULE_DATETIME), ]
    public string $registerTime;

    public function getGroup() {
        return $this->hasOne(MemberGroup::class, ['id' => 'group_id']);
    }

    public function getMemberTags() {
        return $this->hasMany(MemberTag::class, ['mid' => 'mid']);
    }

    public function getTags() {
        return $this->hasMany(Tag::class, ['id' => 'tag_id'], 'memberTags');
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
namespace tests\model;

use dce\db\active\DbActiveRecord;
use dce\db\entity\DbField;
use dce\db\entity\schema\FieldType;
use dce\model\Property;
use dce\model\Validator;

class MemberBadge extends DbActiveRecord {
    #[ Property, DbField(FieldType::TINYINT, primary: true, increment: true), ]
    public int $id;

    #[ Property('徽章名'), DbField(FieldType::VARCHAR, 15),
        Validator(Validator::RULE_STRING, max: 15),
        Validator(Validator::RULE_REQUIRED),
    ]
    public string $name;

    #[ Property('备注'), DbField(FieldType::VARCHAR), Validator(Validator::RULE_STRING, max: 31), ]
    public string $memo;

    #[ Property('添加时间'), DbField(FieldType::DATETIME), Validator(Validator::RULE_DATETIME), ]
    public string $createTime;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

警告

请不要对字段型类属性设置默认值,这将可能导致利用活动记录更新数据库时,真实业务数据被更新为此默认值。如果需要插入时自动补充默认值,请使用默认值赋值器实现。

# ->getPkValues()

取主键值集

  • 返回int[]|string[]

  • 示例

$member = Member::find(410011121441111);
test($member->getPkValues());
/*
1-1    array(1) {
         ["mid"] => int(410011121441111)
       }
*/
1
2
3
4
5
6
7

# ->setQueriedProperties()

初始化查询结果活动记录实例(对新实例属性赋值)

  • 参数

    • array $properties 模型属性键值表
  • 返回void

# ->isCreateByQuery()

判断当前实例是否查询结果实例

  • 返回bool

  • 示例

$member = Member::find(410011121441111);
$member2 = new Member();
test(
    $member->isCreateByQuery(),
    $member2->isCreateByQuery(),
);
/*
1-1    bool(true)
1-2    bool(false)
 */
1
2
3
4
5
6
7
8
9
10

# ->save()

保存数据(插入或更新数据库)

  • 返回int|string

    • 插入 新插入记录的ID
    • 更新 改变的记录数
  • 示例

$memberBadge = new MemberBadge();
$memberBadge->name = 'VIP3';
$memberBadge->memo = 'VIP3等级的贵宾';
$memberBadge->createTime = date('Y-m-d H:i:s');
test($memberBadge->save());
// 1-1    string(1) "4"
1
2
3
4
5
6

# ->delete()

删除数据库记录

  • 返回int 影响的记录数

  • 示例

$memberBadge = MemberBadge::find(4);
test($memberBadge->delete());
// 1-1    int(1)
1
2
3

# ->hasOne()

构建一对一关联数据查询器

  • 参数

    • string $className 关联表模型类名
    • array $relationMap 与关联表的关系字段映射表
    • string|null $viaRelationName = null 中间关联关系名
  • 返回\dce\db\active\ActiveRelation

  • 示例







 





















// 主体类
class Member extends DbActiveRecord {
    // ...

    // 定义获取关联数据的方法
    public function getLogin() {
        return $this->hasOne(MemberLogin::class, ['mid' => 'mid']);
    }
}

// 惰性获取关联数据
$member = Member::find(410011121441111);
test(
    $member->login->extractProperties(),
);
/*
1-1    array(8) {
         ["id"] => int(1000)
         ["mid"] => int(410011121441111)
         ["type"] => int(1)
         ["terminal"] => int(1)
         ["login_date"] => string(10) "2021-01-27"
         ["last_login_date"] => string(10) "1970-01-01"
         ["is_silent"] => int(0)
         ["create_time"] => string(19) "2021-01-27 19:08:00"
       }
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# ->hasMany()

构建一对多关联数据查询器

  • 参数

    • string $className 关联表模型类名
    • array $relationMap 与关联表的关系字段映射表
    • string|null $viaRelationName = null 中间关联关系名
  • 返回\dce\db\active\ActiveRelation

  • 示例







 



 































// 主体类
class Member extends DbActiveRecord {
    // ...

    // 定义获取关联数据的方法
    public function getBadgeMap() {
        return $this->hasMany(MemberBadgeMap::class, ['mid' => 'mid']);
    }

    public function getBadge() {
        return $this->hasMany(MemberBadge::class, ['id' => 'mb_id'], 'badgeMap');
    }
}

// 惰性获取关联数据
$member = Member::find(410011121441111);
foreach ($member->badge as $badge) {
    testPoint($badge->extractProperties());
}
/*
1-1    array(4) {
         ["id"] => int(1)
         ["name"] => string(4) "VIP1"
         ["memo"] => string(19) "VIP1等级的贵宾"
         ["create_time"] => string(19) "2021-01-27 19:09:39"
       }

2-1    array(4) {
         ["id"] => int(2)
         ["name"] => string(4) "VIP2"
         ["memo"] => string(19) "VIP2等级的贵宾"
         ["create_time"] => string(19) "2021-01-27 19:09:45"
       }

3-1    array(4) {
         ["id"] => int(3)
         ["name"] => string(4) "VIP3"
         ["memo"] => string(19) "VIP3等级的贵宾"
         ["create_time"] => string(19) "2021-01-27 19:09:51"
       }
 */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

# ->begin()

开启事务

  • 返回\dce\db\proxy\Transaction

  • 示例

$memberBadge = new MemberBadge();
$memberBadge->name = 'VIP3';
$memberBadge->memo = 'VIP3等级的贵宾';
$memberBadge->createTime = date('Y-m-d H:i:s');
$transaction = $memberBadge::begin();
if ($insertId = $memberBadge->save()) {
    $transaction->commit();
} else {
    $transaction->rollback();
}
test($insertId);
// 1-1    string(1) "5"
1
2
3
4
5
6
7
8
9
10
11
12

# ::getTableName()

取表名(子类可覆盖指定表名)

  • 返回string

  • 示例

test(Member::getTableName());
// 1-1    string(6) "member"
1
2

# ::query();

取新的活动记录查询器实例

  • 返回\dce\db\active\ActiveQuery

  • 示例

$query = Member::query();
1

# ->insert();

向数据库插入数据

  • 参数

    • bool $needLoadNew = false 是否将已插入记录载入到当前对象
    • bool|null $ignoreOrReplace = null
  • 返回int|string

  • 示例

$member->insert();
1

# ->update();

将当前对象更新到数据库

  • 参数

    • array $columns = [] 指定需更新的属性字段而不更新全部
  • 返回int

  • 示例

$member->update();
1

# \dce\db\active\DbActiveRecord;

数据表活动记录抽象类

# ->fieldClass

string 字段类名,用于实现注解字段

# ->find()

筛选一条数据库数据,转为活动记录对象并返回

  • 参数

    • int|string|array|RawBuilder|WhereSchema $whereCondition 查询条件,同\dce\db\Query::where(columnName)
  • 返回static|false

  • 示例

$memberBadge = MemberBadge::find(1);
test($memberBadge->id, $memberBadge->extractProperties());
/*
1-1    int(1)
1-2    array(4) {
         ["id"] => int(1)
         ["name"] => string(4) "VIP1"
         ["memo"] => string(19) "VIP1等级的贵宾"
         ["create_time"] => string(19) "2021-01-27 19:09:39"
       }
*/
1
2
3
4
5
6
7
8
9
10
11

# ->insert()

向数据库插入数据

# ->update()

将当前对象更新到数据库

# ->updateCounter()

计数器更新

  • 参数

    • string|array $fieldName
    • int|float $increment = 1
  • 返回int

  • 示例

$memberBadge = MemberBadge::find(5);
test($memberBadge->updateCounter('id'), MemberBadge::find(6)->id);
/*
1-1    int(1)
1-2    int(6)
 */
1
2
3
4
5
6

# ::getProxy()

指定目标库或设定查询代理器(活动记录类默认使用默认代理查询默认库,你可以在实体类中定义覆盖此方法用指定代理器查询指定库)

  • 返回string|DbProxy|null

  • 示例




 
 
 
 





class Member extends DbActiveRecord {
    // ...

    public static function getProxy() {
        // 指定查询别名为db2的库
        return 'db2',
    }
}

// 此时将向别名为db2的库发起查询而不是default库
$member = Member::find(1);
1
2
3
4
5
6
7
8
9
10
11

# ::query()

取新的活动记录查询器实例

  • 返回\dce\db\active\DbActiveQuery

  • 示例

$query = MemberBadge::query();
$list = $query->arrayify()->select();
test($list);
/*
1-1    array(4) {
         [0] => array(4) {
           ["id"] => int(1)
           ["name"] => string(4) "VIP1"
           ["memo"] => string(19) "VIP1等级的贵宾"
           ["create_time"] => string(19) "2021-01-27 19:09:39"
         }
         [1] => array(4) {
           ["id"] => int(2)
           ["name"] => string(4) "VIP2"
           ["memo"] => string(19) "VIP2等级的贵宾"
           ["create_time"] => string(19) "2021-01-27 19:09:45"
         }
         [2] => array(4) {
           ["id"] => int(3)
           ["name"] => string(4) "VIP3"
           ["memo"] => string(19) "VIP3等级的贵宾"
           ["create_time"] => string(19) "2021-01-27 19:09:51"
         }
 */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# ::getPks()

取数据表主键集

  • 返回Field[]

# ::getPkNames()

取数据表主键名集

  • 返回string[]

  • 示例

$pks = MemberBadge::getPks();
test($pks);
/*
1-1    array(1) {
         [0] => string(2) "id"
       }
 */
1
2
3
4
5
6
7

# \dce\db\active\ActiveQuery;

活动记录查询器

# ->with()

设置即时加载关联数据

查询列表时可能也需要取其关联数据,若通过遍历惰性的取关联数据,则会多次发起查询请求,造成资源浪费,通过with方法设置需取的关系后,会在select时一次性将所有关系数据查询出来,减少查询请求从而提高性能

  • 参数

    • string ... $relationNames 需即时加载的关系集
  • 返回static

  • 示例

$members = Member::query()->with('login')->select();
$logins = array_column($members, 'login');
test($logins);
/* 可以看到一次性将关联的login数据全部查了出来
1-1    array(3) {
         [0] => object(tests\model\MemberLogin)#95 (13) {
           ["id"] => int(1000)
           ["mid"] => int(410011121441111)
           ["type"] => int(1)
           ["terminal"] => int(1)
           ["loginDate"] => string(10) "2021-01-27"
           ["lastLoginDate"] => string(10) "1970-01-01"
           ["isSilent"] => int(0)
           ["createTime"] => string(19) "2021-01-27 19:08:00"
           ["createByQuery":"dce\db\active\ActiveRecord":private] => bool(true)
           ["originalProperties":"dce\db\active\ActiveRecord":private] => array(8) {
             ["id"] => int(1000)
             ["mid"] => int(410011121441111)
             ["type"] => int(1)
             ["terminal"] => int(1)
             ["login_date"] => string(10) "2021-01-27"
             ["last_login_date"] => string(10) "1970-01-01"
             ["is_silent"] => int(0)
             ["create_time"] => string(19) "2021-01-27 19:08:00"
           }
           ["activeQuery":protected] => NULL
           ["getterValues":"dce\model\Model":private] => array(0) {
           }
           ["scenario":"dce\model\Model":private] => string(7) "default"
         }
         [1] => NULL
         [2] => NULL
       }
 */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

WARNING

注意,通过此方式查询数据时,会一次性将所有关联数据全部查出,所以如果关联数据量比较大,则不适合此即时查询,这种情况下通过遍历惰性限量查询性能更佳。








 























// 主体类
class Member extends DbActiveRecord {
    // ...

    // 定义获取关联数据的方法
    public function getLogin() {
        $relation = $this->hasOne(MemberLogin::class, ['mid' => 'mid']);
        $relation->getActiveQuery()->limit(1); // 限量查询
        return $relation;
    }
}

$members = Member::query()->select();
foreach ($members as $member) {
    if ($member->login) {
        testPoint($member->login->extractProperties());
    }
}
/*
1-1    array(8) {
         ["id"] => int(1000)
         ["mid"] => int(410011121441111)
         ["type"] => int(1)
         ["terminal"] => int(1)
         ["login_date"] => string(10) "2021-01-27"
         ["last_login_date"] => string(10) "1970-01-01"
         ["is_silent"] => int(0)
         ["create_time"] => string(19) "2021-01-27 19:08:00"
       }
 */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# ->arrayify()

设置按数组返回查询结果而非活动记录对象

  • 返回static

  • 示例

$memberBadges = MemberBadge::query()->limit(1)->arrayify()->select();
test($memberBadges);
/*
1-1    array(1) {
         [0] => array(4) {
           ["id"] => int(1)
           ["name"] => string(4) "VIP1"
           ["memo"] => string(19) "VIP1等级的贵宾"
           ["create_time"] => string(19) "2021-01-27 19:09:39"
         }
       }
 */
1
2
3
4
5
6
7
8
9
10
11
12

# ->__construct();

  • 参数
    • DbActiveRecord $activeRecord

# ->getActiveRecord();

取活动记录实例

  • 返回\dce\db\active\ActiveRecord

# \dce\db\active\DbActiveQuery

数据库活动记录查询器

# ->getActiveRecord()

取活动记录实例

# ->where()

设置Where条件

  • 参数

  • 返回self

  • 示例

Member::query()->where('mid', 1);
1

# ->order()

设置排序规则

Member::query()->order('mid');
1

# ->limit()

设置记录截取量

  • 参数

    • int $limit 截取条数
    • int $offset = 0 起始截取偏移量
  • 返回self

  • 示例

Member::query()->limit(10);
1

# ->select()

多记录查询实例化结果集并返回

  • 参数

    • string|RawBuilder|null $indexColumn = null 以此字段作为查询结果数组下标
  • 返回ActiveRecord[]

  • 示例

$memberBadges = MemberBadge::query()->arrayify()->select('id');
test($memberBadges);
/*
1-1    array(5) {
         [1] => array(4) {
           ["id"] => int(1)
           ["name"] => string(4) "VIP1"
           ["memo"] => string(19) "VIP1等级的贵宾"
           ["create_time"] => string(19) "2021-01-27 19:09:39"
         }
         [2] => array(4) {
           ["id"] => int(2)
           ["name"] => string(4) "VIP2"
           ["memo"] => string(19) "VIP2等级的贵宾"
           ["create_time"] => string(19) "2021-01-27 19:09:45"
         }
         [3] => array(4) {
           ["id"] => int(3)
           ["name"] => string(4) "VIP3"
           ["memo"] => string(19) "VIP3等级的贵宾"
           ["create_time"] => string(19) "2021-01-27 19:09:51"
         }
         [6] => array(4) {
           ["id"] => int(6)
           ["name"] => string(4) "VIP3"
           ["memo"] => string(19) "VIP3等级的贵宾"
           ["create_time"] => string(19) "2021-01-31 18:24:44"
         }
       }
 */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# ->each()

多记录查询,返回迭代器,遍历时实例化为活动记录对象

  • 返回\Iterator

  • 示例

$iterator = MemberBadge::query()->arrayify()->limit(2)->each();
foreach ($iterator as $memberBadge) {
    testPoint($memberBadge);
}
/*
1-1    array(4) {
         ["id"] => int(1)
         ["name"] => string(4) "VIP1"
         ["memo"] => string(19) "VIP1等级的贵宾"
         ["create_time"] => string(19) "2021-01-27 19:09:39"
       }

2-1    array(4) {
         ["id"] => int(2)
         ["name"] => string(4) "VIP2"
         ["memo"] => string(19) "VIP2等级的贵宾"
         ["create_time"] => string(19) "2021-01-27 19:09:45"
       }
 */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# ->find()

筛选一条数据库数据,转为活动记录对象并返回

  • 返回ActiveRecord|array|false

  • 示例

$memberBadge = MemberBadge::query()->arrayify()->limit(2)->find();
test($memberBadge);
/*
1-1    array(4) {
         ["id"] => int(1)
         ["name"] => string(4) "VIP1"
         ["memo"] => string(19) "VIP1等级的贵宾"
         ["create_time"] => string(19) "2021-01-27 19:09:39"
       }
 */
1
2
3
4
5
6
7
8
9
10

# ->insert()

向数据库插入数据(建议通过活动记录执行,而不是查询器)

# ->update()

更新筛选的数据(建议通过活动记录执行,而不是查询器)

# ->delete()

删除筛选中的数据(建议通过活动记录执行,而不是查询器)

# ->begin()

开启事务(建议通过活动记录执行,而不是查询器)

# \dce\db\active\ActiveRelation

活动记录关联数据查询器

# ->getActiveQuery()

取活动记录查询器

  • 返回\dce\db\active\ActiveQuery

  • 示例





 





class Member extends DbActiveRecord {
    public function getLogin() {
        $relation = $this->hasOne(MemberLogin::class, ['mid' => 'mid']);
        // 取活动记录查询器
        $activeQuery = $relation->getActiveQuery();
        $activeQuery->limit(1);
        return $relation;
    }
}
1
2
3
4
5
6
7
8
9

下述方法在活动记录相关类中自动调用,无需手动调用

# ->getName()

取关系名

# ->hasOne()

设为一对一关联关系

# ->isHasOne()

是否一对一查询

# ->screen()

查询数据库

# ->setMapping()

设置关联关系映射表

# ->getMapping()

取关联关系映射表

# ->getRelationColumns()

取关系字段映射