Skip to content

FW Database & ORM Architecture

To build a framework that is highly performant and deterministic, we cannot rely on the Active Record pattern. Active Record encourages hidden queries, "magic" lazy loading (the root of N+1 issues), and mutable states that confuse static analyzers.

Instead, FW adopts a Data Mapper & Repository pattern inspired by Prisma and Doctrine, strictly optimized for an async persistent runtime (Swoole/RoadRunner).

Progressive Enhancement & No Lock-In

While the FW ecosystem provides a blazing-fast compiled ORM, the framework itself is fundamentally unopinionated about your data layer.

You are never locked into the FW ecosystem. The framework defines strict contracts (e.g., ConnectionInterface, ConnectionPoolInterface), but the implementation is entirely up to you.

  • Want to use Doctrine? Bind it in the compiled DI container.
  • Want to use raw PDO? Just inject PDO into your handlers.

Our goal is to provide a native ORM that is so strictly typed and performant that you want to use it, but you are never forced to use it.

Core Directives for the Native FW DB Layer

1. Zero Lazy Loading (N+1 Prevention)

The Problem: In traditional ORMs, calling $user->posts magically triggers a database query if the posts weren't loaded. In a loop, this causes an N+1 query disaster. The FW Solution: Models are strictly typed, immutable readonly class objects. They have no knowledge of the database. If a relationship isn't explicitly fetched via the Repository, the property is either null or structurally absent. There is absolutely no lazy loading at runtime. To fetch relations, developers must use explicit intent: UserRepository::getWithPosts(int $userId).

2. Async Connection Pooling

In standard PHP-FPM, a database connection is created and destroyed on every request. In FW's persistent Swoole server, connections are expensive to establish but cheap to keep open.

  • The framework will implement a Connection Pool.
  • When an HTTP request comes in, the framework checks out a connection from the pool, executes async queries without blocking the event loop, and returns the connection to the pool at the end of the request.
  • Supported Adapters: MySQL, PostgreSQL, SQLite, InMemory (for blazing fast testing).

3. Declarative Schema (Prisma-Inspired)

Instead of manually writing verbose Migration files, developers (and AI) define the database schema declaratively in database/schema.yaml:

yaml
models:
  User:
    id: uuid @primary
    email: string @unique
    age: int?
    posts: hasMany(Post)

  Post:
    id: uuid @primary
    title: string
    user_id: uuid @foreign(User.id)

Compilation Step: Running php fw build:db will automatically:

  1. Generate strict Modules\User\UserModel (DTO).
  2. Generate the base UserRepository interface and SQL implementation based on the schema mapping.
  3. Compute schema diffs locally to auto-generate standard SQL UP and DOWN migrations.

4. Compile-Time Query Checks

The generated Repositories utilize strict typing. $userRepository->findById('invalid-type') will fail PHPStan Level 9 immediately. Because the Model schemas are strictly defined in YAML and compiled to PHP, an AI agent knows exactly what fields exist on a Model without having to guess or read the database directly.

Engineered for Agents. Released under the MIT License.