# Laravel 學習筆記

## 2025-10-17: AJAX 編輯功能實作與問題排除

### 本次完成的功能
- ✅ 修正 TodoController 的 update 方法
- ✅ 創建並設定 UpdateTodoRequest 表單驗證
- ✅ 實作 AJAX 編輯功能
- ✅ 排除多個技術問題

### 核心學習重點

#### 1. Form Request 驗證類別

**Artisan 指令創建：**
```bash
php artisan make:request UpdateTodoRequest
```

**關鍵設定：**
```php
// app/Http/Requests/UpdateTodoRequest.php
class UpdateTodoRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true; // 重要：預設是 false，會導致 403 錯誤
    }

    public function rules(): array
    {
        return [
            'title' => 'required|string|max:255',
            'notes' => 'nullable|string',
            'due_date' => 'nullable|date|after_or_equal:today',
            'priority' => 'nullable|integer|between:1,5',
            'position' => 'nullable|integer|min:1',
        ];
    }

    public function messages(): array
    {
        return [
            'title.required' => '標題為必填欄位',
            // 自定義錯誤訊息...
        ];
    }
}
```

#### 2. 控制器中的 AJAX 雙向回應

**使用 `$request->expectsJson()` 判斷請求類型：**
```php
public function update(UpdateTodoRequest $request, Todo $todo)
{
    $todo->update($request->validated());
    
    if ($request->expectsJson()) {
        return response()->json([
            'success' => true,
            'todo' => $todo->fresh(),
        ]);
    }
    
    return redirect()->route('todos.index')->with('success', '任務已更新');
}
```

**`$request->expectsJson()` 的判斷條件：**
- Accept Header 包含 `application/json`
- 是 AJAX 請求（X-Requested-With: XMLHttpRequest）
- API 路由

#### 3. 前端 AJAX 實作要點

**正確的 Headers 設定：**
```javascript
fetch(`/todos/${todoId}`, {
    method: 'PATCH',
    headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',        // 讓 expectsJson() 回傳 true
        'X-Requested-With': 'XMLHttpRequest', // 標示為 AJAX 請求
        'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
    },
    body: JSON.stringify({
        title: newTitle
    })
})
```

**Promise 處理：**
```javascript
.then(response => {
    if (response.ok) {
        return response.json(); // 重要：需要 return
    }
    throw new Error('網路回應不是 OK');
})
.then(data => {
    if (data.success) {
        // 更新 UI
        const todoElement = document.querySelector(`[data-todo-id='${data.todo.id}']`);
        todoElement.querySelector('.todo-title').textContent = data.todo.title;
    }
})
```

### 遇到的問題與解決方案

#### 問題 1: "Class UpdateTodoRequest does not exist"
**原因：** 控制器缺少 use 語句
**解決：** 在控制器頂部加上 `use App\Http\Requests\UpdateTodoRequest;`

#### 問題 2: 403 Forbidden 錯誤
**原因：** UpdateTodoRequest 的 `authorize()` 方法回傳 `false`
**解決：** 改為 `return true;`

#### 問題 3: JavaScript Promise 不執行
**原因：** `.then()` 中缺少 `return response.json()`
**解決：** 加上 `return` 關鍵字

#### 問題 4: DOM 選擇器找不到元素
**原因：** 選擇器語法錯誤 `input[data-todo-id="..."]`
**解決：** 改為 `[data-todo-id="..."]`

### 技術重點總結

1. **Form Request** 是 Laravel 驗證的最佳實務
2. **雙向回應**（JSON + HTML）讓同一個方法支援 AJAX 和表單提交
3. **正確的 Headers** 是 AJAX 成功的關鍵
4. **Promise chaining** 需要正確的 return 語句
5. **DOM 選擇器** 要精確匹配 HTML 結構

### 下一步計劃
- [ ] 創建 TodoListController
- [ ] 更新路由結構以支援多清單架構
- [ ] 建立模型關聯（Todo belongsTo TodoList）
- [ ] 實作 Policy 授權機制

### P.S. ● 這些是創建所需檔案的 Laravel Artisan 指令：

    1. Form Request 類

    # 創建 StoreTodoRequest
    php artisan make:request StoreTodoRequest

    # 創建 UpdateTodoRequest  
    php artisan make:request UpdateTodoRequest

    2. Policy 類

    # 創建 TodoListPolicy
    php artisan make:policy TodoListPolicy --model=TodoList

    # 創建 TodoPolicy
    php artisan make:policy TodoPolicy --model=Todo

    3. 模型類（如果需要）

    # 創建 TodoList 模型
    php artisan make:model TodoList

    # 創建其他相關模型
    php artisan make:model TodoTag
    php artisan make:model Subtask
    php artisan make:model Collaborator

    4. Resource 類（API 回應格式化）

    # 創建 TodoResource
    php artisan make:resource TodoResource

    # 創建 TodoListResource
    php artisan make:resource TodoListResource

    5. 控制器（如果需要重新創建）

    # 創建 TodoListController
    php artisan make:controller TodoListController --resource

    # 創建 ReorderController（拖曳排序用）
    php artisan make:controller ReorderController

    6. 遷移檔案（如果需要修改資料表）

    # 創建修改 todos 表的遷移
    php artisan make:migration update_todos_table --table=todos

    # 創建新表的遷移
    php artisan make:migration create_todo_tags_table

    7. 中介軟體（如果需要）

    # 創建授權中介軟體
    php artisan make:middleware CheckTodoListAccess

    建議你先執行：
    8. php artisan make:request UpdateTodoRequest
    9. php artisan make:policy TodoListPolicy --model=TodoList
