preflow/data
Composer 安装命令:
composer require preflow/data
包简介
Preflow data — storage drivers, models, migrations
README 文档
README
Multi-storage data layer for Preflow. Supports JSON files and SQLite out of the box; different models can use different backends simultaneously.
Installation
composer require preflow/data
Requires PHP 8.4+, ext-pdo, ext-pdo_sqlite.
What it does
Models are annotated with PHP attributes. DataManager is the single entry point — it reads model metadata via reflection, selects the right storage driver, and returns typed results. QueryBuilder provides a fluent API for filtering, sorting, searching, and pagination. Migrations are handled by Schema + Table + Migrator.
API
Attributes
| Attribute | Target | Description |
|---|---|---|
#[Entity(table: 'posts', storage: 'sqlite')] |
Class | Maps model to a table/collection and a named driver. storage defaults to 'default'. |
#[Id] |
Property | Marks the primary key field. Works on any property — use string $uuid for UUIDs or int $id for auto-increment. |
#[Field(searchable: true)] |
Property | Marks a field; searchable: true includes it in full-text search. |
#[Timestamps] |
Class | Adds created_at / updated_at handling. |
Model
$model->fill(array $data): void // hydrate from associative array $model->toArray(): array // export public properties
DataManager
$dm->find(Post::class, $id): ?Post $dm->query(Post::class): QueryBuilder<Post> $dm->save(Model $model): void // INSERT when ID is empty, UPDATE otherwise $dm->insert(Model $model): void // explicit INSERT; reads back lastInsertId() $dm->update(Model $model): void // explicit UPDATE $dm->delete(Post::class, $id): void // delete by class + ID $dm->delete($model): void // delete by model instance $dm->raw(string $sql, array $bindings, string $storage): array // raw SQL query
save() detects an empty ID field and automatically issues an INSERT, then reads back lastInsertId() into the model — no need to pre-generate IDs for auto-increment tables.
QueryBuilder
All methods return $this for chaining except the terminal methods.
->where('status', 'published') ->where('views', '>', 100) ->orWhere('featured', true) ->orderBy('created_at', SortDirection::Desc) ->limit(10)->offset(20) ->search('php') // searches all #[Field(searchable: true)] fields ->get(): ResultSet // all results ->first(): ?Model ->paginate(perPage: 15, currentPage: 2): PaginatedResult
Storage drivers
| Class | Backend |
|---|---|
JsonFileDriver |
One .json file per record at {basePath}/{table}/{id}.json |
SqliteDriver |
PDO-based SQLite via PdoDriver + QueryCompiler |
Migrations
abstract class Migration { abstract public function up(Schema $schema): void; public function down(Schema $schema): void {} }
Schema methods: create(string $table, callable $callback), drop(string $table).
Table builder: uuid, string, text, integer, boolean, json, timestamps, nullable(), primary(), index().
Auto-increment IDs
Place #[Id] on an int property and leave it at 0 (or unset). save() / insert() will issue an INSERT and read the generated ID back via lastInsertId().
#[Entity(table: 'comments', storage: 'sqlite')] final class Comment extends Model { #[Id] public int $id = 0; #[Field] public string $body = ''; } $comment = new Comment(); $comment->body = 'Great post!'; $dm->save($comment); echo $comment->id; // e.g. 42 — populated after insert
Raw SQL
Use raw() to run a query that the fluent builder cannot express. Results are returned as plain arrays.
$rows = $dm->raw( 'SELECT p.*, COUNT(c.id) AS comment_count FROM posts p LEFT JOIN comments c ON c.post_id = p.id GROUP BY p.id', [], 'sqlite', );
Usage
Model:
use Preflow\Data\{Model, ModelMetadata}; use Preflow\Data\Attributes\{Entity, Id, Field, Timestamps}; #[Entity(table: 'posts', storage: 'sqlite')] #[Timestamps] final class Post extends Model { #[Id] public string $id; #[Field(searchable: true)] public string $title; #[Field(searchable: true)] public string $body; public string $status = 'draft'; }
Querying:
// Find by ID $post = $dm->find(Post::class, 'abc-123'); // Filtered query $posts = $dm->query(Post::class) ->where('status', 'published') ->orderBy('created_at', SortDirection::Desc) ->paginate(perPage: 10, currentPage: 1); // Full-text search across searchable fields $results = $dm->query(Post::class)->search('preflow')->get();
Saving:
$post = new Post(); $post->fill(['id' => 'abc-123', 'title' => 'Hello', 'body' => '...', 'status' => 'published']); $dm->save($post);
Migration:
use Preflow\Data\Migration\{Migration, Schema}; final class CreatePostsTable extends Migration { public function up(Schema $schema): void { $schema->create('posts', function (Table $t) { $t->uuid('id')->primary(); $t->string('title')->index(); $t->text('body'); $t->string('status'); $t->timestamps(); }); } public function down(Schema $schema): void { $schema->drop('posts'); } }
Multi-storage setup:
$dm = new DataManager([ 'default' => new JsonFileDriver(basePath: '/storage/data'), 'sqlite' => new SqliteDriver(new \PDO('sqlite:/storage/db.sqlite')), ]);
Models with #[Entity(storage: 'sqlite')] use SQLite; all others fall back to 'default'.
preflow/data 适用场景与选型建议
preflow/data 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 34 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 04 月 10 日, 在 PHP 生态内属于活跃度较高的组件。
我们在过去多个企业项目中使用过 preflow/data 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 preflow/data 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
统计信息
- 总下载量: 34
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 31
- 依赖项目数: 4
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-04-10