哈囉,大家好!經過前面的努力,我們已經設計了資料庫結構,建立了模型,並設定了路由。現在,是時候讓我們深入 Laravel 的 控制器(Controller),將一切串聯起來,為我們的個人財務管理系統打造強大的後端 API。
首先,我們需要為每個資源建立對應的控制器,包括 UserController、BankAccountController、CategoryController 和 TransactionController。
打開你的終端機,進入專案目錄,執行以下指令:
php artisan make:controller UserController
php artisan make:controller BankAccountController
php artisan make:controller CategoryController
php artisan make:controller TransactionController
這會在 app/Http/Controllers 目錄下生成四個控制器檔案。
小提醒:善用 Artisan 指令可以大大提高開發效率,讓我們專注於實際的業務邏輯。
讓我們先從 UserController 開始,實作使用者資源的 CRUD 操作。
use App\Models\User;
public function index()
{
$users = User::all();
return response()->json($users);
}
這段程式碼相當直觀,我們透過模型取得所有使用者,然後以 JSON 格式回傳。還記得有一次,我需要快速取得所有使用者的列表,這個方法就派上了用場。
public function store(Request $request)
{
$validatedData = $request->validate([
'username' => 'required|unique:users',
'email' => 'required|email|unique:users',
'password' => 'required|min:6',
]);
$user = User::create([
'username' => $validatedData['username'],
'email' => $validatedData['email'],
'password' => bcrypt($validatedData['password']),
]);
return response()->json($user, 201);
}
在這裡,我們使用 $request->validate() 進行資料驗證,確保使用者輸入的資料符合我們的規則。還記得當初忘記加上驗證,結果收到一堆奇怪的資料,真是讓人頭疼!
public function show($id)
{
$user = User::findOrFail($id);
return response()->json($user);
}
透過 findOrFail,我們可以輕鬆處理找不到資料的情況,避免程式崩潰。這真是 Laravel 體貼的設計啊!
public function update(Request $request, $id)
{
$user = User::findOrFail($id);
$validatedData = $request->validate([
'username' => 'sometimes|required|unique:users,username,' . $user->id,
'email' => 'sometimes|required|email|unique:users,email,' . $user->id,
'password' => 'sometimes|required|min:6',
]);
if (isset($validatedData['password'])) {
$validatedData['password'] = bcrypt($validatedData['password']);
}
$user->update($validatedData);
return response()->json($user);
}
這裡特別要注意的是,我們使用了 sometimes 規則,允許部分更新。當初在實作部分更新時,這個規則真是救了我一命!
public function destroy($id)
{
$user = User::findOrFail($id);
$user->delete();
return response()->json(null, 204);
}
刪除資料後,我們回傳 204 No Content,表示請求已成功處理,但沒有內容回傳。
接下來,我們來實作銀行帳戶的控制器方法。
use App\Models\BankAccount;
public function index()
{
$bankAccounts = BankAccount::all();
return response()->json($bankAccounts);
}
public function store(Request $request)
{
$validatedData = $request->validate([
'user_id' => 'required|exists:users,id',
'account_name' => 'required|string|max:100',
'account_number' => 'nullable|string|max:50',
'bank_name' => 'nullable|string|max:100',
'balance' => 'nullable|numeric',
]);
$bankAccount = BankAccount::create($validatedData);
return response()->json($bankAccount, 201);
}
在這裡,我們確保了 user_id 必須存在於 users 表中,避免了孤兒資料的產生。
public function show($id)
{
$bankAccount = BankAccount::findOrFail($id);
return response()->json($bankAccount);
}
public function update(Request $request, $id)
{
$bankAccount = BankAccount::findOrFail($id);
$validatedData = $request->validate([
'account_name' => 'sometimes|required|string|max:100',
'account_number' => 'nullable|string|max:50',
'bank_name' => 'nullable|string|max:100',
'balance' => 'nullable|numeric',
]);
$bankAccount->update($validatedData);
return response()->json($bankAccount);
}
public function destroy($id)
{
$bankAccount = BankAccount::findOrFail($id);
$bankAccount->delete();
return response()->json(null, 204);
}
現在,我們來為分類資源建立控制器方法。
use App\Models\Category;
public function index()
{
$categories = Category::all();
return response()->json($categories);
}
public function store(Request $request)
{
$validatedData = $request->validate([
'user_id' => 'required|exists:users,id',
'category_name' => 'required|string|max:100',
'type' => 'required|in:income,expense',
]);
$category = Category::create($validatedData);
return response()->json($category, 201);
}
public function show($id)
{
$category = Category::findOrFail($id);
return response()->json($category);
}
public function update(Request $request, $id)
{
$category = Category::findOrFail($id);
$validatedData = $request->validate([
'category_name' => 'sometimes|required|string|max:100',
'type' => 'sometimes|required|in:income,expense',
]);
$category->update($validatedData);
return response()->json($category);
}
public function destroy($id)
{
$category = Category::findOrFail($id);
$category->delete();
return response()->json(null, 204);
}
最後,我們來實作交易資源的控制器。
use App\Models\Transaction;
public function index()
{
$transactions = Transaction::all();
return response()->json($transactions);
}
public function store(Request $request)
{
$validatedData = $request->validate([
'user_id' => 'required|exists:users,id',
'bank_account_id' => 'required|exists:bank_accounts,id',
'category_id' => 'required|exists:categories,id',
'type' => 'required|in:income,expense',
'amount' => 'required|numeric',
'transaction_date' => 'required|date',
'description' => 'nullable|string|max:255',
]);
$transaction = Transaction::create($validatedData);
return response()->json($transaction, 201);
}
public function show($id)
{
$transaction = Transaction::findOrFail($id);
return response()->json($transaction);
}
public function update(Request $request, $id)
{
$transaction = Transaction::findOrFail($id);
$validatedData = $request->validate([
'bank_account_id' => 'sometimes|required|exists:bank_accounts,id',
'category_id' => 'sometimes|required|exists:categories,id',
'type' => 'sometimes|required|in:income,expense',
'amount' => 'sometimes|required|numeric',
'transaction_date' => 'sometimes|required|date',
'description' => 'nullable|string|max:255',
]);
$transaction->update($validatedData);
return response()->json($transaction);
}
public function destroy($id)
{
$transaction = Transaction::findOrFail($id);
$transaction->delete();
return response()->json(null, 204);
}
在每個控制器中,我們都使用了 $request->validate() 來確保接收到的資料符合我們的預期。這不僅提升了應用程式的健全性,也讓我們更放心地處理資料。
如果你想要讓錯誤訊息更貼近使用者,可以這樣做:
$validatedData = $request->validate([
'email' => 'required|email',
], [
'email.required' => '電子郵件是必填的喔!',
'email.email' => '請輸入有效的電子郵件地址。',
]);
我記得有一次,我的客戶反應說錯誤訊息太生硬了,透過自訂錯誤訊息,使用者體驗得到了明顯的改善。
透過控制器,我們可以輕鬆地與模型進行互動,實現各種資料操作。
例如,要取得使用者的所有交易紀錄:
public function getUserTransactions($userId)
{
$user = User::findOrFail($userId);
$transactions = $user->transactions;
return response()->json($transactions);
}
這樣的寫法是不是很直觀?Laravel 的 Eloquent ORM 真是讓人愛不釋手!
到目前為止,我們的控制器已經能夠正常運作,實現基本的 CRUD 功能。然而,你可能會發現,程式碼中有一些重複的部分,例如資料驗證和錯誤處理。而且,業務邏輯直接寫在控制器中,可能會讓控制器變得臃腫。
這其實很正常,因為我們現在的目標是先讓整個應用程式跑起來,建立一個基本的功能底子。之後,我們會進行 重構,將重複的程式碼抽取出來,優化我們的架構。
還記得在很久以前剛學Laravel時,一開始也是直接在控制器中寫業務邏輯。後來隨著功能越來越多,程式碼變得難以維護。透過重構,我們將邏輯拆分到不同的類別中,整個專案的結構變得清晰許多,開發效率也大大提升。
回顧整個開發過程,我深刻體會到控制器在 Laravel 開發中的重要性。它就像是應用程式的指揮官,負責調度各種資源,處理業務邏輯。
然而,直接在控制器中編寫所有邏輯,可能會導致程式碼難以維護。這就是為什麼我們需要考慮未來的重構。透過將重複的部分抽取出來,並將業務邏輯移到適當的位置,我們可以讓程式碼更加乾淨、可讀。我強烈建議大家在開發初期,專注於讓功能先跑起來,之後再進行重構和優化。這樣可以避免過度設計,同時也能在實踐中發現更好的架構方式。
今天,我們深入了解了 Laravel 控制器的實作方式,並為我們的 API 建立了完整的控制器邏輯。透過這些內容,我們可以:
在獨自開發的過程中就像是一場有趣的旅程,不僅可以提升了技術能力,也可以對框架有了更深的理解。
接下來,我們將進入 API 測試的階段。畢竟,再好的程式碼也需要經過嚴謹的測試才能確保品質。我們會學習如何使用工具來測試 API,並探討一些進階技巧,讓我們的應用程式更加完善。
同時,在未來的文章中,我們會開始進行重構,將目前的程式碼優化,提升整體的架構和效能。讓我們繼續這段充滿挑戰與樂趣的開發之旅吧!相信透過不斷的學習和實踐,我們都能成為更好的開發者。