--- name: backend-gen-model description: Generate Eloquent model for madong module. Supports both app (main project) and plugin targets. Creates model with SoftDeletes, relationships, and standard CRUD methods. globs: - "app/model/**/*.php" - "plugin/**/app/model/**/*.php" --- # Step 3: Generate Model Create Eloquent model file for module. ## File Location **App (主项目):** ``` app/model/{module}/{Model}.php ``` **Plugin (插件):** ``` plugin/{plugin}/app/model/{Model}.php ``` > 本项目插件模型采用扁平目录;仅在已有插件明确使用分模块目录时,才使用 `app/model/{module}/{Model}.php`。 ## Target Variables | 变量 | App | Plugin | |------|-----|--------| | `{prefix}` | `` (空) | `plugin\{Plugin}` | | `{ns}` | `app` | `plugin\{Plugin}\app` | | `{base_model}` | `core\base\BaseModel` | `plugin\{Plugin}\app\model\BaseModel` | ## Model Template ```php {relationMethod}({RelatedModel}::class, '{foreign_key}', '{owner_key}'); } /** * 设置密码(自动hash) */ public function setPasswordAttribute($value): void { $this->attributes['password'] = password_hash($value, PASSWORD_DEFAULT); } /** * 验证密码 */ public function verifyPassword($password): bool { return password_verify($password, $this->password); } } ``` ## Complete Example (App) ```php gender)?->label() ?? '未知'; } /** * 获取状态文本 */ public function getEnabledTextAttribute(): string { return EnabledStatus::tryFrom($this->enabled)?->label() ?? '未知'; } /** * 关联会员等级 */ public function level(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(MemberLevel::class, 'level_id', 'id'); } /** * 关联会员标签 */ public function tags(): \Illuminate\Database\Eloquent\Relations\BelongsToMany { return $this->belongsToMany(MemberTag::class, MemberTagRelation::class, 'member_id', 'tag_id'); } /** * 关联签到记录 */ public function signRecords(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(MemberSign::class, 'member_id', 'id'); } /** * 设置密码 */ public function setPasswordAttribute($value): void { $this->attributes['password'] = password_hash($value, PASSWORD_DEFAULT); } /** * 验证密码 */ public function verifyPassword($password): bool { return password_verify($password, $this->password); } } ``` ## Complete Example (Plugin) ```php 'integer', 'price' => 'decimal:2', 'view_count' => 'integer', 'status' => 'integer', 'created_at' => 'integer', 'updated_at' => 'integer', 'deleted_at' => 'integer', ]; /** * 关联分类 */ public function category(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Category::class, 'category_id', 'id'); } } ``` ## Relationship Types ### BelongsTo (belongs_to) ```php /** * 获取所属分类 */ public function category(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Category::class, 'category_id', 'id'); } ``` ### HasMany (has_many) ```php /** * 获取评论列表 */ public function comments(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(Comment::class, 'question_id', 'id'); } ``` ### BelongsToMany (many_to_many) ```php /** * 获取标签列表 */ public function tags(): \Illuminate\Database\Eloquent\Relations\BelongsToMany { return $this->belongsToMany( Tag::class, MemberTagRelation::class, // 中间表模型 'member_id', // 当前模型在中间表的关联键 'tag_id' // 另一模型在中间表的关联键 ); } ``` ### HasOne (has_one) ```php /** * 获取主图 */ public function cover(): \Illuminate\Database\Eloquent\Relations\HasOne { return $this->hasOne(Image::class, 'question_id', 'id'); } ``` ## Cast Types | Type | Example | |------|---------| | integer | `'id' => 'integer'` | | float | `'price' => 'float'` | | decimal | `'price' => 'decimal:2'` | | boolean | `'is_hot' => 'boolean'` | | string | `'name' => 'string'` | | array | `'data' => 'array'` | | object | `'data' => 'object'` | | datetime | `'created_at' => 'datetime'` | | timestamp | `'created_at' => 'timestamp'` | ## Attribute Mutators ```php /** * 设置生日(自动转换时间戳) */ public function setBirthdayAttribute($value): void { if (empty($value)) { $this->attributes['birthday'] = null; return; } if (is_numeric($value)) { $this->attributes['birthday'] = $value; return; } try { $carbon = \Carbon\Carbon::parse($value); $this->attributes['birthday'] = $carbon->timestamp; } catch (\Exception $e) { $this->attributes['birthday'] = null; } } /** * 获取生日 */ public function getBirthdayAttribute($value): ?string { if (empty($value)) { return null; } try { return \Carbon\Carbon::createFromTimestamp($value)->toIso8601String(); } catch (\Exception $e) { return null; } } ``` ## Auto-generation Checklist When generating model: - [ ] Set correct namespace based on target - [ ] Import BaseModel (core\base or plugin variant) - [ ] Import SoftDeletes trait - [ ] Import related models - [ ] Import Enum classes for status/text fields - [ ] Set table name (plugin may have prefix) - [ ] Set primary key - [ ] Set fillable array - [ ] Set hidden array (for sensitive fields) - [ ] Set casts array - [ ] Set appends array (for accessor attributes) - [ ] Add accessor methods (getXxxTextAttribute) - [ ] Add relationship methods - [ ] Add mutator methods (setPasswordAttribute)