This section is for Northwind Studio engineers building DeskFlow — the task board API on port 8000. Porm is how TaskService, MemberService, and ProjectService query tasks, team_members, and projects without Eloquent-style models.
[db] and call table() from DeskFlow servicestable(), db(), and connectionManager()Pionia includes Porm (Pionia ORM) — a Medoo-inspired query builder, not a full ORM. There are no models or migrations in the framework; you work with tables, arrays, and a fluent API.
// Global helpers (recommended)
$row = table('tasks')->get(1);
$rows = table('tasks')->filter(['status' => 'open'])->limit(10)->all();
// Named connection from environment/settings.ini
table('projects', null, 'db_pgsql')->save(['name' => 'Northwind rebrand']);Porm is built into your Pionia app. Use table() or db() — not legacy Porm\Porm::from() patterns from older tutorials.
In the DeskFlow tutorial you start with hardcoded tasks, then persist them in SQLite and add task.create:
tasks table migration or SQL file under database/.[db] in environment/settings.ini (SQLite is fine for local DeskFlow).TaskService::listAction, replace the array with table('tasks')->filter(['project_id' => $data->getInt('project_id')])->all().$tasks = table('tasks')
->filter(['status' => 'open'])
->orderBy('created_at', 'DESC')
->limit(20)
->all();Try it: Making queries walks through get(), save(), and update() on a single table.
| Topic | Page |
|---|---|
| Configuration & entry points | Getting started |
| CRUD & reads | Making queries |
filter(), orderBy, limit | Filtering |
| WHERE operators & clause keys | WHERE DSL reference |
| Joins & aliases | Relationships & joins |
count, sum, Agg builder | Aggregation |
PaginationCore & list APIs | Pagination |
| Multi-DB & pooling | Connections |
| Transactions & raw SQL | Transactions & raw SQL |
chunk, random, explain | Performance |
| Method cheat sheet | API reference |
table('tasks')
├─ Direct mode → get(), save(), update(), delete(), has(), random(), …
├─ filter() → Builder (where, orderBy, limit, all, count, …)
└─ join() → Join (left, inner, right, full, all, count, random, …)After filter() or join(), table-level write methods (save, get, etc.) are not available on the same chain — finish with all(), get(), or count() on the builder.
GenericServiceConnectionManager keeps PDO alive across requeststable(), db(), connectionManager()Porm::from() or Db::from() in DeskFlow services — prefer the global table() helper wired in bootstrap.save() after filter() on the same chain — finish reads with all() / get() first, then start a new table('tasks') for writes.[db] in settings.ini — DeskFlow on port 8000 still needs a default connection (SQLite is fine locally).connectionManager(); do not call disconnect() between HTTP requests.Wire SQLite for DeskFlow on port 8000.
CRUD on tasks and projects.
Method cheat sheet for Porm.