In previous posts, we’ve explored using Laravel stubs to streamline code generation. In this installment, we’ll zoom in on a specific example: automatically creating validation rules for your models by extracting metadata from your database schema.
Ready to supercharge your Laravel development? Let’s dive in!
Why Automate Code Generation?
Building code by hand — especially boilerplate like CRUD and validation — is time-consuming, repetitive, and prone to human error. When you integrate automation into your workflow, you:
Stay in Sync: Whenever you add or remove columns from your database, you can regenerate code with a single command.
Improve Consistency: Every generated file follows a uniform structure and coding standard.
Reduce Manual Labor: Focus on your application’s unique features, not on repetitive tasks.
TIME: Reduce repetitive boilerplate when adding or modifying columns.
Extracting Your Database Schema
The first step in this automation journey is extracting your database schema. We want to transform our table definitions into a JSON file — a format that’s easy to read, modify, and feed into a code generation process.
Extracting the Schema into JSON
The first step is to pull table information — like columns and indexes — into a JSON file. Below is a minimal snippet (from a larger TableUtils
class that I use in my bigger project, follow me for future projects and updates!) that demonstrates capturing columns for a given table:
// TableUtils snippet
public function getTableInfo(): Collection
{
// Ensure the table exists
if (!Schema::hasTable($this->table)) {
throw new \Exception("Table {$this->table} not found");
}
$columns = Schema::getColumns($this->table);
return collect([
'model' => Str::studly(Str::singular($this->table)),
'table' => $this->table,
'columns' => $columns,
]);
}
You then convert this collection to JSON and save it to a file — say, schema/categories.json
. ( For not do the query all the time )
{
"model": "Category",
"table": "categories",
"columns": [
{
"name": "id",
"type": "bigint(20) unsigned",
"nullable": false
},
{
"name": "name",
"type": "varchar(255)",
"nullable": false
},
{
"name": "created_at",
"type": "timestamp",
"nullable": true
},
{
"name": "updated_at",
"type": "timestamp",
"nullable": true
}
]
}
Minimal Form Request Stub
Next, we create a tiny stub representing a Form Request in Laravel that we learned to do in the first part:
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class Store{{modelName}}Request extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
{{validationRules}}
];
}
}
Generating the Validation Rules Automatically
Here’s a small command that reads the JSON, analyzes each column, and injects an appropriate validation rule into the stub, we learned to combine the stub and the command in the part 2:
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
class GenerateValidation extends Command
{
protected $signature = 'generate:validation {table}';
protected $description = 'Generates a Form Request validation file from a table schema JSON';
public function handle()
{
$table = $this->argument('table');
$schemaPath = base_path("schema/{$table}.json");
if (! File::exists($schemaPath)) {
$this->error("Schema JSON for table [{$table}] not found at: {$schemaPath}");
return;
}
// Load the schema
$schema = json_decode(File::get($schemaPath), true);
// Load our stub
$validationStub = File::get(base_path('stubs/validation.stub'));
// Build rules based on columns
$rules = collect($schema['columns'])->map(function ($column) {
$ruleParts = [];
// Required or nullable
$ruleParts[] = $column['nullable'] ? 'nullable' : 'required';
// Quick example for strings
if (preg_match('/varchar\((\d+)\)/', $column['type'], $matches)) {
$maxLength = $matches[1];
$ruleParts[] = 'string';
$ruleParts[] = "max:{$maxLength}";
}
// Could expand for other types (e.g., integer, date)
return "'{$column['name']}' => '" . implode('|', $ruleParts) . "'";
})->implode(",\n ");
// Insert the rules into the stub
$validationStub = str_replace('{{modelName}}', $schema['model'], $validationStub);
$validationStub = str_replace('{{validationRules}}', $rules, $validationStub);
// Save to app/Http/Requests
$filename = "Store{$schema['model']}Request.php";
File::put(app_path("Http/Requests/{$filename}"), $validationStub);
$this->info("Validation file for [{$schema['model']}] created: {$filename}");
}
}
How It Works:
Load the JSON: We retrieve our table’s schema file (e.g.,
categories.json
).Parse Columns: Each column is analyzed to see if it’s nullable or has a
varchar(x)
type.Build a Rule String: For instance, a non-nullable
varchar(255)
becomesrequired|string|max:255
.Inject into Stub: The placeholder
{{validationRules}}
is replaced with the built rule strings.Generate a File: The final
StoreCategoryRequest.php
is written out, ready to use in your Laravel app.
Why This Matters
Saves Time: You never have to manually type out
required|string|max:255
again.Prevents Errors: Changes to the database propagate to your validation rules at the push of a button.
Easy to Extend: Add logic for integers, dates, or enums — whatever fits your schema.
Looking Ahead
This is just the tip of the iceberg. Once you’re comfortable with automating models, controllers, and validation, you can expand to:
View Generation: Use your schema to generate Blade templates for listing, creating, editing, and viewing records.
API Resources: Automatically build out API controllers, routes, and resource classes based on your schema.
Relationships: Incorporate foreign key data to automatically generate
hasOne
,hasMany
,belongsTo
, etc.
For now, the approach outlined here provides a powerful foundation for automating a large chunk of your Laravel development workflow.
Conclusion
By leveraging your database schema to generate validation rules, you take another step toward a fully automated code generation pipeline. You can apply the same principles to build models, controllers, and more—giving you a robust, scalable, and maintainable development process.
Key Takeaways
Centralize Validation: Keep your form requests always aligned with the actual database.
Minimize Manual Upkeep: Regenerate whenever columns change, letting the script do the heavy lifting.
Extend as Needed: Add rules for more data types (e.g., integer, decimal, date) as your application grows.
With this setup, you’ll never again have to track column changes in multiple places—your database schema becomes the single source of truth. Happy coding, and may all your validations be precise!
P.S. If you’re as excited as I am about this upcoming tool, be sure to subscribe to my newsletter or follow me on social media for the latest updates. Let’s revolutionize Laravel development together!
Top comments (0)