templates = [ 'model' => $this->getModelTemplate(), 'property' => $this->getPropertyTemplate(), 'method' => $this->getMethodTemplate(), 'migration' => $this->getMigrationTemplate(), 'factory' => $this->getFactoryTemplate(), 'seeder' => $this->getSeederTemplate() ]; } public function generate(string $name, array $options = []): bool { if (!$this->validateName($name)) { return false; } $className = $this->getClassName($name); $tableName = $options['table'] ?? $this->getTableName($name); $fields = $options['fields'] ?? []; $timestamps = $options['timestamps'] ?? true; $softDeletes = $options['soft_deletes'] ?? false; $relationships = $options['relationships'] ?? []; $generateMigration = $options['migration'] ?? true; $generateFactory = $options['factory'] ?? false; $generateSeeder = $options['seeder'] ?? false; if (!empty($fields)) { if (is_string($fields)) { $fields = $this->parseFields($fields); } } // 生成模型 $modelContent = $this->generateModel($className, $tableName, $fields, $timestamps, $softDeletes, $relationships); $modelPath = $this->getNamespacePath('Model'); $modelFilePath = $modelPath . '/' . $className . '.php'; if (!$this->createFile($modelFilePath, $modelContent)) { return false; } // 生成迁移文件 if ($generateMigration) { $this->generateMigration($className, $tableName, $fields, $timestamps, $softDeletes); } // 生成工厂文件 if ($generateFactory) { $this->generateFactory($className, $fields); } // 生成种子文件 if ($generateSeeder) { $this->generateSeeder($className); } $this->showMessage('success', "Model '{$className}' generated successfully!"); return true; } private function generateModel(string $className, string $tableName, array $fields, bool $timestamps, bool $softDeletes, array $relationships): string { $useStatements = []; $properties = ''; $methods = ''; // 基础use语句 $useStatements[] = 'use Fendx\\ORM\\Model;'; if ($softDeletes) { $useStatements[] = 'use Fendx\\ORM\\Traits\\SoftDeletes;'; } // 生成属性 foreach ($fields as $field) { $properties .= $this->generateProperty($field); } // 生成关系方法 foreach ($relationships as $relationship) { $methods .= $this->generateRelationshipMethod($relationship); } // 生成访问器和修改器 foreach ($fields as $field) { $methods .= $this->generateAccessorMutator($field); } $useBlock = implode("\n", array_unique($useStatements)) . "\n\n"; return $this->renderTemplate('model', [ 'namespace' => $this->getFullNamespace('Model'), 'use_block' => $useBlock, 'class_name' => $className, 'table_name' => $tableName, 'timestamps' => $timestamps ? 'true' : 'false', 'soft_deletes' => $softDeletes ? 'use SoftDeletes;' : '', 'properties' => $properties, 'methods' => $methods ]); } private function generateProperty(array $field): string { $name = $field['name']; $type = $this->getPhpType($field['type']); $nullable = isset($field['options']['nullable']); $docBlock = $this->generatePropertyDocBlock($field); return $this->renderTemplate('property', [ 'doc_block' => $docBlock, 'property_name' => $name, 'property_type' => $type, 'nullable' => $nullable ? '?' : '' ]); } private function generatePropertyDocBlock(array $field): string { $type = $this->getPhpType($field['type']); $comment = ''; if (isset($field['options']['unique'])) { $comment .= ' (unique)'; } if (isset($field['options']['default'])) { $comment .= ' (default: ' . $field['options']['default'] . ')'; } if (isset($field['options']['nullable'])) { $comment .= ' (nullable)'; } return "/**\n * @var {$type}{$comment}\n */"; } private function generateRelationshipMethod(array $relationship): string { $type = $relationship['type']; $relatedModel = $relationship['model']; $foreignKey = $relationship['foreign_key'] ?? null; $localKey = $relationship['local_key'] ?? null; switch ($type) { case 'hasOne': return $this->generateHasOneMethod($relatedModel, $foreignKey, $localKey); case 'hasMany': return $this->generateHasManyMethod($relatedModel, $foreignKey, $localKey); case 'belongsTo': return $this->generateBelongsToMethod($relatedModel, $foreignKey, $localKey); case 'belongsToMany': return $this->generateBelongsToManyMethod($relatedModel, $foreignKey, $localKey); default: return ''; } } private function generateHasOneMethod(string $relatedModel, ?string $foreignKey, ?string $localKey): string { $methodName = $this->getVariableName($relatedModel); $params = ''; if ($foreignKey) { $params .= ", '{$foreignKey}'"; } if ($localKey) { $params .= ", '{$localKey}'"; } return <<hasOne({$relatedModel}::class{$params}); } PHP; } private function generateHasManyMethod(string $relatedModel, ?string $foreignKey, ?string $localKey): string { $methodName = $this->getPluralName($this->getVariableName($relatedModel)); $params = ''; if ($foreignKey) { $params .= ", '{$foreignKey}'"; } if ($localKey) { $params .= ", '{$localKey}'"; } return <<hasMany({$relatedModel}::class{$params}); } PHP; } private function generateBelongsToMethod(string $relatedModel, ?string $foreignKey, ?string $localKey): string { $methodName = $this->getVariableName($relatedModel); $params = ''; if ($foreignKey) { $params .= ", '{$foreignKey}'"; } if ($localKey) { $params .= ", '{$localKey}'"; } return <<belongsTo({$relatedModel}::class{$params}); } PHP; } private function generateBelongsToManyMethod(string $relatedModel, ?string $foreignKey, ?string $localKey): string { $methodName = $this->getPluralName($this->getVariableName($relatedModel)); $params = ''; if ($foreignKey) { $params .= ", '{$foreignKey}'"; } if ($localKey) { $params .= ", '{$localKey}'"; } return <<belongsToMany({$relatedModel}::class{$params}); } PHP; } private function generateAccessorMutator(array $field): string { $name = $field['name']; $type = $this->getPhpType($field['type']); $methods = ''; // 生成访问器 $accessorName = 'get' . $this->getClassName($name) . 'Attribute'; $methods .= <<attributes['{$name}']; } PHP; // 生成修改器 $mutatorName = 'set' . $this->getClassName($name) . 'Attribute'; $methods .= <<attributes['{$name}'] = \$value; } PHP; return $methods; } private function generateMigration(string $className, string $tableName, array $fields, bool $timestamps, bool $softDeletes): void { $migrationName = 'create_' . $tableName . '_table'; $migrationClassName = $this->getClassName($migrationName); $content = $this->generateMigrationContent($migrationClassName, $tableName, $fields, $timestamps, $softDeletes); $migrationPath = $this->getNamespacePath('../database/migrations'); $timestamp = date('Y_m_d_His'); $filename = $timestamp . '_' . $migrationName . '.php'; $filePath = $migrationPath . '/' . $filename; $this->createFile($filePath, $content); } private function generateMigrationContent(string $className, string $tableName, array $fields, bool $timestamps, bool $softDeletes): string { $upMethods = ''; $downMethods = ''; // 生成字段定义 foreach ($fields as $field) { $upMethods .= $this->generateMigrationField($field); } // 生成时间戳 if ($timestamps) { $upMethods .= " \$table->timestamps();\n"; $downMethods .= " \$table->dropTimestamps();\n"; } // 生成软删除 if ($softDeletes) { $upMethods .= " \$table->softDeletes();\n"; $downMethods .= " \$table->dropSoftDeletes();\n"; } return $this->renderTemplate('migration', [ 'class_name' => $className, 'table_name' => $tableName, 'up_methods' => $upMethods, 'down_methods' => $downMethods ]); } private function generateMigrationField(array $field): string { $name = $field['name']; $type = $field['type']; $options = $field['options'] ?? []; $method = "\$table->{$type}('{$name}')"; if (isset($options['nullable'])) { $method .= '->nullable()'; } if (isset($options['default'])) { $default = $options['default']; if (is_string($default)) { $default = "'{$default}'"; } $method .= "->default({$default})"; } if (isset($options['unique'])) { $method .= '->unique()'; } return " {$method};\n"; } private function generateFactory(string $className, array $fields): void { $factoryClassName = $className . 'Factory'; $definition = $this->generateFactoryDefinition($className, $fields); $content = $this->renderTemplate('factory', [ 'namespace' => $this->getFullNamespace('Database\\Factories'), 'class_name' => $factoryClassName, 'model_class' => $className, 'definition' => $definition ]); $factoryPath = $this->getNamespacePath('../database/factories'); $filePath = $factoryPath . '/' . $factoryClassName . '.php'; $this->createFile($filePath, $content); } private function generateFactoryDefinition(string $className, array $fields): string { $definition = ''; foreach ($fields as $field) { $name = $field['name']; $type = $field['type']; $faker = $this->getFakerMethod($type, $field['options'] ?? []); $definition .= " '{$name}' => {$faker},\n"; } return $definition; } private function getFakerMethod(string $type, array $options): string { $fakerMap = [ 'string' => '$this->faker->sentence()', 'varchar' => '$this->faker->word()', 'text' => '$this->faker->paragraph()', 'int' => '$this->faker->numberBetween(1, 1000)', 'integer' => '$this->faker->numberBetween(1, 1000)', 'bigint' => '$this->faker->numberBetween(1, 1000000)', 'float' => '$this->faker->randomFloat(2, 0, 1000)', 'double' => '$this->faker->randomFloat(2, 0, 1000)', 'bool' => '$this->faker->boolean()', 'boolean' => '$this->faker->boolean()', 'date' => '$this->faker->date()', 'datetime' => '$this->faker->datetime()', 'timestamp' => '$this->faker->datetime()', 'email' => '$this->faker->email()', 'url' => '$this->faker->url()' ]; return $fakerMap[$type] ?? '$this->faker->word()'; } private function generateSeeder(string $className): void { $seederClassName = $className . 'Seeder'; $modelVariable = $this->getVariableName($className); $content = $this->renderTemplate('seeder', [ 'namespace' => $this->getFullNamespace('Database\\Seeders'), 'class_name' => $seederClassName, 'model_class' => $className, 'model_variable' => $modelVariable, 'model_namespace' => $this->getFullNamespace('Model') ]); $seederPath = $this->getNamespacePath('../database/seeders'); $filePath = $seederPath . '/' . $seederClassName . '.php'; $this->createFile($filePath, $content); } private function getModelTemplate(): string { return <<schema->create('{{table_name}}', function (Blueprint \$table) { {{up_methods}}); } public function down(): void { \$this->schema->dropIfExists('{{table_name}}'); } } PHP; } private function getFactoryTemplate(): string { return <<count(10)->create(); } } PHP; } }