Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Code Generator Laravel Package

krlove/code-generator

krlove/code-generator is a Laravel package that scaffolds PHP classes from your existing database schema, automating model and related boilerplate so you can skip repetitive hand-written code and keep generated classes consistent with your tables.

Deep Wiki
Context7

Getting Started

krlove/code-generator is a reverse-engineering tool: it reads your existing database schema and emits Eloquent model classes. It is not a migration or scaffolding package — the DB is the source of truth, and the models are the output.

Install and publish config:

composer require krlove/code-generator --dev
php artisan vendor:publish --provider="Krlove\CodeGenerator\CodeGeneratorServiceProvider"

Run the generator against your default connection:

php artisan code:models

First use case to try: point it at a table you already understand (users) and inspect the result before trusting the whole run.

php artisan code:models --table=users

You'll get a class in app/ (namespace App by default, per config/code-generator.php) extending Illuminate\Database\Eloquent\Model, with $table, $primaryKey, $timestamps, $fillable, @property docblocks derived from column types, and relation methods inferred from foreign keys.

Where to look first:

  • config/code-generator.php — the model_defaults block (namespace, base_class_name, connection, no_timestamps, date_format, backup). Set this once so every generation matches your conventions.
  • The command itself: php artisan code:models --help — options include --table, --connection, --namespace, --parent, --no-timestamps, --date-format, --backup, --filename, --path.

Implementation Patterns

Brownfield onboarding. The strongest day-to-day use is a legacy or externally-owned database. Generate everything once, then hand-curate. Do not treat generated output as final code — treat it as a first draft you commit and then edit.

Generate into a scratch directory, then move. Avoid letting the tool write directly into app/Models on a codebase with hand-edited models:

php artisan code:models --path=database/generated --namespace="App\Generated"

Review the diff, copy what you need, discard the rest.

Custom base class instead of repeating behavior. Point base_class_name (or --parent) at your own App\Models\BaseModel so generated models inherit UUID keys, global scopes, $guarded, cast conventions, etc. This is the single highest-leverage config change.

// config/code-generator.php
'model_defaults' => [
    'namespace'       => 'App\\Models',
    'base_class_name' => App\\Models\\BaseModel::class,
    'connection'      => 'legacy',
    'backup'          => true,
],

Per-table regeneration during schema drift. When a table changes, regenerate just that table rather than the whole schema:

php artisan code:models --table=orders --backup

--backup writes a .backup sibling; diffing it against the overwritten file shows exactly what the schema change did. Add *.backup to .gitignore unless you deliberately keep them.

Multi-connection apps. Pass --connection= for each database rather than relying on the default. Generate per-connection into separate namespaces (App\Models\Billing, App\Models\Reporting) so ownership is obvious.

CI drift check. Because output is deterministic, you can assert models match the schema:

php artisan schema:dump --prune          # fast local DB
php artisan code:models --path=/tmp/gen
diff -r /tmp/gen app/Models || echo "models out of sync"

This is useful when the DB is owned by another team and you want a warning when a deploy ships a column you haven't modeled.

Read-only legacy models. For reporting-side tables you never write to, generate normally, then strip $fillable and set $guarded = ['*'] in the model or base class. The generator's $fillable is literal — every column ends up mass-assignable.

Gotchas and Tips

It is archived (last release 2022-02-20). No Laravel 10/11 guarantees. Its doctrine/dbal constraint is the usual failure point — DBAL 3/4 removal of getSchemaManager() and type-mapping changes break schema introspection. Pin your Laravel/DBAL versions, or fork the package and patch the DBAL calls. On a modern app, budget a day for the fork; don't assume composer require just works.

Overwrites are silent. Running code:models without --table or --path rewrites every model in place. If you have added accessors, scopes, or relationships by hand, they are gone. --backup mitigates but does not prevent. Always scope to a table or a scratch path until you trust the workflow.

Relations only exist if foreign keys exist. No FK constraint → no belongsTo/hasMany. In MySQL be aware of engine/FOREIGN_KEY_CHECKS history; in SQLite FKs are often declared but off. Inspect generated relation methods against information_schema before assuming completeness.

Pivot detection is heuristic. Many-to-many is inferred from table naming and column shape. It will occasionally emit a belongsToMany where you wanted two hasManys, or pick the wrong related model on ambiguous names. Fix by hand and re-generate only per-table from then on.

Timestamps are name-based. --no-timestamps is needed for tables without created_at/updated_at, and nonstandard names (e.g. created/modified) require --no-timestamps plus manual const CREATED_AT. --date-format only helps if your column format is uniform.

Nullable and default values can be lossy. Generated $fillable doesn't encode nullability; @property docblocks reflect column type but not ?. If you rely on static analysis (PHPStan/Larastan), review the docblocks or regenerate with a tightened base class.

Enum and JSON columns. Depending on DBAL version, native MySQL ENUM may surface as string or throw during type mapping; JSON may not get a $casts entry. Add casts manually and expect to lose them on the next regeneration of that table.

Large schemas. Generate per-connection and per-table for big databases; a single full run introspects everything in memory and is slow against remote DBs. Run it against a schema:dump-loaded local copy when possible.

Extension points are thin. There are no custom stubs or post-generation hooks. The practical extension pattern is: custom base model via config, plus your own thin Artisan command that shells out to code:models --path=... and then applies a post-processing pass (adding traits, rewriting $fillable, running php-cs-fixer). If you need more than that, vendor the package and edit the model template directly.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin