EntityForge is a configuration-driven, multi-tenant SaaS framework. JSON-driven code generation, two tenant isolation strategies, automated migrations, an HTTP routing layer with middleware pipeline, and a DI container โ all wired through a single boot cycle.
composer require entity-forge/entity-forge
EntityForge ships a complete, opinionated foundation. Every feature is documented, tested, and wired together through a single boot cycle.
Define an entity in JSON โ fields, relations, and indexes. One command generates a typed PHP entity class, a repository with full CRUD, and paired
Shared database (scoped by
Resolve the active tenant from an HTTP header, subdomain, Bearer JWT, or session. Configured in one YAML key. Custom resolvers implement
FastRoute-backed
Supports
Batch-tracked forward and rollback migrations.
EntityForge does not ship auth.
Five steps. One JSON entity, one YAML config, three CLI commands.
1. config/application.yaml
2. config/entities/Order.json
3. Generate, migrate, onboard
4. Boot and query
The pivot is
All tenants share one database. Every table gets a
Each tenant gets a dedicated database named
Reads a configurable HTTP header from the request context. Default:
Extracts the leading subdomain from the host (
Decodes and verifies a Bearer JWT from the Authorization header, then extracts a configurable claim. Supports RS256.
Reads tenant from
Validates tenant ID format (
Sets
Sets
Drops the tenant database (database strategy) via
A complete, immutable HTTP stack built on FastRoute. No additional framework required.
Every major operation has a dedicated
| Command | Options | Description |
|---|---|---|
| generate <Entity> | --migration | Generate entity + repository from JSON schema. Add --migration for paired .up.sql / .down.sql files. |
| generate:all | --config-dir | Generate all schemas in config/entities/. Monotonically ordered migration timestamps. Run from project root. |
| migrate | --dry-run | Run pending migrations on the main database. Skips already-executed files via the migrations tracking table. |
| migrate:rollback | --dry-run | Roll back the last migration batch. Requires paired .down.sql โ missing file aborts with exception. |
| migrate:all-tenants | --tenant, --parallel N, --dry-run | Run pending migrations on every active tenant DB. Up to N concurrent workers via symfony/process. Suspended tenants skipped. |
| tenant:create <id> | --name | Onboard a new tenant. Atomic: validates ID, provisions DB, runs migrations, registers in tenants table. |
| make:middleware <Name> | --auth, --output | Scaffold a middleware class. Use --auth for an AuthMiddlewareInterface stub with annotated steps. |
| make:controller <Name> | --output | Scaffold a controller class with CRUD method stubs. |
Every module has a single responsibility. The boot sequence is deterministic and transparent.
Boot Sequence
Source Tree
Every query decision must account for both strategies. There is no "skip scoping" path in BaseRepository.
The
Instantiate a fresh repository after
Tenant resolution, connection selection, and scope injection are always conscious calls โ nothing happens silently.
New entity types go through the generator pipeline, not handwritten files. The JSON schema is the single source of truth.
EntityForge is a WIP. The core is complete and tested.
Both strategies fully implemented. TenantConnectionResolver, TenantContext, BaseRepository scoping โ all production-ready.
EntityBuilder generates typed properties for belongsTo and hasMany. MigrationBuilder emits FK constraints, INDEX and UNIQUE INDEX clauses.
MigrationRunner with batch-tracked rollback. dry-run across all migration commands. migrate:all-tenants with --parallel N and suspended-tenant skipping.
TenantService is the canonical entry point. Atomic provisioning with rollback-on-failure. Suspended tenants blocked at boot.
FastRoute-backed router with {param} segments. Immutable middleware chain. Three response modes. AuthMiddlewareInterface integration surface.
bind, singleton, instance, and make with auto-wiring. Core services pre-registered as singletons after boot.
All four implemented and configurable via YAML. JWT resolver verifies Bearer tokens. Session resolver supports injected context for testability.
RequestLifecycle::begin()/end() for Swoole, RoadRunner, Octane. setTenantId() throws LogicException if already set.
EntityForge is published on Packagist. Install via
A reference SaaS application demonstrating real-world EntityForge usage โ entity definitions, tenant onboarding, HTTP routing, middleware pipeline, and repository patterns โ to help developers get started quickly.
EntityForge gives you multi-tenancy, code generation, migrations, HTTP routing, and a DI container โ all wired through a single boot cycle. Now on Packagist.