This section is for developers building Pionia Shop — the store API on port 8000. Porm is how ProductService, CustomerService, and OrderService query products, customers, and orders without Eloquent-style models.
[db] and call table() from Pionia Shop servicestable(), db(), and connectionManager()flowchart LR
ProductService --> table["table('products')"]
CustomerService --> tm["table('customers')"]
OrderService --> orders["table('orders')"]
table --> Porm["Porm / Piql"]
tm --> Porm
orders --> Porm
Porm --> SQLite[("SQLite / PostgreSQL")]Pionia includes Porm (Pionia ORM) — a Medoo-inspired query builder, not a full Eloquent-style ORM. You work with tables, arrays, and a fluent API. Schema changes use PHP migrations (Schema + Blueprint) — see Migrations.
// Global helpers (recommended)
$row = table('products')->get(1);
$rows = table('products')->filter(['status' => 'open'])->limit(10)->all();
// Named connection from environment/settings.ini
table('orders', null, 'db_pgsql')->save(['customer_id' => 1, 'status' => 'pending', 'total' => 49.0]);Porm is built into your Pionia app. Use table() or db() — not legacy Porm\Porm::from() patterns from older tutorials.
In the Pionia Shop tutorial you start with a hardcoded catalog, then persist products in SQLite and add product.create:
php pionia make:table and php pionia migrate — see Migrations.[db] in environment/settings.ini (SQLite is fine for local Pionia Shop).ProductService::listAction, replace the array with table('products')->all().$products = table('products')
->filter(['stock[>]' => 0])
->orderBy('created_at', 'DESC')
->limit(20)
->all();Try it: Making queries walks through get(), save(), and update() on a single table.
| Topic | Page |
|---|---|
| Schema & migrations | Migrations |
| 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('products')
├─ 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 Pionia Shop 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('products') for writes.[db] in settings.ini — Pionia Shop on port 8000 still needs a default connection (SQLite is fine locally).connectionManager(); do not call disconnect() between HTTP requests.make:table, migrate, Blueprint columns.
Wire SQLite for Pionia Shop on port 8000.
CRUD on tasks and projects.