Skip to content
Back to skills

Laravel Eloquent

ASecurity

Use when working with database models — Eloquent ORM, PHP attributes, relationships, queries, observers, or factories in Laravel 13.

  • 29 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added February 7, 2026
databasesphpsqltestingdebuggingapidatabaseperformance

Works with

  • api
  • mcp

Security analysis

A100/100

Pro scans all 20 files and shows the line behind each finding

Scanned September 29, 2026

npx -y skills add fusengine/agents --skill laravel-eloquent --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Laravel Eloquent?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Laravel Eloquent
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/fusengine-laravel-eloquent/badge)](https://www.skillsdirectory.com/skills/fusengine-laravel-eloquent)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: laravel-eloquent
description: Use when working with database models — Eloquent ORM, PHP attributes, relationships, queries, observers, or factories in Laravel 13.
versions:
  laravel: "13.0"
  php: "8.3"
user-invocable: true
references: references/legacy-properties.md, references/models.md, references/relationships-basic.md, references/relationships-many-to-many.md, references/relationships-advanced.md, references/relationships-polymorphic.md, references/eager-loading.md, references/scopes.md, references/casts.md, references/accessors-mutators.md, references/events-observers.md, references/soft-deletes.md, references/collections.md, references/serialization.md, references/factories.md, references/performance.md, references/resources.md, references/transactions.md, references/pagination.md, references/aggregates.md, references/batch-operations.md, references/query-debugging.md, references/templates/ModelBasic.php.md, references/templates/ModelRelationships.php.md, references/templates/ModelCasts.php.md, references/templates/Observer.php.md, references/templates/Factory.php.md, references/templates/Resource.php.md, references/templates/EagerLoadingExamples.php.md
related-skills: laravel-attributes, laravel-migrations, laravel-api, laravel-testing
---

<objective>
Covers Laravel 13 Eloquent ORM with PHP 8.3 Attributes as the primary
metadata mechanism (#[Table], #[Fillable], #[Hidden], #[Visible], #[Guarded],
#[Appends], #[Touches], #[Connection], #[Refreshes]) alongside legacy property
equivalents for backward compatibility. Includes all relationship types
(basic, many-to-many, advanced, polymorphic), eager loading, scopes,
accessors/mutators, events/observers, soft deletes, collections,
serialization, factories, API resources, transactions, pagination,
aggregates, batch operations, and query debugging/performance.
</objective>

# Laravel Eloquent ORM (L13 — Attributes-first)

## Agent Workflow (MANDATORY)

Before ANY implementation, spawn 3 agents in parallel, one `Agent` call each with a `name`:

1. **fuse-ai-pilot:explore-codebase** - Inspect existing models, mixed property/attribute usage
2. **fuse-ai-pilot:research-expert** - Verify Laravel 13 Eloquent + Attributes docs via Context7
3. **mcp__context7__query-docs** - Query attribute patterns (#[Fillable], #[Table], #[Scope])

After implementation, run **fuse-ai-pilot:sniper** for validation.

---

## Overview

Laravel 13 promotes **PHP 8.3 Attributes** as the primary metadata mechanism on Eloquent models. Legacy properties (`$fillable`, `$hidden`, ...) remain supported for backward compatibility but should not be mixed with their attribute counterparts.

| Feature | Attribute (L13 MAIN) | Legacy property |
|---------|---------------------|-----------------|
| Table name | `#[Table('users')]` | `protected $table` |
| Mass assignment | `#[Fillable([...])]` | `protected $fillable` |
| Hidden / Visible | `#[Hidden([...])]` / `#[Visible([...])]` | `protected $hidden` / `$visible` |
| Guarded | `#[Guarded([...])]` / `#[Unguarded]` | `protected $guarded` |
| Casts | no attribute — `casts()` method | `protected $casts` |
| Appends | `#[Appends([...])]` | `protected $appends` |
| Touches | `#[Touches([...])]` | `protected $touches` |
| Connection | `#[Connection('mysql')]` | `protected $connection` |
| Primary key | `#[Table(key: 'uuid', keyType: 'string', incrementing: false)]` | `$primaryKey` / `$keyType` / `$incrementing` |
| Timestamps off | `#[WithoutTimestamps]` | `public $timestamps = false` |
| Refresh after write (13.33+) | `#[Refreshes(['slug'])]` | — |

---

## Critical Rules

1. **Attributes are the source of truth** - Use `#[Fillable]`, `#[Hidden]`, `#[Table]` on new code (casts stay in `casts()`)
2. **Never mix attribute + property** for the same concern (`#[Fillable]` AND `$fillable`)
3. **Eager load relationships** - Prevent N+1 queries with `with()`
4. **No `new static()` / `new Model()` inside the model's own `boot()` / trait `boot*()`** - Throws `LogicException` in L13 (nested booting disallowed)
5. **Use factories** in tests - Never hardcode test data

---

## Architecture

```
app/Models/
├── User.php              # #[Table], #[Fillable], #[Hidden] + casts()
├── Post.php              # #[Connection], #[Appends], relationships
└── Concerns/
    └── HasUuid.php       # Reusable trait
```

→ See [templates/ModelBasic.php.md](references/templates/ModelBasic.php.md)

---

## Reference Guide

### Concepts

- **Migration L12→L13:** [legacy-properties.md](references/legacy-properties.md)
- **Modeling:** [models.md](references/models.md) · [casts.md](references/casts.md) · [accessors-mutators.md](references/accessors-mutators.md) · [serialization.md](references/serialization.md) · [soft-deletes.md](references/soft-deletes.md)
- **Relationships:** [relationships-basic.md](references/relationships-basic.md) · [relationships-many-to-many.md](references/relationships-many-to-many.md) · [relationships-advanced.md](references/relationships-advanced.md) · [relationships-polymorphic.md](references/relationships-polymorphic.md)
- **Querying:** [eager-loading.md](references/eager-loading.md) · [scopes.md](references/scopes.md) · [aggregates.md](references/aggregates.md) · [pagination.md](references/pagination.md) · [batch-operations.md](references/batch-operations.md) · [query-debugging.md](references/query-debugging.md)
- **Lifecycle / Output:** [events-observers.md](references/events-observers.md) · [collections.md](references/collections.md) · [resources.md](references/resources.md) · [factories.md](references/factories.md) · [transactions.md](references/transactions.md) · [performance.md](references/performance.md)

### Templates

| Template | When to Use |
|----------|-------------|
| [ModelBasic.php.md](references/templates/ModelBasic.php.md) | Attribute-based model |
| [ModelRelationships.php.md](references/templates/ModelRelationships.php.md) | All relationship types |
| [ModelCasts.php.md](references/templates/ModelCasts.php.md) | casts() and accessors |
| [Observer.php.md](references/templates/Observer.php.md) | Complete observer |
| [Factory.php.md](references/templates/Factory.php.md) | Factory with states |
| [Resource.php.md](references/templates/Resource.php.md) | API resource |
| [EagerLoadingExamples.php.md](references/templates/EagerLoadingExamples.php.md) | N+1 prevention |

---

## Quick Reference

### Attribute-based Model (L13 MAIN)

```php
use Illuminate\Database\Eloquent\Attributes\{Table, Fillable, Hidden};
use Illuminate\Database\Eloquent\Model;

#[Table('users')]
#[Fillable(['name', 'email', 'password'])]
#[Hidden(['password', 'remember_token'])]
final class User extends Model
{
    protected function casts(): array
    {
        return ['email_verified_at' => 'datetime', 'is_admin' => 'boolean'];
    }

    public function posts(): HasMany
    {
        return $this->hasMany(Post::class);
    }
}
```

### Scope (attribute syntax)

```php
#[Scope]
protected function published(Builder $query): void
{
    $query->whereNotNull('published_at');
}
// Usage: Post::published()->get();
```

### Eager Loading

```php
$posts = Post::with('author')->get();  // 2 queries, not N+1
```

### 13.x additions

```php
#[Refreshes(['slug'])]            // 13.33+: re-read generated columns after insert/update
final class Post extends Model {}

DB::transaction(function () use ($flight) {
    $flight->refreshForUpdate();  // 13.27+: reload with a FOR UPDATE lock
});
```

→ Legacy `$fillable` / `$hidden` style — see [legacy-properties.md](references/legacy-properties.md)

---

## Best Practices

### DO
- Declare metadata with **PHP Attributes** (`#[Table]`, `#[Fillable]`, `#[Hidden]`, ...)
- Use `final` on model classes when not extended
- Eager load with `with()`
- Use factories in tests
- Cast dates, arrays, enums via the `casts()` method (there is no `#[Casts]` attribute)

### DON'T
- **Mix `#[Fillable]` and `$fillable`** on the same model (conflict — single source of truth)
- **Instantiate the model inside its own `boot()` / trait `boot*()`** — L13 throws `LogicException`
- Lazy-load relationships in loops (N+1)
- Use `#[Unguarded]` in production
- Query inside accessors / mutators
- Put business logic in models (use Services/Actions)

Files in this skill

  • SKILL.md7.2 KB
  • references/accessors-mutators.md2.8 KB
  • references/aggregates.md3.2 KB
  • references/batch-operations.md3.3 KB
  • references/casts.md3.2 KB
  • references/collections.md3.2 KB
  • references/eager-loading.md3.2 KB
  • references/events-observers.md3.2 KB
  • references/factories.md3.2 KB
  • references/models.md2.7 KB
  • references/pagination.md2.8 KB
  • references/performance.md3.4 KB
  • references/query-debugging.md2.8 KB
  • references/relationships-advanced.md3 KB
  • references/relationships-basic.md2.8 KB
  • references/relationships-many-to-many.md3.2 KB
  • references/relationships-polymorphic.md3.3 KB
  • references/resources.md3.2 KB
  • references/scopes.md2.7 KB
  • references/serialization.md3.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…