> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Eloquent 入门

> 介绍如何使用 Laravel 的 ORM「Eloquent」操作数据库数据。

## 什么是 Eloquent ORM

Laravel 内置了名为 Eloquent 的对象关系映射器（ORM）。
Eloquent 采用 **ActiveRecord 模式**，用于简化数据库交互。

使用 Eloquent 时，为每张数据库表准备一个对应的「模型」类。
通过模型可以完成记录的查询、插入、更新与删除。

<Info>
  使用 Eloquent 之前，请先在 `config/database.php` 中配置数据库连接。
  默认使用 `.env` 中的 `DB_*` 设置。
</Info>

## 创建模型

使用 `make:model` Artisan 命令生成新模型：

```shell theme={null}
php artisan make:model Post
```

同时创建迁移：

```shell theme={null}
php artisan make:model Post -m
```

模型会生成到 `app/Models`：

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    // ...
}
```

## 模型与表的对应

Eloquent 会根据类名推断表名：将类名转换为下划线复数形式。

| 模型名                    | 表名                        |
| ---------------------- | ------------------------- |
| `Post`                 | `posts`                   |
| `User`                 | `users`                   |
| `AirTrafficController` | `air_traffic_controllers` |

不符合命名约定时，可在模型中定义 `$table` 属性：

```php theme={null}
class Post extends Model
{
    protected $table = 'blog_posts';
}
```

### 时间戳

Eloquent 默认自动维护 `created_at` 和 `updated_at`。
在迁移中调用 `$table->timestamps()` 即可，保存或更新时会自动写入。

关闭自动维护：

```php theme={null}
class Post extends Model
{
    public $timestamps = false;
}
```

## 批量赋值保护

批量保存数据时需要配置批量赋值保护。

### fillable

用 `$fillable` 指定允许批量赋值的列：

```php theme={null}
class Post extends Model
{
    protected $fillable = [
        'user_id',
        'title',
        'body',
        'published',
    ];
}
```

### guarded

反向指定禁止赋值的列使用 `$guarded`：

```php theme={null}
class Post extends Model
{
    // 仅保护主键，允许其余全部
    protected $guarded = ['id'];
}
```

<Warning>
  将 `$guarded` 设为空数组会允许所有列被赋值。若直接接收用户输入，可能造成意外列被修改。建议使用 `$fillable` 明确许可范围。
</Warning>

## Eloquent 查询执行流程

`User::where()->get()` 的内部流程如下：

```mermaid theme={null}
flowchart LR
    A["User::where('active', true)"] --> B["构建查询构建器"]
    B --> C["调用 ->get()"]
    C --> D["生成 SQL"]
    D --> E["在数据库执行"]
    E --> F["结果转换为 Eloquent 模型"]
    F --> G["以 Collection 返回"]
```

## 基本 CRUD

### 读取

```php theme={null}
use App\Models\Post;

$posts = Post::all();
```

带条件：

```php theme={null}
// 已发布的文章
$publishedPosts = Post::where('published', true)->get();

// 第一条
$post = Post::where('published', true)->first();

// 按 ID 查
$post = Post::find(1);

// 未找到时返回 404
$post = Post::findOrFail(1);
```

### 创建

需要设置 `$fillable`：

```php theme={null}
$post = Post::create([
    'title' => '第一篇文章',
    'body' => 'Laravel 是很棒的框架。',
    'published' => true,
]);
```

或逐个赋值：

```php theme={null}
$post = new Post;
$post->title = '第一篇文章';
$post->body = 'Laravel 是很棒的框架。';
$post->save();
```

### 更新

```php theme={null}
$post = Post::find(1);
$post->title = '新标题';
$post->save();
```

或批量更新：

```php theme={null}
Post::find(1)->update([
    'title' => '新标题',
    'published' => true,
]);
```

批量更新符合条件的多条：

```php theme={null}
Post::where('published', false)->update(['published' => true]);
```

### 删除

```php theme={null}
$post = Post::find(1);
$post->delete();
```

按 ID 直接删除：

```php theme={null}
Post::destroy(1);

// 批量删除
Post::destroy([1, 2, 3]);
```

## 基础查询方法

| 方法                                           | 说明                   |
| -------------------------------------------- | -------------------- |
| `Post::all()`                                | 取全部记录                |
| `Post::find($id)`                            | 按 ID 取（未找到返回 `null`） |
| `Post::findOrFail($id)`                      | 按 ID 取（未找到返回 404）    |
| `Post::where('column', 'value')->get()`      | 取满足条件的记录             |
| `Post::where('column', 'value')->first()`    | 第一条                  |
| `Post::where('column', 'value')->count()`    | 数量                   |
| `Post::orderBy('created_at', 'desc')->get()` | 按某列排序                |
| `Post::latest()->get()`                      | 按 `created_at` 降序    |
| `Post::limit(10)->get()`                     | 限制条数                 |

## 实践示例：使用 Post 模型

一个基于迁移创建的 `posts` 表的控制器示例：

```php theme={null}
<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;

class PostController extends Controller
{
    // 文章列表
    public function index(): View
    {
        $posts = Post::where('published', true)
            ->latest()
            ->get();

        return view('posts.index', ['posts' => $posts]);
    }

    // 创建
    public function store(Request $request): RedirectResponse
    {
        $validated = $request->validate([
            'title' => ['required', 'string', 'max:255'],
            'body' => ['required', 'string'],
            'published' => ['boolean'],
        ]);

        Post::create([
            ...$validated,
            'user_id' => $request->user()->id,
        ]);

        return redirect('/posts');
    }

    // 更新
    public function update(Request $request, Post $post): RedirectResponse
    {
        $validated = $request->validate([
            'title' => ['required', 'string', 'max:255'],
            'body' => ['required', 'string'],
        ]);

        $post->update($validated);

        return redirect('/posts');
    }

    // 删除
    public function destroy(Post $post): RedirectResponse
    {
        $post->delete();

        return redirect('/posts');
    }
}
```

<Tip>
  在控制器方法参数中写 `Post $post`，Laravel 会通过路由模型绑定自动取回模型，无需再写 `Post::findOrFail($id)`。
</Tip>

## 模型事件生命周期

调用 `save()` 时触发事件的顺序如下。新建与更新触发不同的事件，`saving`、`saved` 在两种情况下都会触发。

```mermaid theme={null}
flowchart TD
    A["创建实例"] --> B{"save()"}
    B --> I["saving 事件"]
    I -->|"新建"| C["creating 事件"]
    C --> D["执行 INSERT"]
    D --> E["created 事件"]
    I -->|"更新"| F["updating 事件"]
    F --> G["执行 UPDATE"]
    G --> H["updated 事件"]
    E --> J["saved 事件"]
    H --> J
```

## 下一步

<Card title="迁移" icon="table" href="/zh/migrations">
  回顾如何通过迁移创建 Eloquent 所用的数据表。
</Card>


## Related topics

- [Eloquent 集合](/zh/eloquent-collections.md)
- [数据库填充（Seeding）](/zh/seeding.md)
- [数据库迁移](/zh/migrations.md)
- [MongoDB](/zh/mongodb.md)
- [Eloquent 关联入门](/zh/eloquent-relationships.md)
