DEV Community

Cover image for Unlock Laravel Code Generation (Part 3): Automating Validation from Your Database Schema 🤯🚀
AdriánColom
AdriánColom

Posted on

Unlock Laravel Code Generation (Part 3): Automating Validation from Your Database Schema 🤯🚀

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,
    ]);
}
Enter fullscreen mode Exit fullscreen mode

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
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

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}}
        ];
    }
}
Enter fullscreen mode Exit fullscreen mode

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}");
    }
}
Enter fullscreen mode Exit fullscreen mode

How It Works:

  1. Load the JSON: We retrieve our table’s schema file (e.g., categories.json).

  2. Parse Columns: Each column is analyzed to see if it’s nullable or has a varchar(x) type.

  3. Build a Rule String: For instance, a non-nullable varchar(255) becomes required|string|max:255.

  4. Inject into Stub: The placeholder {{validationRules}} is replaced with the built rule strings.

  5. 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)