← Back to list
managing-models
by moonpixels
Laravel skeleton application template with Inertia React.
⭐ 1🍴 0📅 Jan 10, 2026
SKILL.md
name: managing-models description: Create and modify Eloquent models with PHPDoc properties, casts, relationships, and virtual properties. Use when creating models, defining relationships, managing database models, or when user mentions models, Eloquent, database models, or model properties.
Manage Laravel Eloquent Models
Create and modify Eloquent models with PHPDoc properties, casts, relationships, and virtual properties. Models represent database tables with full type safety via PHPDoc annotations, enabling IDE autocompletion and static analysis.
File Structure
Models are stored in the Models directory:
app/Models/{Model}.php
Examples:
app/Models/User.phpapp/Models/Order.phpapp/Models/Product.php
Core Conventions
1. Model Structure
<?php
declare(strict_types=1);
namespace App\Models;
use Carbon\CarbonImmutable;
use Database\Factories\{Model}Factory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Override;
/**
* @property int $id
* @property string $name
* @property ?CarbonImmutable $created_at
* @property ?CarbonImmutable $updated_at
*/
final class {Model} extends Model
{
/**
* @use HasFactory<{Model}Factory>
*/
use HasFactory;
#[Override]
protected function casts(): array
{
return [
'created_at' => 'immutable_datetime',
'updated_at' => 'immutable_datetime',
];
}
}
Key Requirements:
- Always include
declare(strict_types=1); - Use
final classmodifier - PHPDoc with all
@propertyannotations - Use
CarbonImmutablefor dates - Type hint
HasFactorywith factory class - Use
#[Override]oncasts()method - Return array from
casts()method (not property)
2. PHPDoc Properties
Document ALL database columns and virtual properties:
/**
* @property int $id
* @property string $name
* @property string $email
* @property string $password
* @property ?string $remember_token
* @property ?CarbonImmutable $email_verified_at
* @property ?CarbonImmutable $created_at
* @property ?CarbonImmutable $updated_at
*/
final class User extends Authenticatable
3. Virtual Properties (PHP 8.4+)
public ?string $avatarUrl {
get => $this->avatar_path ? Storage::url($this->avatar_path) : null;
}
public string $firstName {
get => Str::before($this->name, ' ');
}
4. Casts
#[Override]
protected function casts(): array
{
return [
'email_verified_at' => 'immutable_datetime',
'password' => 'hashed',
'two_factor_secret' => 'encrypted',
'two_factor_recovery_codes' => 'encrypted:array',
'is_active' => 'boolean',
'settings' => 'array',
'status' => OrderStatus::class,
];
}
Examples
Example 1: User Model
<?php
declare(strict_types=1);
namespace App\Models;
use App\Support\TwoFactorAuthentication\Concerns\TwoFactorAuthenticatable;
use Carbon\CarbonImmutable;
use Database\Factories\UserFactory;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\MassPrunable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Override;
/**
* @property int $id
* @property string $name
* @property string $email
* @property string $language
* @property string $password
* @property ?string $two_factor_secret
* @property ?list<string> $two_factor_recovery_codes
* @property ?string $remember_token
* @property ?string $avatar_path
* @property ?CarbonImmutable $email_verified_at
* @property ?CarbonImmutable $two_factor_confirmed_at
* @property ?CarbonImmutable $created_at
* @property ?CarbonImmutable $updated_at
*/
final class User extends Authenticatable implements MustVerifyEmail
{
/**
* @use HasFactory<UserFactory>
* @use TwoFactorAuthenticatable<User>
*/
use HasFactory, MassPrunable, Notifiable, TwoFactorAuthenticatable;
public ?string $avatarUrl {
get => $this->avatar_path ? Storage::url($this->avatar_path) : null;
}
public string $firstName {
get => Str::before($this->name, ' ');
}
protected $hidden = [
'password',
'two_factor_secret',
'two_factor_recovery_codes',
'remember_token',
];
/**
* @var array<string, mixed>
*/
protected $attributes = [
'language' => 'en',
'avatar_path' => null,
];
/**
* @return Builder<self>
*/
public function prunable(): Builder
{
return self::query()
->whereNull('email_verified_at')
->where('created_at', '<=', now()->subDay());
}
#[Override]
protected function casts(): array
{
return [
'email_verified_at' => 'immutable_datetime',
'password' => 'hashed',
'two_factor_secret' => 'encrypted',
'two_factor_recovery_codes' => 'encrypted:array',
'two_factor_confirmed_at' => 'immutable_datetime',
];
}
}
Example 2: Model with Relationships
<?php
declare(strict_types=1);
namespace App\Models;
use Carbon\CarbonImmutable;
use Database\Factories\OrderFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Override;
/**
* @property int $id
* @property int $user_id
* @property string $status
* @property int $total
* @property ?CarbonImmutable $created_at
* @property ?CarbonImmutable $updated_at
*
* @property-read User $user
* @property-read \Illuminate\Database\Eloquent\Collection<int, OrderItem> $items
*/
final class Order extends Model
{
/**
* @use HasFactory<OrderFactory>
*/
use HasFactory;
/**
* @return BelongsTo<User, self>
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* @return HasMany<OrderItem, self>
*/
public function items(): HasMany
{
return $this->hasMany(OrderItem::class);
}
#[Override]
protected function casts(): array
{
return [
'status' => OrderStatus::class,
'total' => 'integer',
'created_at' => 'immutable_datetime',
'updated_at' => 'immutable_datetime',
];
}
}
Example 3: Model with Scopes
<?php
declare(strict_types=1);
namespace App\Models;
use Carbon\CarbonImmutable;
use Database\Factories\PostFactory;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Override;
/**
* @property int $id
* @property string $title
* @property bool $is_published
* @property ?CarbonImmutable $published_at
* @property ?CarbonImmutable $created_at
* @property ?CarbonImmutable $updated_at
*/
final class Post extends Model
{
/**
* @use HasFactory<PostFactory>
*/
use HasFactory;
/**
* @param Builder<self> $query
* @return Builder<self>
*/
public function scopePublished(Builder $query): Builder
{
return $query->where('is_published', true);
}
/**
* @param Builder<self> $query
* @return Builder<self>
*/
public function scopeRecent(Builder $query): Builder
{
return $query->orderBy('published_at', 'desc');
}
#[Override]
protected function casts(): array
{
return [
'is_published' => 'boolean',
'published_at' => 'immutable_datetime',
'created_at' => 'immutable_datetime',
'updated_at' => 'immutable_datetime',
];
}
}
Anti-Patterns
❌ Don't Do This
// Don't skip PHPDoc properties
final class User extends Model // ❌ Missing @property docs
{
}
// Don't use Carbon instead of CarbonImmutable
/**
* @property Carbon $created_at // ❌ Use CarbonImmutable
*/
// Don't use $casts property
protected $casts = [ // ❌ Use casts() method
'created_at' => 'datetime',
];
// Don't skip type hints on relationships
public function user() // ❌ Type hint return
{
return $this->belongsTo(User::class);
}
// Don't forget #[Override] attribute
protected function casts(): array // ❌ Missing #[Override]
// Don't use mutable classes
class User extends Model // ❌ Use final class
✅ Do This Instead
// Include full PHPDoc
/**
* @property int $id
* @property string $name
* @property ?CarbonImmutable $created_at
*/
final class User extends Model
// Use CarbonImmutable
/**
* @property ?CarbonImmutable $created_at
*/
// Use casts() method
#[Override]
protected function casts(): array
{
return ['created_at' => 'immutable_datetime'];
}
// Type hint relationships
/**
* @return BelongsTo<User, self>
*/
public function user(): BelongsTo
// Add #[Override] attribute
#[Override]
protected function casts(): array
// Use final class
final class User extends Model
Quality Standards
- All models must pass PHPStan level 8
- 100% type coverage required
- Code formatted with Pint
- Refactored with Rector
- All properties documented in PHPDoc
- All relationships type hinted
Score
Total Score
50/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
○LICENSE
ライセンスが設定されている
0/10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
Reviews
💬
Reviews coming soon