FiberPHP ORM: Active Record with relationships, eager loading, attributes, timestamps, scopes on top of fiberphp/database.

Maintainers

Package info

gitee.com/FiberPHP/orm

Issues

pkg:composer/fiberphp/orm

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

dev-master 2026-08-22 14:24 UTC

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,当前版本)

模块能力
Attributefillable/guarded 批量赋值、$casts 类型转换(json/int/bool/string)、获取器 getXxxAttr / 修改器 setXxxAttr
Timestampinsert/UPDATE 时自动填充 created_at / updated_at,值回写 attributes,子类可覆盖列名
Scopebase(Query) 全局作用域(多租户/SaaS 自动加条件,走 Context,天然协程隔离)+ scopeXxx() local scope
关系hasOne / hasMany / belongsTo 三种核心关系,外键按表名单数约定自动推断
预加载with() + Relation::eagerLoad() 实现,1+1 查询解决 N+1,批量查询后按外键映射回父实例
CRUDfind(id) / all() / save()(有 id→update,无→insert) / delete() / with() 链式
Collectionmap/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,实例销毁(协程结束)即自动清除。
  • 全局作用域走 Contextbase()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 生命周期钩子 + ObserverInterfaceBelongsToMany + Pivot
  • P2:SoftDeleteMorphTo/MorphOne/MorphMany 多态、HasManyThrough
  • P3:JsonType JSON 路径查询(需 database Driver 加 jsonPath()