changeset 45:c7fd31303024 default tip

merging down to default
author Luka Sitas <sitas.luka.97@gmail.com>
date Thu, 12 Nov 2026 21:19:53 -0500
parents f65ab84ee47f (current diff) cde7e0f145fa (diff)
children
files
diffstat 16 files changed, 614 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/.vimrc	Wed Sep 10 21:00:47 2025 -0400
+++ b/.vimrc	Thu Nov 12 21:19:53 2026 -0500
@@ -11,6 +11,11 @@
 nnoremap <C-l> :ALECodeAction <cr>
 set mouse=a
 
+function! GeneratePhpCtags()
+	let command = 'ctags -R --fields=+aimS --php-kinds=cdfint --languages=php --extras=+q --tag-relative=yes --exclude=".git" --exclude=".hg" --exclude="node_modules" --exclude="composer.phar" --totals=yes'
+	let output = system(command)
+endfunction
+
 function! FixPhpFiles()
  " Save the current cursor position
   let save_cursor = getpos(".")
--- a/src/Generator/Controller/stubs/controller.stub	Wed Sep 10 21:00:47 2025 -0400
+++ b/src/Generator/Controller/stubs/controller.stub	Thu Nov 12 21:19:53 2026 -0500
@@ -16,20 +16,19 @@
      */
     public function index({{ filterRequest }} $request)
     {
-				$validated = $request->validated();
+		$validated = $request->validated();
         $data = [];
-        $data['items'] = {{ model }}::get_data($validated);
-				$data = array_merge($data, {{ model }}::load_index());
+		$data = array_merge($data, {{ model }}::load_index());
 
         return view('{{ tableName }}.index', $data);
     }
 
