PHPackages                             veasin/ff-ddd - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. veasin/ff-ddd

ActiveLibrary

veasin/ff-ddd
=============

DDD modeling layer: concept-config driven, separation of abstraction and data operations, built on the veasin/ff functional framework

0.2.0(today)03↑2900%LGPL-3.0-or-laterPHPPHP &gt;=8.5

Since Jul 28Pushed todayCompare

[ Source](https://github.com/veasin/ff-ddd)[ Packagist](https://packagist.org/packages/veasin/ff-ddd)[ Docs](https://github.com/veasin/ff-ddd)[ RSS](/packages/veasin-ff-ddd/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (1)Versions (7)Used By (0)

veasin/ff-ddd
=============

[](#veasinff-ddd)

基于 **veasin/ff** 函数式框架的 DDD 业务建模层。 概念配置驱动：**抽象与数据操作分离** —— `then` 之前只构建概念配置，`then` 触发才执行数据操作。

安装
--

[](#安装)

```
composer require veasin/ff-ddd
```

`veasin/ff` 为依赖项，框架函数（如 `ff\db`、`ff\container`）通过 composer 的 `autoload.files` 自动加载。

核心概念
----

[](#核心概念)

术语说明概念领域模型最小单元，由 `ddd::define()` 定义，概念名全小写 `/` 分隔，如 `corp/user`集合概念的一组实例，可被范围方法分割，`ddd::collection(name)` 开链单体集合经 `id()`/`create()` 缩小到的唯一元素，`ddd::entity(name)` 开链范围对集合的筛选条件，链上每一步都在叠加关系概念间的关联（从属导航），触发根转化 + 范围转换配置概念的全部定义，then 前链式操作的最终产物**铁律**

1. 抽象与数据操作分离（`then` 前只构建配置）
2. 集合 → 范围方法 → 新集合；单体 → 关系方法 → 集合/单体
3. 一切显式，无自动推导（概念必须 `define`）

配置结构
----

[](#配置结构)

`ddd::define(name, $colCfg, $entCfg)` 将集合与单体配置分离为第二、三参数，各自独立归一化、独立存储，不合并。

### 子类型

[](#子类型)

```
// 范围项：在某字段 field 上施加一次筛选
//   op 缺省 'eq'；顺序固定 [field, value, op?]
type ScopeItem = [field: string, value: unknown, op?: string];

// 范围定义 = 范围方法返回值：
//   · ScopeItem —— 字面范围项
//   · 闭包      —— 运行时追加范围项
type Def = ScopeItem | ((c: Concept) => void);

type Op = 'eq' | 'ne' | 'gt' | 'ge' | 'lt' | 'le' | 'like' | 'in' | 'not_in' | 'is_null' | 'not_null';

type RelationDef = {
  concept: string;                        // 目标概念（类名或注册概念名）
  via: Record;            // map：targetField => currentField
};
```

### 集合配置（colConfig，第二参数）

[](#集合配置colconfig第二参数)

```
interface ColConfig {
  base?:    string | null;                                         // 继承父集合；合并时子优先、子 null 删父对应项
  source:   { table: string; primary?: string; db?: string };      // 数据源；primary 默认 'id'，db 默认 'default'
  defs:     Record;                                   // map：method => Def（范围方法定义）
  mutators: Record unknown>;              // map：field => 闭包（persist 前作用）
  uniques:  string[];                                              // 唯一键；默认 ['id']
  order:    null | string | Record;        // 默认排序
  entity?:  string;                                                // id()/create()/findUnique() fork 目标 entity 类
  trigger?: string;                                                // 自定义集合 Trigger 类
  // —— 运行时状态（链式构建自动填充，不写死在定义中） ——
  scopes:   ScopeItem[];                                           // 已应用范围项
  update:   Record | null;                        // 当前概念瞬态更新
  pending:  Pending[];                                             // 仅上游 create 态（内联 data 快照）
  refs:     Record;               // concept => (field => value) 上游瞬态包
}
```

```
ddd::define('corp/user', [
    'source'    => ['table' => 'corp_users', 'primary' => 'id', 'db' => 'default'],
    'defs'      => ['active' => ['status', 1], 'newest' => ['created_at', null, 'desc']],
    'uniques'   => ['id', 'email'],
    'mutators'  => ['password' => static fn($v) => password_hash($v, PASSWORD_DEFAULT)],
    'order'     => 'created_at',
    'entity'    => UserEnt::class,
    // 'base'   => 'base/user',
], null);
```

### 单体配置（entConfig，第三参数）

[](#单体配置entconfig第三参数)

```
interface EntConfig {
  base?:     string | null;                                         // 继承父单体；合并时子优先、子 null 删父对应项
  relations: Record;                           // map：method => RelationDef（关系定义）
  mutators:  Record unknown>;              // 优先读自身，fallback 到 colConfig
  uniques:   string[];                                              // 唯一键；优先读自身，fallback 到 colConfig
  trigger?:  string;                                                // 自定义实体 Trigger 类
  // —— 运行时状态（链式构建自动填充） ——
  scopes:    ScopeItem[];                                           // 已应用范围项
  create:    Record | null;                        // 当前概念构造数据；存在即 create 态
  update:    Record | null;                        // 当前概念瞬态更新
  pending:   Pending[];                                             // 仅上游 create 态（内联 data 快照）
  refs:      Record;               // concept => (field => value) 上游瞬态包
}
```

```
ddd::define('corp/user', null, [
    'source'    => ['table' => 'corp_users', 'primary' => 'id', 'db' => 'default'],
    'relations' => ['tokens' => ['concept' => 'corp/user/token', 'via' => ['user_id' => 'id']]],
    'uniques'   => ['id', 'email'],
    'mutators'  => ['password' => static fn($v) => password_hash($v, PASSWORD_DEFAULT)],
    // 'base'   => 'base/user',
]);
```

### 字段归属

[](#字段归属)

字段colConfigentConfig说明`source`✅✅实体构造时 ent→col fallback`defs`✅❌集合专属`relations`❌✅单体专属`uniques`✅✅实体构造时 ent→col fallback`mutators`✅✅实体构造时 ent→col fallback`order`✅❌仅集合配置持有`base`✅✅同类型继承（col→col, ent→ent）> **配置分离强制规则**：colConfig 不含 `relations`/`create`；entConfig 不含 `defs`/`entity`。`normalize()` 阶段强制执行（传入即剥离）。

### 视图构造 fallback

[](#视图构造-fallback)

实体构造时，最终配置 = entConfig 为基底，以下共享字段若 entConfig 不存在则从 colConfig 回退读取：

```
final.source   = entConfig.source   ?? colConfig.source   ?? 默认
final.uniques  = entConfig.uniques  ?? colConfig.uniques  ?? ['id']
final.mutators = entConfig.mutators ?? colConfig.mutators ?? []

```

共享字段仅 `source`、`uniques`、`mutators` 三项。`order` 不属于共享字段——实体没有默认排序。

### base 继承

[](#base-继承)

`base` 仅同类型继承（colConfig→父 colConfig，entConfig→父 entConfig），不跨类型：

- 父项某 key 为数组（`defs`/`relations`）则逐项合并，子优先；子值为 `null` 删除父对应项
- 非数组字段直接覆盖
- `base` 继承关系在 `normalize()` 阶段解析展开，展开后 `base` 字段被移除

### 正常化（normalize）拆分

[](#正常化normalize拆分)

集合和单体各自独立归一化：

- **`normalizeCol`**：`defs`→`[]`，`mutators`→`[]`，`scopes`→`[]`，`pending`→`[]`，`refs`→`[]`；`uniques`→`['id']`；剥离 `relations`/`create`
- **`normalizeEnt`**：`relations`→`[]`，`scopes`→`[]`，`pending`→`[]`，`refs`→`[]`；剥离 `defs`/`entity`/`order`

自定义 Trigger 扩展
--------------

[](#自定义-trigger-扩展)

业务方法（如 `launch()`、`toggleSkip()`）属于"找到实体后的数据操作"，应放在 Trigger 上。通过 lv0 配置注入 `trigger` 即可，不必绕三层继承：

```
use ff\ddd\ddd;
use ff\ddd\trigger\entity as entityTrigger;

// 1. 自定义 Trigger：继承单体触发基类，写业务方法
class DirsTrigger extends entityTrigger {
    public function launch(): array {
        $dir = $this->get();            // 复用原生 get()
        // ... 执行业务逻辑（文件系统、exec 等）
        return $dir;
    }
}

// 2. lv0 配置注入 trigger 类名
ddd::define('dirs', [
    'source'  => ['table' => 'dirs', 'primary' => 'id'],
    'trigger' => DirsTrigger::class,
]);

// 3. 使用：链式走到 then，自动返回自定义 Trigger 实例
$dir = ddd::collection('dirs')->id(5)->then->launch();
```

同样支持集合 Trigger 扩展（继承 `trigger\collection`）。若需自定义 Entity（如有额外导航方法），配置 `entity` 指定 fork 目标：

```
ddd::define('dirs', [
    'source' => ['table' => 'dirs', 'primary' => 'id'],
    'entity' => DirsEntity::class,   // id()/create()/findUnique() fork 到 DirsEntity
]);
```

快速开始
----

[](#快速开始)

```
use function ff\{container, db};
use ff\ddd\ddd;

// 1. 注册概念（集合与单体配置分离）
ddd::define('corps', [
    'source'   => ['table' => 'corps', 'primary' => 'id'],
], [
    'relations'=> ['users' => ['concept' => 'corp/users', 'via' => ['id' => 'corp_id']]],
]);
ddd::define('corp/users', [
    'source'   => ['table' => 'corp_users', 'primary' => 'id'],
    'order'    => ['created_at' => 'desc'],
    'uniques'  => ['id', 'email'],
    'mutators' => ['password' => static fn($v) => password_hash($v, PASSWORD_DEFAULT)],
    'defs'     => ['active' => ['status', 1], 'newest' => ['created_at', null, 'desc']],
], [
    'relations'=> ['tokens' => ['concept' => 'corp/user/token', 'via' => ['user_id' => 'id']]],
]);
ddd::define('corp/user/token', [
    'source' => ['table' => 'corp_user_tokens', 'primary' => 'id'],
]);

// 2. 列表（集合，范围方法 active() 来自配置的 defs）
ddd::collection('corp/users')->active()->then->get();

// 3. 读取单体
ddd::collection('corp/users')->id(5)->then->get();

// 4. 新建（一级 rules：unique/mutators 自动生效）
ddd::collection('corp/users')->create(['email' => 'a@b.com', 'password' => 'secret'])->then->persist();

// 5. 关联创建（依赖链自动处理：先 persist user 得 id，再回填 token.user_id）
ddd::collection('corps')
    ->id(5)
    ->users()
    ->create(['email' => 'u@b.com', 'password' => 'x'])
    ->tokens()
    ->create(['token' => 'xxx', 'client' => 'web'])
    ->then->persist();   // 返回 token 的持久化结果

// 6. 更新 / 删除 / 计数 / 存在性
ddd::collection('corp/users')->id(5)->update(['nick_name' => '新名'])->then->persist();
ddd::collection('corp/users')->id(5)->then->delete();
ddd::collection('corp/users')->active()->then->count();
ddd::collection('corp/users')->findUnique(['email' => 'a@b.com'])->then->exists();

// 7. 配置继承（base）
ddd::define('corp/vip/users', [
    'base'   => 'corp/users',
    'defs'   => ['vip' => ['is_vip', 1]],
]);
ddd::collection('corp/vip/users')->vip()->then->get();

// 8. 显式定义（类形态）
class VipUsers extends \ff\ddd\collection{
    public const array CONCEPT = [
        'base'   => 'corp/users',
        'defs'   => ['vip' => ['is_vip', 1]],
    ];
}
ddd::define('corp/vip2/users', VipUsers::class);
ddd::collection('corp/vip2/users')->vip()->then->get();
```

IDE 辅助
------

[](#ide-辅助)

```
# 自动生成 .phpstorm.meta.php + _ddd.php（桩类命名空间 _ddd）
php vendor/bin/ddd.php

# 监控模式：文件变动自动重生成
php vendor/bin/ddd.php --watch
```

生成 PhpStorm 元数据（override / expectedArguments / registerArgumentsSet）， 以及 IDE 桩类（`_ddd` 命名空间，`@method` 标注 defs / relations / 自定义方法）。 支持 lv1 class 反射 + base 继承链合并。`collection()` 和 `entity()` 各自独立提示列表。

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance100

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity45

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

5

Last Release

0d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/127591812?v=4)[vea](/maintainers/vea)[@Vea](https://github.com/Vea)

### Embed Badge

![Health badge](/badges/veasin-ff-ddd/health.svg)

```
[![Health](https://phpackages.com/badges/veasin-ff-ddd/health.svg)](https://phpackages.com/packages/veasin-ff-ddd)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
