Code Generator
The code generator creates PHP classes based on your database tables, dramatically speeding up development.
What It Generates
The code generator supports two architectural patterns:
Repository Pattern (Default)
- Model - PHP class with properties matching table columns
- Repository - Data access layer with ORM integration
- Service - Business logic layer extending BaseService
- REST API - Complete CRUD endpoints (GET, POST, PUT)
- Functional Tests - Test suite for the CRUD API
- Config - Automatic DI bindings (added automatically with
--save)
ActiveRecord Pattern (with --activerecord)
- Model - PHP class with properties and ActiveRecord trait for direct database operations
- REST API - Complete CRUD endpoints (GET, POST, PUT)
- Functional Tests - Test suite for the CRUD API
The delete endpoint is not generated; write it by hand where the entity needs one.
The generated routes are GET /{table}/{id}, GET /{table}, POST /{table} and
PUT /{table}/{id}. POST and PUT take the same body, the writable fields; the key is
generated on POST and taken from the path on PUT, so a key sent in the body is refused.
From columns to the OpenAPI schema
Each column becomes an OA\Property on the model and in the request body of POST and
PUT. That schema is what #[ValidateRequest] enforces on the request (400 on failure),
what the model is checked against on every save() (see below), and what the API docs
publish:
| Column | Generated |
|---|---|
int, bigint, decimal, date, datetime, ... | type and format |
NULL allowed | nullable: true |
NOT NULL | listed in required |
char(N) / varchar(N) | maxLength: N |
NOT NULL text (char, varchar, text) with no default | minLength: 1: an empty string is refused like a missing value |
primary key (auto-increment, or a UUID seeded by TableUuidPKAttribute), virtual generated column | readOnly: true: the server generates it; the API returns it and does not take it |
Value ranges (minimum, maximum) cannot be read from a column type; add them by hand.
The model's table attribute also declares validator: SchemaValidator::class. The model is
then checked against its own schema every time it is saved, not only when a request comes
in: a command line script, a queue consumer or a service that saves it gets the same 400.
A readOnly property, such as the generated key, is not required for that check. Writes
that do not go through save() (UpdateQuery, InsertBulkQuery, raw SQL) are not
checked. See OpenAPI Integration.
The generated functional test also sends invalid bodies straight to the server, on POST
and on PUT: the key in the body, the required fields missing, and an empty value for each
minLength column. It expects 400. They are sent without the OpenAPI spec on the client
side, so the test client does not stop them first.
Usage
APP_ENV=<environment> php gluo codegen:<component> --table=<table_name> [options]
php gluo --env=<environment> codegen:<component> --table=<table_name> [options]
Required
--table=<name>- Database table name
Environment
You can specify the environment in two ways:
- Set the
APP_ENVenvironment variable - Use the
--env=<environment>parameter (overridesAPP_ENV)
Note: At least one method must be used to specify the environment (dev, test, prod).
Arguments (at least one required)
| Argument | Description | Repository Pattern | ActiveRecord Pattern |
|---|---|---|---|
all | Generate all components | ✓ All components | ✓ Model, Controller, Test |
model | Generate Model | ✓ | ✓ (with ActiveRecord trait) |
repo or repository | Generate Repository | ✓ | ✗ Not applicable |
service | Generate Service | ✓ | ✗ Not applicable |
controller | Generate REST controller | ✓ | ✓ |
test | Generate Test | ✓ | ✓ |
Options
--activerecord- Use ActiveRecord pattern instead of a Repository pattern--save- Save generated files to disk (otherwise prints to console)--debug- Show debug information
Examples
The commands below run from the repository root, which is also the PHP application root. Generated files land under src/ (model, repository, service, controller), tests/ (the functional test) and config/ (the DI bindings, with --save).
Repository Pattern (Default)
Generate all components for the project table using the Repository pattern:
# Using APP_ENV
APP_ENV=dev php gluo codegen:all --table=project --save
# Using --env parameter
php gluo --env=dev codegen:all --table=project --save
This creates:
src/Model/Project.phpsrc/Repository/ProjectRepository.phpsrc/Service/ProjectService.phpsrc/Controller/ProjectController.phptests/Controller/ProjectTest.php- Automatically adds DI bindings to
config/dev/04-repositories.phpandconfig/dev/05-services.php
Generate only specific components:
APP_ENV=dev php gluo codegen --table=project model controller --save
ActiveRecord Pattern
Generate all components for the note table using the ActiveRecord pattern:
# Using APP_ENV
APP_ENV=test php gluo codegen:all --table=note --activerecord --save
# Using --env parameter
php gluo --env=test codegen:all --table=note --activerecord --save
This creates:
src/Model/Note.php(with ActiveRecord trait)src/Controller/NoteController.phptests/Controller/NoteTest.php
Generate only the model:
APP_ENV=test php gluo codegen:model --table=note --activerecord --save
Preview Without Saving
Preview the generated REST controller without saving to disk:
APP_ENV=dev php gluo codegen:controller --table=project
php gluo --env=dev codegen:all --table=note --activerecord
Automatic Configuration
When using --save with the Repository pattern, repository and service bindings are automatically added to the configuration files:
- Repositories →
config/dev/04-repositories.php - Services →
config/dev/05-services.php
No manual configuration needed!
Note: ActiveRecord pattern does not require DI bindings since models use the ActiveRecord trait for direct database access.
Example output:
Processing Repository for table project...
File saved in src/Repository/ProjectRepository.php
Added use statement for ProjectRepository to 04-repositories.php
Added DI binding for ProjectRepository to 04-repositories.php
Important Notes
Using --save will overwrite existing files without warning. Be careful when regenerating files you've customized.
After generating REST controllers, remember to:
- Run
php gluo openapito update the OpenAPI specification - Run
php gluo testto verify the generated tests pass
Customizing Templates
You can modify existing templates or create your own. The default templates ship inside byjg/gluo-core (vendor/byjg/gluo-core/templates/codegen/) and use the Jinja template engine for PHP. To customize, copy them into your project — a local templates/codegen/ directory takes precedence over the package templates:
mkdir -p templates/codegen
cp -r vendor/byjg/gluo-core/templates/codegen/* templates/codegen/
Available templates:
Repository Pattern:
model.php.jinja- Model class templaterepository.php.jinja- Repository class templateservice.php.jinja- Service class templatecontroller.php.jinja- REST controller templatetest.php.jinja- Test class template
ActiveRecord Pattern:
model.php.jinja- Same model template; theactiverecordvariable switches it to the ActiveRecord traitcontrolleractiverecord.php.jinja- REST controller for ActiveRecord template- Uses the same
test.php.jinjatemplate as a Repository pattern
Template variables available (see Template Customization for the full field-level reference):
className- PascalCase class name (e.g.,UserProfile)tableName- Original table name (e.g.,user_profile)varTableName- camelCase variable name (e.g.,userProfile)restPath/restTag- REST route path (e.g.,user/profile) and OpenAPI tagnamespace- Project namespacefields- Array of table columns (keys:field,property,type,php_type,openapi_type,openapi_format,openapi_max_length,null,key,default,extra)primaryKeys- Array of primary key column namesnullableFields/nonNullableFields- camelCase property listsindexes- Table indexes (withcamelColumnName)autoIncrement-"yes"when the PK auto-incrementsactiverecord- True in ActiveRecord modehasCreatedAt/hasUpdatedAt/hasDeletedAt- Timestamp-trait switches