-    public function get_data()
+    public function get_data({{ filterRequest }} $request)
     {
+        $validated = $request->validated() ?? [];
         $data = [];
-        $data['records'] = {{ model }}::get_data([]);
-        $data['total_records'] = count($data['records']);
 
+        $data = array_merge($data, {{ model }}::get_data($validated));
         return $data;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Generator/Factory/FactoryGenerator.php	Thu Nov 12 21:19:53 2026 -0500
@@ -0,0 +1,158 @@
+<?php
+
+namespace Wizard\MagicForger\Generator\Factory;
+
+use Illuminate\Support\Str;
+use Symfony\Component\Console\Attribute\AsCommand;
+use Wizard\MagicForger\Generator\BaseGenerator;
+use Wizard\MagicForger\Helpers\RelationshipNavigator;
+
+#[AsCommand(name: 'mf:factory')]
+class FactoryGenerator extends BaseGenerator
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $name = 'mf:factory';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'Generates the Factory File for a table.';
+
+    /**
+     * The type of class being generated.
+     *
+     * @var string
+     */
+    protected $type = 'Factory';
+
+    protected static $cached_snippets = [];
+
+    /**
+     * Execute the console command.
+     *
+     * @return mixed
+     */
+    public function handle()
+    {
+        // Delegate to parent handler (includes replacements and insertions)
+        return parent::handle();
+    }
+
+    /**
+     * Get the stub file for the generator.
+     *
+     * @return string
+     */
+    protected function getStub()
+    {
+        return $this->resolveStubPath('/stubs/factory.stub');
+    }
+
+    /**
+     * Resolve the fully-qualified path to the stub.
+     *
+     * @param  string  $stub
+     * @return string
+     */
+    protected function resolveStubPath($stub)
+    {
+        return is_file($customPath = $this->laravel->basePath(trim($stub, '/')))
+            ? $customPath
+            : __DIR__.$stub;
+    }
+
+    protected function getClassName($name)
+    {
+        return $this->factory_name($name);
+    }
+
+    /**
+     * Get the stub file for the generator.
+     *
+     * @return string
+     */
+    protected function getPath($name = null)
+    {
+        return str_replace(['App\\', '\\'], ['app/', '/'], $this->getFactoryNamespace().'/'.$this->factory_name($this->getTableInput()).'.php');
+    }
+
+    protected function gatherRelations()
+    {
+        $relations = RelationshipNavigator::getRelations($this->getCurrentTable());
+        foreach ($relations as $relation_type => $relation_values) {
+            $relations[$relation_type] = array_column($relation_values, null, 'column');
+        }
+
+        return $relations;
+    }
+
+    protected function renderColumns()
+    {
+        $values = [];
+        $relations = $this->gatherRelations();
+
+        foreach ($this->get_columns() as $column) {
+            if (in_array($column['name'], $this->columns_to_ignore)) {
+                continue;
+            }
+
+            $value = $this->getFakeValue($column, $relations);
+            $snippet = $this->getSnippet('value');
+
+            // Replace placeholders with actual values
+            $values[] = str_replace(['{{value}}', '{{column_name}}'], [$value, $column['name']], $snippet);
+        }
+
+        return implode("\n", $values);
+    }
+
+    protected function getFakeValue($column, $relations)
+    {
+        $value = '$this->faker';
+        $nullable = ($column['nullable'] ? '->optional($weight = 0.5)' : '');
+
+        switch ($column['type_name']) {
+            case 'date':
+                return "$value${nullable}->date()";
+            case 'timestamp':
+                return "$value${nullable}->timestamp()";
+            case 'tinyint':
+                return "$value${nullable}->numberBetween(0,1)";
+            case 'bigint':
+                if (isset($relations['belongsTo'][$column['name']])) {
+                    $related = $this->getNamespacedModel($relations['belongsTo'][$column['name']]['table']);
+                    return "$related::factory()";
+                }
+                // fall through to int for lack of better option
+            case 'int':
+                return "$value${nullable}->randomNumber()";
+            case 'float':
+                return "$value${nullable}->randomFloat()";
+            default:
+                return "$value${nullable}->text()";
+        }
+    }
+
+    /**
+     * Get available insertions including model relationships.
+     */
+    public function get_available_inserts(): array
+    {
+        // Merge parent insertions (attributes, fillable, etc.)
+        $inserts = parent::get_available_inserts();
+
+        // Gather and render relationships for this model
+        $columns = $this->renderColumns();
+
+        // Assign to stub placeholders
+        $inserts['# {{ factoryInsertPoint }}'] = $columns;
+
+        return $inserts;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Generator/Factory/snippets/value.stub	Thu Nov 12 21:19:53 2026 -0500
@@ -0,0 +1,1 @@
+'{{column_name}}' => {{value}},
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Generator/Factory/stubs/factory.stub	Thu Nov 12 21:19:53 2026 -0500
@@ -0,0 +1,35 @@
+<?php
+
+namespace Database\Factories;
+
+use {{ namespacedModel }};
+use Illuminate\Database\Eloquent\Factories\Factory;
+use Illuminate\Support\Facades\Hash;
+use Illuminate\Support\Str;
+
+/**
+ * @extends \Illuminate\Database\Eloquent\Factories\Factory<{{ namespacedModel }}>
+ */
+class {{ class }} extends Factory
+{
+
+		/**
+     * The name of the factory's corresponding model.
+     *
+     * @var class-string<\Illuminate\Database\Eloquent\Model>
+     */
+    protected $model = {{ model }}::class;
+
+    /**
+     * Define the model's default state.
+     *
+     * @return array<string, mixed>
+     */
+    public function definition(): array
+    {
+        return [
+						# {{ factoryInsertPoint }}
+        ];
+    }
+
+}
--- a/src/Generator/Generator.php	Wed Sep 10 21:00:47 2025 -0400
+++ b/src/Generator/Generator.php	Thu Nov 12 21:19:53 2026 -0500
@@ -41,7 +41,7 @@
         /* dd($this->getCurrentTable()->getForeignKeys()); */
 
         if ($this->option('all')) {
-            /* $this->input->setOption('factory', true); */
+            $this->input->setOption('factory', true);
             /* $this->input->setOption('seed', true); */
             /* $this->input->setOption('migration', true); */
             $this->input->setOption('controller', true);
@@ -49,11 +49,12 @@
             $this->input->setOption('request', true);
             $this->input->setOption('view', true);
             $this->input->setOption('route', true);
+            $this->input->setOption('test', true);
         }
 
-        /* if ($this->option('factory')) { */
-        /*     $this->createFactory(); */
-        /* } */
+        if ($this->option('factory')) {
+            $this->createFactory();
+        }
 
         /* if ($this->option('migration')) { */
         /*     $this->createMigration(); */
@@ -82,6 +83,10 @@
         if ($this->option('route')) {
             $this->createRoute();
         }
+
+        if ($this->option('test')) {
+            $this->createTest();
+        }
     }
 
     /**
@@ -96,6 +101,8 @@
             ['request', 'r', InputOption::VALUE_NONE, 'Generate base request classes for the table.'],
             ['view', '', InputOption::VALUE_NONE, 'Generate base views for the table.'],
             ['route', 'w', InputOption::VALUE_NONE, 'Generate base routes classes for the table.'],
+            ['factory', 'F', InputOption::VALUE_NONE, 'Generate base factory classes for the table.'],
+            ['test', 't', InputOption::VALUE_NONE, 'Generate base test classes for the table.'],
         ]);
     }
 
@@ -130,4 +137,14 @@
     {
         $this->call('mf:route', ['table' => $this->getTableInput(), '--fresh' => $this->option('fresh')]);
     }
+
+    protected function createFactory()
+    {
+        $this->call('mf:factory', ['table' => $this->getTableInput(), '--fresh' => $this->option('fresh')]);
+    }
+
+    protected function createTest()
+    {
+        $this->call('mf:test', ['table' => $this->getTableInput(), '--fresh' => $this->option('fresh')]);
+    }
 }
--- a/src/Generator/Model/stubs/model.stub	Wed Sep 10 21:00:47 2025 -0400
+++ b/src/Generator/Model/stubs/model.stub	Thu Nov 12 21:19:53 2026 -0500
@@ -2,12 +2,14 @@
 
 namespace {{ namespace }};
 
+use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\SoftDeletes;
 use Wizard\Framework\Models\BaseModel;
 
 class {{ class }} extends BaseModel
 {
-    //use HasFactory;
+		/** @use HasFactory<\Database\Factories\{{ class }}Factory> */
+    use HasFactory;
     use SoftDeletes;
 
     /**
@@ -38,6 +40,13 @@
 			# {{ defaultRelationsInsertPoint }}
 		];
 
+		public static function named_joins() {
+			$joins = [
+				//
+			];
+			return parent::named_joins();
+		}
+
 		protected static $filters = [
 			# {{ defaultFiltersInsertPoint }}
 		];
--- a/src/Generator/Requests/FilterRequestGenerator.php	Wed Sep 10 21:00:47 2025 -0400
+++ b/src/Generator/Requests/FilterRequestGenerator.php	Thu Nov 12 21:19:53 2026 -0500
@@ -44,7 +44,7 @@
      */
     protected function getStub()
     {
-        return $this->resolveStubPath('/stubs/request.stub');
+        return $this->resolveStubPath('/stubs/filter_request.stub');
     }
 
     /**
@@ -74,4 +74,19 @@
     {
         return str_replace(['App\\', '\\'], ['app/', '/'], $this->getRequestNamespace($this->getTableInput()).'/'.$this->filter_request_name($this->getTableInput()).'.php');
     }
+
+    /**
+     * Get available insertions including model relationships.
+     *
+     * @return array
+     */
+    public function get_available_inserts(): array
+    {
+        // Merge parent insertions (attributes, fillable, etc.)
+        $inserts = parent::get_available_inserts();
+
+		$inserts['// {{ valuesForValidation }}'] = str_replace("'required'", "'nullable'", $inserts['// {{ valuesForValidation }}']);
+
+        return $inserts;
+    }
 }
