liar88828 / laravel-schema-attributes
PHP 8 attribute-driven schema compiler for Laravel. One schema class drives migrations, models, factories, controllers, and tests — no duplication.
Package info
github.com/liar88828/laravel-schema-attributes
pkg:composer/liar88828/laravel-schema-attributes
Requires
- php: ^8.2
- illuminate/console: ^11.0|^12.0
- illuminate/database: ^11.0|^12.0
- illuminate/filesystem: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
- spatie/laravel-route-attributes: ^1.0
Requires (Dev)
- laravel/pint: ^1.29
- orchestra/testbench: ^9.0
- phpunit/phpunit: ^11.0
README
PHP 8 attribute-driven schema compiler for Laravel. One schema class drives everything — migrations, models, factories, controllers, and tests with no duplication.
Reverse Engineering Existing Migrations
Already have a Laravel project with migrations? Import them as schemas with one command:
# Scan all migrations → generate schema classes in app/Schema/ php artisan schema:scan # Scan a specific table php artisan schema:scan create_orders_table # Generate migration-only schemas (no EloquentModel) php artisan schema:scan --migration # Generate full schemas with EloquentModel php artisan schema:scan --model # Print to console instead of writing files php artisan schema:scan --print # Overwrite existing schemas php artisan schema:scan --force
Example — given this migration:
Schema::create('orders', function (Blueprint $table) { $table->id(); $table->foreignId('user_id')->constrained()->cascadeOnDelete(); $table->string('status', 20)->default('pending')->index(); $table->decimal('total', 10, 2); $table->timestamps(); $table->softDeletes(); });
Generated OrderSchema.php:
#[EloquentModel(model: Order::class)] #[Table(name: 'orders', timestamps: true, softDeletes: true)] class OrderSchema { #[PrimaryKey(type: 'bigIncrements')] public int $id; #[Column(type: 'unsignedBigInteger', index: true)] #[ForeignKey(references: 'id', on: 'users', onDelete: 'cascade')] // #[BelongsTo(related: UserSchema::class)] ← set the related schema // #[Fillable] public int $user_id; #[Column(type: 'string', length: 20, default: 'pending', index: true)] // #[Fillable] public string $status; #[Column(type: 'decimal', precision: 10, scale: 2)] // #[Fillable] public float $total; }
After scanning, review the generated schemas and uncomment/add
#[Fillable],#[Required],#[Hidden],#[Cast]as needed.
Concept
#[EloquentModel(model: Article::class)] #[Table(name: 'articles', timestamps: true, softDeletes: true)] class ArticleSchema { #[PrimaryKey(type: 'bigIncrements')] public int $id; #[Column(type: 'string', length: 191)] #[Fillable] #[Required] #[Min(2)] #[Max(191)] public string $title; #[Column(type: 'unsignedBigInteger')] #[ForeignKey(references: 'id', on: 'users', onDelete: 'cascade')] #[BelongsTo(related: UserSchema::class)] public int $user_id; }
Then run one command to generate everything:
php artisan schema:refresh ArticleSchema
This generates:
- ✅ Migration
- ✅ Eloquent model with
$fillable,$hidden,$casts, relations - ✅ Factory with correct Faker calls
- ✅ PHPUnit test covering migration, model wiring, validation, persistence
- ✅ API controller with validation, Auth injection, soft delete & restore
Installation
composer require liar88828/laravel-schema-attributes
Laravel auto-discovers the service provider. No manual registration needed.
Artisan Commands
| Command | Description |
|---|---|
schema:make ArticleSchema |
Create a new schema class |
schema:scan |
Reverse-engineer existing migrations → schema classes |
schema:migrate ArticleSchema |
Generate migration |
schema:model ArticleSchema |
Generate Eloquent model |
schema:relations ArticleSchema |
Generate relation methods |
schema:factory ArticleSchema |
Generate factory |
schema:service ArticleSchema |
Generate Service layer class |
schema:controller ArticleSchema |
Generate API controller |
schema:test ArticleSchema |
Generate PHPUnit test |
schema:refresh ArticleSchema |
Generate all of the above |
Available Attributes
Migration
#[Table] #[Column] #[PrimaryKey] #[ForeignKey] #[ForeignSchema]
#[HasOne] #[HasMany] #[BelongsTo] #[BelongsToMany]
Model
#[EloquentModel] #[Fillable] #[Hidden] #[Cast] #[Appended] #[UsesSchema]
Validation
#[Required] #[Email] #[Min] #[Max] #[In] #[Unique] #[Uuid]
#[Confirmed] #[Regex] #[Numeric]
Auth Model Example
use Illuminate\Foundation\Auth\User; use Illuminate\Notifications\Notifiable; use Laravel\Fortify\TwoFactorAuthenticatable; #[EloquentModel( model: UserModel::class, extend: User::class, traits: [Notifiable::class, TwoFactorAuthenticatable::class], )] #[Table(name: 'users', timestamps: true, softDeletes: true)] class UserSchema { #[Column(type: 'string', length: 191, unique: true)] #[Fillable] #[Required] #[Email] #[Unique(table: 'users', column: 'email')] public string $email; #[Column(type: 'string')] #[Fillable] #[Hidden] #[Cast('hashed')] #[Required] #[Confirmed] public string $password; #[Column(type: 'rememberToken')] #[Hidden] public ?string $remember_token = null; }
HasSchema Trait
Adding use HasSchema to your model gives you:
// Schema-driven validation User::schemaValidateOrFail($request->all()); // Update validation (ignores own unique fields) $user->schemaValidateForUpdate($request->all(), ignoreUniqueFor: ['email' => $user->id]); // Auto $fillable, $hidden, $casts, $table from schema // UUID primary key auto-generation // Relation resolution from schema annotations
Authors & Credits
This package was entirely created by AI.
| Role | AI |
|---|---|
| Code & Architecture | Claude (Anthropic) |
| Helper & Consultation | ChatGPT (OpenAI) |
| Human Supervisor | liar88828 |
💡 This is an experiment in AI-driven open source development. Every line of code, architecture decision, bug fix, and this README was written by AI assistants guided by a human developer.
- PHP 8.2+
- Laravel 11 or 12
- spatie/laravel-route-attributes — installed automatically
spatie/laravel-route-attributes is a lightweight package (~50KB) that only depends on illuminate/routing which Laravel already includes. If your project already has any Spatie package installed, there is zero additional cost.
License
MIT — see LICENSE.