iT邦幫忙

2024 iThome 鐵人賽

DAY 28
0
佛心分享-IT 人自學之術

後端小白自學 Laravel系列 第 28

第 28 天:實戰項目 - 後台任務管理應用開發

  • 分享至 

  • xImage
  •  

昨天有提到事前規劃,今天就進入開發流程!

建立模型和遷移檔案


回顧:第 5 天:數據模型與遷移

創建模型和遷移檔案可以用指令 php artisan make:model Task -m 自動建立

定義欄位規範

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Task extends Model
{
    use HasFactory;

    protected $fillable = [
        'title',
        'description',
        'completed',
    ];

    protected $casts = [
        'completed' => 'boolean'
    ];
}

在遷移檔案中添加任務的欄位

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up(): void
    {
        Schema::create('tasks', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('description');
            $table->boolean('completed')->default(false);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down(): void
    {
        Schema::dropIfExists('tasks');
    }
};

執行遷移來建立資料表
指令 php artisan migrate

創建 controller


回顧:第 4 天:控制器

前提摘要
這裡會依照第 24 天:項目重構與優化的方法做分工,主要就是把本來寫在控制器的內容區分成商業邏輯以及拜訪資料庫!
分工

創建 controller 來處理任務的 CRUD 操作
指令 php artisan make:controller TaskController

<?php

namespace App\Http\Controllers;

use App\Http\Requests\TaskRequest;
use App\Models\Task;
use App\Services\TaskService;
use App\Transformers\TaskTransformer;
use \Illuminate\Http\JsonResponse;

class TaskController extends Controller
{
    public function __construct(
        protected readonly TaskService $service,
        protected readonly TaskTransformer $transformer,
    ) {
    }

    /**
     * 取得所有任務明細
     * 
     * @return JsonResponse
     */
    public function showTasks(): JsonResponse
    {
        $tasks = $this->service->showTasks();

        return response()->json($this->transformer->transformTasks($tasks), 200);
    }

    /**
     * 新增任務
     * 
     * @param TaskRequest $request
     * @return mixed JsonResponse
     */
    public function storeTask(TaskRequest $request): JsonResponse
    {
        $validated = $request->validated();

        $task = $this->service->storeTask($validated);

        return response()->json($this->transformer->transformTask($task), 201);
    }

    /**
     * 編輯任務
     * 
     * @param TaskRequest $request
     * @param Task $task
     * @return JsonResponse
     */
    public function updateTask(TaskRequest $request, Task $task): JsonResponse
    {
        $validated = $request->validated();

        $task = $this->service->updateTask($task, $validated);

        return response()->json($this->transformer->transformTask($task), 201);
    }

    /**
     * 改變任務的完成欄位
     * 
     * @param Task $task
     * @param bool $complete
     * @return void
     */
    public function changeTaskComplete(Task $task, bool $complete): void
    {
        $this->service->changeTaskComplete($task, $complete);
    }

    /**
     * 刪除任務
     * 
     * @param Task $task
     * @return void
     */
    public function deleteTask(Task $task): void
    {
        $this->service->deleteTask($task);
    }
}

創建 require validate
指令 php artisan make:request TaskRequest

回顧:第 18 天:驗證與自定義規則
參考文章:Laravel Validator介紹與用法

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;
use Symfony\Component\HttpFoundation\Response;


class TaskRequest extends FormRequest
{
    /**
     * 預設function,定義授權規則
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * 預設 function,定義驗證規則
     *
     * @return array<string, mixed>
     */
    public function rules()
    {
        return [
            'title'         => ['required', 'string', 'max:255'],
            'description'   => ['required', 'string'],
            'completed'     => ['required', 'boolean'],
        ];
    }

    /**
     * 預設 function,可自行定義錯誤訊息
     * 
     * @return string[]
     */
    public function messages()
    {
        return [
            'title.required'         => '標題必填',
            'description.required'   => '內容描述必填',
            'completed.required'     => '完成欄位必填',
        ];
    }

    // 預設 function,驗證失敗時會執行,這邊自定義錯誤時會傳json
    protected function failedValidation(Validator $validator)
    {
        throw new HttpResponseException(
            response: response()->json([
                'status' => 'error',
                'message' => 'Validation failed',
                'errors' => $validator->errors(),
            ], status: Response::HTTP_UNPROCESSABLE_ENTITY)
        );
    }

    // 預設 function,授權失敗時會執行,這邊自定義錯誤時會傳json
    protected function failedAuthorization()
    {
        throw new HttpResponseException(
            response: response()->json([
                'status' => 'error',
                'message' => 'Authorization failed',
            ], status: Response::HTTP_UNAUTHORIZED)
        );
    }
}

創建 transform 轉成與前端約定好的架構
這裡無法下指令,所以直接在 app 下創建一個新的資料夾 Transforms 然後新增一個新的檔案

<?php

namespace App\Transformers;

use App\Models\Task;
use Illuminate\Support\Collection;

/**
 * TaskTransformer
 * 詳細說明: 任務相關資料轉換回傳的處理
 */
class TaskTransformer
{
    /**
     * 把模型的時間轉成 Y-M-D
     * 
     * @param Task $task
     * @return array
     */
    public function transformTask(Task $task): array
    {
        return [
            'id'            => $task->id,
            'title'         => $task->title,
            'description'   => $task->description,
            'completed'     => $task->completed,
            'start_at'      => $task->created_at?->format('Y-m-d'),
            'update_at'     => $task->updated_at?->format('Y-m-d'),
        ];
    }

    /**
     * 把模型集合的時間轉成 Y-M-D
     * 
     * @param Collection $tasks
     * @return array
     */
    public function transformTasks(Collection $tasks): array
    {
        return $tasks->map(fn(Task $task) => [
            'id'             => $task->id,
            'title'          => $task->title,
            'description'    => $task->description,
            'completed'      => $task->completed,
            'created_at'     => $task->created_at->format('Y-m-d'),
            'updated_at'     => $task->updated_at->format('Y-m-d'),
        ])->toArray();
    }
}

創建 service 做邏輯處理


這裡無法下指令,所以直接在 app 下創建一個新的資料夾 Services 然後新增一個新的檔案

<?php

namespace App\Services;

use App\Models\Task;
use App\Repositories\TaskRepository;
use Illuminate\Support\Collection as SupportCollection;

/**
 * TaskService
 * 詳細說明: 任務邏輯處理
 */
class TaskService
{
    public function __construct(
        protected readonly TaskRepository $repository,
    ) {
    }

    /**
     * 取得所有任務明細的邏輯處理
     * @return SupportCollection
     */
    public function showTasks(): SupportCollection
    {
        return $this->repository->showTasks();
    }

    /**
     * 新增任務的邏輯處理
     * 
     * @param array $data
     * @return Task
     */
    public function storeTask(array $data): Task
    {
        return $this->repository->storeTask($data);
    }

    /**
     * 編輯任務的邏輯處理
     * 
     * @param Task $task
     * @param array $data
     * @return Task
     */
    public function updateTask(Task $task, array $data): Task
    {
        return $this->repository->updateTask($task, $data);
    }

    /**
     * 改變任務的完成欄位邏輯處理
     * 
     * @param Task $task
     * @param bool $complete
     * @return void
     */
    public function changeTaskComplete(Task $task, bool $complete): void
    {
        $this->repository->changeTaskComplete($task, $complete);
    }

    /**
     * 刪除任務的邏輯處理
     * 
     * @param Task $task
     * @return void
     */
    public function deleteTask(Task $task): void
    {
        $this->repository->deleteTask($task);
    }
}

創建 repository 和資料庫互動


這裡無法下指令,所以直接在 app 下創建一個新的資料夾 Repositories 然後新增一個新的檔案

<?php

namespace App\Repositories;

use App\Models\Task;
use \Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection as SupportCollection;

/**
 * TaskRepository
 * 詳細說明: 任務資料邏輯
 */
class TaskRepository
{
    /**
     * 取得所有任務明細的資料處理
     * @return SupportCollection
     */
    public function showTasks(): SupportCollection
    {
        return Task::query()->get();
    }

    /**
     * 新增任務的資料處理
     * 
     * @param array $data
     * @return Task
     */
    public function storeTask(array $data): Task
    {
        return Task::create($data);
    }

    /**
     * 編輯任務的資料處理
     * 
     * @param Task $task
     * @param array $data
     * @return Task
     */
    public function updateTask(Task $task, array $data): Task
    {
        $task->update($data);

        return $task;
    }

    /**
     * 改變任務的完成欄位資料處理
     * 
     * @param Task $task
     * @param bool $complete
     * @return void
     */
    public function changeTaskComplete(Task $task, bool $complete): void
    {
        $task->completed = $complete;

        $task->save();
    }

    /**
     * 刪除任務的資料處理
     * 
     * @param \App\Models\Task $task
     * @return void
     */
    public function deleteTask(Task $task): void
    {
        $task->delete();
    }
}

上一篇
第 27 天:實戰項目 - 後台任務管理應用測試
下一篇
第 29 天:部署與環境管理
系列文
後端小白自學 Laravel30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
kuku
iT邦新手 4 級 ‧ 2024-10-03 18:04:51

前後端串接的方法可以用文件提到的 Inertia 方法,相關流程

文件:Inertia
安裝:Laravel Vite Vue Inertia

我要留言

立即登入留言