--- a/src/Generator/Requests/RequestGenerator.php	Wed Sep 10 21:00:47 2025 -0400
+++ b/src/Generator/Requests/RequestGenerator.php	Thu Nov 12 21:19:53 2026 -0500
@@ -90,16 +90,16 @@
 
     protected function createFilterRequest()
     {
-        $this->call('mf:filter_request', ['table' => $this->getTableInput()]);
+        $this->call('mf:filter_request', ['table' => $this->getTableInput(), '--fresh' => $this->option('fresh')]);
     }
 
     protected function createStoreRequest()
     {
-        $this->call('mf:store_request', ['table' => $this->getTableInput()]);
+        $this->call('mf:store_request', ['table' => $this->getTableInput(), '--fresh' => $this->option('fresh')]);
     }
 
     protected function createUpdateRequest()
     {
-        $this->call('mf:update_request', ['table' => $this->getTableInput()]);
+        $this->call('mf:update_request', ['table' => $this->getTableInput(), '--fresh' => $this->option('fresh')]);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Generator/Requests/stubs/filter_request.stub	Thu Nov 12 21:19:53 2026 -0500
@@ -0,0 +1,33 @@
+<?php
+
+namespace {{ namespace }};
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class {{ class }} extends FormRequest
+{
+    /**
+     * Determine if the user is authorized to make this request.
+     */
+    public function authorize(): bool
+    {
+        return true;
+    }
+
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
+     */
+    public function rules(): array
+    {
+        return [
+            'filters' => [
+                // {{ valuesForValidation }} 
+            ],
+            'page' => ['nullable', 'int', 'min:0'],
+            'page_size' => ['nullable', 'int', 'min:0'],
+            'sort' => ['nullable', 'array'],
+        ];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Generator/Test/TestGenerator.php	Thu Nov 12 21:19:53 2026 -0500
@@ -0,0 +1,79 @@
+<?php
+
+namespace Wizard\MagicForger\Generator\Test;
+
+use Symfony\Component\Console\Attribute\AsCommand;
+use Wizard\MagicForger\Generator\BaseGenerator;
+use Wizard\MagicForger\Replacer;
+use Illuminate\Support\Str;
+
+#[AsCommand(name: 'mf:test')]
+class TestGenerator extends BaseGenerator
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $name = 'mf:test';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'Generates the Test File for a table.';
+
+    /**
+     * The type of class being generated.
+     *
+     * @var string
+     */
+    protected $type = 'Test';
+
+    /**
+     * Execute the console command.
+     */
+    public function handle()
+    {
+			parent::handle();
+    }
+
+    /**
+     * Get the stub file for the generator.
+     *
+     * @return string
+     */
+    protected function getStub()
+    {
+        return $this->resolveStubPath('/stubs/test.stub');
+    }
+
+    /**
+     * Resolve the fully-qualified path to the stub.
+     *
+     * @param  string  $stub
+     * @return string
+     */
+    protected function resolveStubPath($stub)
+    {
+        return is_file($customPath = $this->laravel->basePath(trim($stub, '/')))
+            ? $customPath
+            : __DIR__.$stub;
+    }
+
+    protected function getClassName($name)
+    {
+        return $this->test_name($name);
+    }
+
+    /**
+     * Get the stub file for the generator.
+     *
+     * @return string
+     */
+    protected function getPath($name = null)
+    {
+        return str_replace(['App\\', '\\'], ['app/', '/'], $this->getTestNamespace() . '/' . $this->test_name($this->getTableInput()) . '.php');
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Generator/Test/stubs/test.stub	Thu Nov 12 21:19:53 2026 -0500
@@ -0,0 +1,128 @@
+<?php
+
+namespace Tests\CRUD;
+
+use {{ namespacedModel }};
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use App\Models\User;
+use Wizard\Framework\Tests\TestCase;
+
+class {{ class }} extends TestCase
+{
+    /* use RefreshDatabase; */
+
+    public function test_{{ modelVariable }}_crud_index_access(): void
+    {
+        $response = $this
+					->get(route('{{ tableName }}.index'));
+
+        $response->assertStatus(200);
+    }
+
+    public function test_{{ modelVariable }}_crud_get_data_access(): void
+    {
+        $response = $this
+					->post(route('{{ tableName }}.get_data'));
+
+        $response->assertStatus(200);
+    }
+
+    public function test_{{ modelVariable }}_crud_create_access(): void
+    {
+				$response = $this
+					->get(route('{{ tableName }}.create'));
+
+        $response->assertStatus(200);
+    }
+
+    public function test_{{ modelVariable }}_crud_edit_access(): void
+    {
+		$item = {{ model }}::factory()->create();
+
+        $response = $this
+					->get(route('{{ tableName }}.edit', $item));
+
+        $response->assertStatus(200);
+    }
+
+    public function test_{{ modelVariable }}_crud_create_usage(): void
+    {
+        $item = {{ model }}::factory()->make();
+
+        $response = $this
+            ->from(route('{{ tableName }}.create'))
+            ->post(route('{{ tableName }}.store'),
+                $item->toArray()
+            );
+
+        $response
+            ->assertSessionHasNoErrors()
+            ->assertRedirect(route('{{ tableName }}.index'));
+
+        $this->assertDatabaseHas('{{ tableName }}', $item->toArray());
+    }
+
+   public function test_{{ modelVariable }}_crud_create_invalid_data(): void
+   {
+       $response = $this
+           ->from(route('{{ tableName }}.create'))
+           ->post(route('{{ tableName }}.store'), []);
+
+       $response
+           ->assertSessionHasErrors()
+           ->assertRedirect(route('{{ tableName }}.create'));
+
+       // Make sure no entry was added
+       $this->assertDatabaseCount('{{ tableName }}', 0);
+   }
+
+   public function test_{{ modelVariable }}_crud_update_usage(): void
+   {
+       $item = {{ model }}::factory()->create();
+
+       $updateData = {{ model }}::factory()->make()->toArray();
+
+       $response = $this
+           ->from(route('{{ tableName }}.edit', $item))
+           ->put(route('{{ tableName }}.update', $item), $updateData);
+
+       $response
+           ->assertSessionHasNoErrors()
+           ->assertRedirect(route('{{ tableName }}.index'));
+
+       $this->assertDatabaseHas('{{ tableName }}', $updateData);
+   }
+
+   public function test_{{ modelVariable }}_crud_edit_invalid_data(): void
+   {
+       $item = {{ model }}::factory()->create();
+
+       $response = $this
+           ->from(route('{{ tableName }}.edit', $item))
+           ->put(route('{{ tableName }}.update', $item), []);
+
+       $response
+           ->assertSessionHasErrors()
+           ->assertRedirect(route('{{ tableName }}.edit', $item));
+
+       // Make sure no entry was added
+       $this->assertDatabaseHas('{{ tableName }}', array_intersect_key($item->toArray(), array_flip($item->getFillable())));
+   }
+
+   public function test_{{ modelVariable }}_crud_delete_usage(): void
+   {
+       $item = {{ model }}::factory()->create();
+
+       $response = $this
+           ->delete(route('{{ tableName }}.destroy', $item));
+
+       $response
+           ->assertSessionHasNoErrors()
+           ->assertRedirect(route('{{ tableName }}.index'));
+
+       $this->assertSoftDeleted('{{ tableName }}', [
+           'id' => $item->id,
+       ]);
+   }
+
+}
--- a/src/Generator/View/stubs/index.stub	Wed Sep 10 21:00:47 2025 -0400
+++ b/src/Generator/View/stubs/index.stub	Thu Nov 12 21:19:53 2026 -0500
@@ -28,6 +28,7 @@
             if (el) {
                 new ServerTable(el, {
                     endpoint: '/{{ tableName }}/get_data',
+                    filters: Object.fromEntries(new URLSearchParams(location.search)),
                     columns: [
             	        {{ columnInsertPoint }}
                         {
--- a/src/MagicForgerServiceProvider.php	Wed Sep 10 21:00:47 2025 -0400
+++ b/src/MagicForgerServiceProvider.php	Thu Nov 12 21:19:53 2026 -0500
@@ -5,12 +5,14 @@
 use Illuminate\Support\ServiceProvider;
 use Wizard\MagicForger\Generator\Controller\ControllerGenerator;
 use Wizard\MagicForger\Generator\Generator;
+use Wizard\MagicForger\Generator\Factory\FactoryGenerator;
 use Wizard\MagicForger\Generator\Model\ModelGenerator;
 use Wizard\MagicForger\Generator\Requests\RequestGenerator;
 use Wizard\MagicForger\Generator\Requests\FilterRequestGenerator;
 use Wizard\MagicForger\Generator\Requests\StoreRequestGenerator;
 use Wizard\MagicForger\Generator\Requests\UpdateRequestGenerator;
 use Wizard\MagicForger\Generator\Route\RouteGenerator;
+use Wizard\MagicForger\Generator\Test\TestGenerator;
 use Wizard\MagicForger\Generator\View\ViewGenerator;
 use Wizard\MagicForger\Generator\View\IndexViewGenerator;
 use Wizard\MagicForger\Generator\View\CreateEditViewGenerator;
@@ -37,6 +39,8 @@
                 IndexViewGenerator::class,
                 CreateEditViewGenerator::class,
                 ShowViewGenerator::class,
+								FactoryGenerator::class,
+								TestGenerator::class,
             ]);
         }
 
--- a/src/Replacer/Replacer.php	Wed Sep 10 21:00:47 2025 -0400
+++ b/src/Replacer/Replacer.php	Thu Nov 12 21:19:53 2026 -0500
@@ -157,6 +157,22 @@
         return Str::singular(Str::studly($name));
     }
 
+    /**
+     * Generate factory name in Studly case.
+     */
+    public function factory_name(string $name): string
+    {
+        return Str::singular(Str::studly($name)) . 'Factory';
+    }
+
+    /**
+     * Generate test name in Studly case.
+     */
+    public function test_name(string $name): string
+    {
+        return Str::singular(Str::studly($name)) . 'Test';
+    }
+
     // Namespace Methods
     // These methods handle the formation of various namespaces used within the replacements.
 
@@ -267,6 +283,24 @@
         return $this->getViewNamespace($name) . '\\';
     }
 
+    /**
+     * Get the factory namespace.
+     */
+    public function getFactoryNamespace(string $name = ''): string
+    {
+        return database_path()
+				. DIRECTORY_SEPARATOR . 'factories' ;
+    }
+
+    /**
+     * Get the test namespace.
+     */
+    public function getTestNamespace(string $name = ''): string
+    {
+        return base_path()
+				. DIRECTORY_SEPARATOR . 'tests' 
+				. DIRECTORY_SEPARATOR . 'CRUD' ;
+    }
 
     /**
      * Get the request uses string for replacement.
--- a/src/Replacer/TableReplacer.php	Wed Sep 10 21:00:47 2025 -0400
+++ b/src/Replacer/TableReplacer.php	Thu Nov 12 21:19:53 2026 -0500
@@ -51,15 +51,15 @@
             if (in_array($column['name'], $this->columns_to_ignore)) {
                 continue;
             }
-						$type = $column['type_name'];
-						//date
-						if(in_array($type, ['date'])) {
-							$insert .= sprintf("'%s' => 'date:Y-m-d',", $column['name'])."\n";
-						}
-						//time
-						if(in_array($type, ['timestamp'])) {
-							$insert .= sprintf("'%s' => 'date:Y-m-d H:i',", $column['name'])."\n";
-						}
+            $type = $column['type_name'];
+            // date
+            if (in_array($type, ['date'])) {
+                $insert .= sprintf("'%s' => 'date:Y-m-d',", $column['name'])."\n";
+            }
+            // time
+            if (in_array($type, ['timestamp'])) {
+                $insert .= sprintf("'%s' => 'date:Y-m-d H:i',", $column['name'])."\n";
+            }
         }
 
         return $insert;
@@ -104,10 +104,81 @@
     {
         $insert = '';
         foreach ($this->get_columns() as $column) {
+            // Don't do validation on some of the basic columns
             if (in_array($column['name'], $this->columns_to_ignore)) {
                 continue;
             }
-            $insert .= sprintf("'%s' => 'nullable',", $column['name'])."\n";
+
+            $options = [];
+
+            // Add default value checks if needed
+            if (/*is_null($column['default']) && */! $column['nullable']) {
+                $options[] = "'required'";
+            }
+            else {
+                $options[] = "'nullable'";
+            }
+
+            // Determine the validations based on column type
+            $type = strtolower($column['type_name']);
+            $size = (preg_match('/\((\d+)\)/', $column['type'], $matches)) ? $matches[1] : null;
+
+            switch ($type) {
+                case 'varchar':
+                case 'char':
+                    $options[] = "'string'";
+
+                    // Extract length if defined
+                    if (! is_null($size)) {
+                        $options[] = "'max:$size'";
+                    }
+                    break;
+
+                case 'text':
+                    $options[] = "'string'";
+                    break;
+
+                case 'int':
+                case 'tinyint':
+                case 'smallint':
+                case 'mediumint':
+                case 'bigint':
+                    $options[] = "'integer'";
+                    if (strpos($column['type'], 'unsigned') !== false) {
+                        $options[] = "'min:0'";
+                    }
+                    if (! is_null($size)) {
+                        $options[] = "'max_digits:".$size."'";
+                    }
+                    break;
+
+                case 'decimal':
+                case 'double':
+                case 'float':
+                    $options[] = "'numeric'";
+                    // Extract precision and scale if defined
+                    if (preg_match('/\((\d+),(\d+)\)/', $column['type'], $matches)) {
+                        $precision = $matches[1];
+                        $scale = isset($matches[2]) ? ','.$matches[2] : '';
+
+                        $options[] = "'decimal:$precision$scale'";
+                    }
+                    break;
+
+                case 'boolean':
+                    $options[] = "'boolean'";
+                    break;
+
+                case 'date':
+                case 'datetime':
+                case 'timestamp':
+                    $options[] = "'date'";
+                    break;
+
+                    // Add other types as needed
+            }
+
+            $insert .= sprintf("'%s' => [%s],\n", $column['name'], implode(',', $options));
         }
 
         return $insert;