fiberphp / orm
FiberPHP ORM: Active Record with relationships, eager loading, attributes, timestamps, scopes on top of fiberphp/database.
dev-master
2026-08-22 14:24 UTC
Requires
- php: >=8.3
- fiberphp/database: dev-master
- fiberphp/framework: dev-master
Requires (Dev)
- phpunit/phpunit: ^11.0
This package is not auto-updated.
Last update: 2026-08-22 14:25:25 UTC
README
FiberPHP ORM —— 基于 fiberphp/database 连接池/SQL 抽象层的 Active Record 实现,支持属性处理、时间戳、全局作用域、关系映射与预加载,协程原生安全。
参考:命名风格借鉴 ThinkPHP 简短风格(Attr 获取器/修改器、Concern 名词 trait), 关系 API 保持行业惯例(hasOne/belongsTo/with 等)。
特性(P0,当前版本)
| 模块 | 能力 |
|---|---|
| Attribute | fillable/guarded 批量赋值、$casts 类型转换(json/int/bool/string)、获取器 getXxxAttr / 修改器 setXxxAttr |
| Timestamp | insert/UPDATE 时自动填充 created_at / updated_at,值回写 attributes,子类可覆盖列名 |
| Scope | base(Query) 全局作用域(多租户/SaaS 自动加条件,走 Context,天然协程隔离)+ scopeXxx() local scope |
| 关系 | hasOne / hasMany / belongsTo 三种核心关系,外键按表名单数约定自动推断 |
| 预加载 | with() + Relation::eagerLoad() 实现,1+1 查询解决 N+1,批量查询后按外键映射回父实例 |
| CRUD | find(id) / all() / save()(有 id→update,无→insert) / delete() / with() 链式 |
| Collection | map/filter/pluck/each/contains/first/toArray |
快速开始
use FiberPHP\Orm\Model;
use FiberPHP\Orm\Query;
class User extends Model
{
public const TABLE = 'users';
public const PK = 'id';
protected array $fillable = ['name', 'email', 'meta'];
protected array $casts = ['meta' => 'json'];
// 获取器(大写名字)
protected function getNameAttr($value): string
{
return strtoupper($value);
}
// 修改器(小写邮箱)
protected function setEmailAttr($value): string
{
return strtolower($value);
}
// 全局作用域:多租户只看当前租户
public static function base(Query $query): void
{
$query->where('tenant_id', \FiberPHP\Context::get('tenant_id'));
}
// local scope
public function scopeActive(Query $query): void
{
$query->where('status', 1);
}
// 关系
public function profile() { return $this->hasOne(Profile::class); }
public function posts() { return $this->hasMany(Post::class); }
}
// 查单条(触发 base 过滤,结果触发获取器)
$user = User::find(1);
echo $user->name; // 大写
// 预加载 posts(1+1 查询)
$users = User::with('posts')->active()->get();
foreach ($users as $u) {
// $u->posts 已通过 eagerLoad 写入,无额外查询
echo $u->posts->count();
}
// 插入(修改器 + created_at/updated_at 自动填充)
$u = new User();
$u->fill(['name' => 'Alice', 'email' => 'ALICE@EXAMPLE.COM']);
$u->save();
echo $u->id;
echo $u->email; // alice@example.com(修改器生效)
// 更新 + 删除
$u->name = 'Alicia';
$u->save();
$u->delete();
协程安全设计
- 实例不缓存静态:每次
find()/query()返回全新实例,协程间零共享。 - 关系缓存绑实例:
$user->posts懒加载后写入当前实例的$relations,实例销毁(协程结束)即自动清除。 - 全局作用域走 Context:
base()从FiberPHP\Context读取 tenant_id,天然每协程独立。 - DB 连接池:底层依赖
fiberphp/database的 Workerman 协程连接池,多协程共享连接。
目录结构
orm/
├── src/
│ ├── Model.php # Active Record 基类
│ ├── Query.php # ORM 查询层(包装 database Query,加预加载/base)
│ ├── Collection.php # 模型集合
│ ├── Concern/
│ │ ├── Attribute.php # 属性处理(fillable/casts/获取器/修改器)
│ │ ├── Relation.php # 关系入口(hasOne/hasMany/belongsTo + 懒加载触发)
│ │ ├── Timestamp.php # 时间戳自动填充
│ │ └── Scope.php # 全局/局部作用域
│ ├── Relation/
│ │ ├── Relation.php # 关系抽象基类(懒加载 + 预加载契约)
│ │ ├── HasOne.php
│ │ ├── HasMany.php
│ │ └── BelongsTo.php
│ ├── OrmProvider.php
│ └── Install.php
├── config/orm.php # observers 声明(P1 启用)
├── tests/
├── composer.json
└── README.md
后续规划
- P1:
Collection继续补充、Event生命周期钩子 +ObserverInterface、BelongsToMany+Pivot - P2:
SoftDelete、MorphTo/MorphOne/MorphMany多态、HasManyThrough - P3:
JsonTypeJSON 路径查询(需 database Driver 加jsonPath())