diff src/Generator/Factory/FactoryGenerator.php @ 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 59eb5b4424ca
children
line wrap: on
line diff
--- /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;
+    }
+}