零、目標:
1.專案目標:
A.環境準備
B.建立 Laravel 專案 + 登入系統
C.建立資料庫(資料夾 / 檔案)
D.資料夾 CRUD
E.檔案上傳 / 下載
F.檔案列表(像 Google Drive)
G.分享連結
H.權限與安全
1.專案目標:
A.環境準備
B.建立 Laravel 專案 + 登入系統
C.建立資料庫(資料夾 / 檔案)
D.資料夾 CRUD
E.檔案上傳 / 下載
F.檔案列表(像 Google Drive)
G.分享連結
H.權限與安全
I.回收桶(Soft Delete)
2.目前目標:
D.資料夾CRUD
a.點擊資料夾進入
b.在資料夾內新增子資料夾
c.無限層資料夾
d.基本路徑導覽
2.目前目標:
D.資料夾CRUD
a.點擊資料夾進入
b.在資料夾內新增子資料夾
c.無限層資料夾
d.基本路徑導覽
一、新增 Show 路由
1.編輯 routes/web.php
Route::get('/folders/{folder}',[FolderController::class,'show'])->name('folders.show');
如下圖:
二、FolderController 加入 show 方法
1.編輯 app/Http/Controllers/FolderController.php
public function show(Folder $folder){
// 安全檢查:只能看自己的資料夾
abort_if($folder->user_id !== Auth::id(), 403);
$subFolders = Folder::where('parent_id', $folder->id)->get();
return view('folders.show', compact('folder', 'subFolders'));
}
如下圖:
三、修改資料夾列表(可點擊)
1.編輯 resources/view/folders/index.blade.php
@foreach($folders as $folder)
<li class="border p-3 rounded hover:bg-gray-100">
📁
<a href="{{ route('folders.show', $folder) }}"
class="text-blue-600 font-semibold">
{{ $folder->name }}
</a>
</li>
@endforeach
如下圖:
四、建立資料夾內容頁
1.指令:cd resources/views/folders
type nul > show.blade.php
2.編輯 resources/view/folders/show.blade.php
<x-app-layout>
<div class="p-6 max-w-4xl mx-auto">
{{-- breadcrumb --}}
<div class="mb-4 text-sm text-gray-500">
<a href="{{ route('folders.index') }}" class="hover:underline">
我的雲端硬碟
</a>
/
{{ $folder->name }}
</div>
<h1 class="text-xl font-bold mb-4">📁 {{ $folder->name }}</h1>
{{-- 新增子資料夾 --}}
<form method="POST" action="{{ route('folders.store') }}" class="mb-4">
@csrf
<input type="hidden" name="parent_id" value="{{ $folder->id }}">
<input type="text" name="name" placeholder="子資料夾名稱"
class="border rounded p-2 mr-2">
<button class="bg-blue-500 text-white px-4 py-2 rounded">
新增
</button>
</form>
{{-- 子資料夾列表 --}}
<ul class="space-y-2">
@forelse($subFolders as $sub)
<li class="border p-3 rounded hover:bg-gray-100">
📁
<a href="{{ route('folders.show', $sub) }}"
class="text-blue-600 font-semibold">
{{ $sub->name }}
</a>
</li>
@empty
<li class="text-gray-400">此資料夾尚無子資料夾</li>
@endforelse
</ul>
</div>
</x-app-layout>
如下圖:
五、測試流程
1.開 /folders
2.建立資料夾01
3.點進01
4.建立資料夾02
5.點進02
如果可以一直點進去,巢狀成功
想在 顯示資料夾頁面時,呈現完整的 breadcrumb(麵包屑),像這樣:
我的雲端硬碟 / 父資料夾名稱 / 子資料夾名稱
目前程式碼只有顯示:
<a href="{{ route('folders.index') }}">我的雲端硬碟</a> / {{ $folder->name }}
也就是只顯示 雲端硬碟 → 當前資料夾,沒有祖先資料夾的層級。
調整方式如下:
1.在控制器準備 breadcrumb 資料
編輯 FolderController@show
// 建立 breadcrumb
$breadcrumbs = collect();
$current = $folder;
while($current) {
$breadcrumbs->prepend($current);
$current = $current->parent; // parent 關聯
}
如下圖
2.在 Blade 顯示完整 breadcrumb
編輯 show.blade.php@foreach ($breadcrumbs as $crumb)
/ <a href="{{ route('folders.show', $crumb) }}" class="hover:underline">{{ $crumb->name }}</a>
@endforeach
如下圖
4.根目錄頁加上 breadcrumb(一致性)
編輯resources/folders/index.blade.php
編輯resources/folders/index.blade.php
{{-- breadcrumb --}}
<div class="mb-4 text-sm text-gray-500">
我的雲端硬碟
</div>
想要在目前架構下,新增兩種功能,分別是1.資料夾重新命名、2.資料夾刪除。
1.資料夾重新命名
2.資料夾刪除(含所有子資料夾,利用 cascade)
調整方式如下:
(一).新增兩條路由:
編輯routes/web.php
Route::patch('/folders/{folder}', [FolderController::class, 'update'])->name('folders.update');
Route::delete('/folders/{folder}', [FolderController::class, 'destroy'])->name('folders.destroy');
編輯App/Http/Controllers/FolderController.php
public function update(Request $request, Folder $folder){
// 安全檢查:只能看自己的資料夾
abort_if($folder->user_id !== Auth::id(), 403);
$request->validate([
'name' => 'required|string|max:255',
]);
$folder->update([
'name' => $request->name,
]);
return back();
}
public function destroy(Folder $folder){
// 安全檢查:只能看自己的資料夾
abort_if($folder->user_id !== Auth::id(), 403);
// 你的 migration 已經設定 cascadeOnDelete
// 子資料夾會自動刪除
$folder->delete();
return redirect()->route('folders.index');
}
如下圖:
如下圖:
編輯 resiucrces/folders/show.blade.php
<li class="border p-3 rounded hover:bg-gray-100 flex justify-between items-center">
<div>
📁
<a href="{{ route('folders.show', $sub) }}"
class="text-blue-600 font-semibold">
{{ $sub->name }}
</a>
</div>
<div class="flex gap-2">
{{-- 重新命名 --}}
<form method="POST" action="{{ route('folders.update', $sub) }}">
@csrf
@method('PATCH')
<input type="text" name="name"value="{{ $sub->name }}"
class="border rounded p-1 text-sm w-32">
<button class="text-green-600 text-sm">儲存</button>
</form>
{{-- 刪除 --}}
<form method="POST" action="{{ route('folders.destroy', $sub) }}"
onsubmit="return confirm('確定要刪除這個資料夾及其所有子資料夾嗎?')">
@csrf
@method('DELETE')
<button class="text-red-600 text-sm">刪除</button>
</form>
</div>
</li>
與
在解決七、問題02的同時,發現index.blade.php 並沒有支援。所以編輯 resources/folders/index.blade.php,使其擁有重新命名與刪除的功能。
(一),編輯 resources/folders/index.blade.php 如下:
{{-- 新增根資料夾 --}}
<form method="POST" action="{{ route('folders.store') }}" class="mb-4">
@csrf
<input type="text" name="name" placeholder="新資料夾名稱"
class="border rounded p-2 mr-2">
<button class="bg-blue-500 text-white px-4 py-2 rounded">
新增
</button>
</form>
{{-- 資料夾列表 --}}
<ul class="space-y-2">
@foreach($folders as $folder)
<li class="border p-3 rounded hover:bg-gray-100
flex justify-between items-center">
{{-- 資料夾名稱 --}}
<div>
📁
<a href="{{ route('folders.show', $folder) }}"
class="text-blue-600 font-semibold">
{{ $folder->name }}
</a>
</div>
{{-- 操作 --}}
<div class="flex gap-3 items-center">
{{-- 重新命名 --}}
<form method="POST"
action="{{ route('folders.update', $folder) }}"
class="flex items-center gap-1">
@csrf
@method('PATCH')
<input type="text" name="name"
value="{{ $folder->name }}"
class="border rounded p-1 text-sm w-32">
<button class="text-green-600 text-sm">
儲存
</button>
</form>
{{-- 刪除 --}}
<form method="POST"
action="{{ route('folders.destroy', $folder) }}"
onsubmit="return confirm('確定要刪除這個資料夾及其所有子資料夾嗎?')">
@csrf
@method('DELETE')
<button class="text-red-600 text-sm">
刪除
</button>
</form>
</div>
</li>
@endforeach
</ul>
九、問題說明04:
在解決八、問題說明03時,希望做到[點擊]才編輯資料夾名稱。所以再次編輯 resources/folders/index.blade.php 與 resources/folders/show.blade.php。
在解決八、問題說明03時,希望做到[點擊]才編輯資料夾名稱。所以再次編輯 resources/folders/index.blade.php 與 resources/folders/show.blade.php。
(一)編輯resources/folders/index.blade.php
<li class="border p-3 rounded hover:bg-gray-100
flex justify-between items-center"
x-data="{ editing: false, name: '{{ $folder->name }}' }">
{{-- 左側:資料夾名稱 --}}
<div class="flex items-center gap-2">
📁
{{-- 顯示模式 --}}
<template x-if="!editing">
<span
@dblclick="editing = true"
class="font-semibold text-blue-600 cursor-pointer">
{{ $folder->name }}
</span>
</template>
{{-- 編輯模式 --}}
<template x-if="editing">
<form method="POST"
action="{{ route('folders.update', $folder) }}"
class="flex items-center gap-1">
@csrf
@method('PATCH')
<input type="text"
name="name"
x-model="name"
@keydown.enter.prevent="$el.form.submit()"
@keydown.escape="editing = false"
class="border rounded p-1 text-sm w-32"
autofocus>
<button class="text-green-600 text-sm">
儲存
</button>
<button type="button"
@click="editing = false"
class="text-gray-500 text-sm">
取消
</button>
</form>
</template>
</div>
{{-- 右側操作 --}}
<div class="flex gap-2 items-center">
{{-- 開啟 --}}
<a href="{{ route('folders.show', $folder) }}"
class="text-sm text-blue-500">
開啟
</a>
{{-- 重新命名 --}}
<button @click="editing = true"
class="text-sm text-gray-600">
重新命名
</button>
{{-- 刪除 --}}
<form method="POST"
action="{{ route('folders.destroy', $folder) }}"
onsubmit="return confirm('確定要刪除這個資料夾及其所有子資料夾嗎?')">
@csrf
@method('DELETE')
<button class="text-sm text-red-600">
刪除
</button>
</form>
</div>
</li>
如下圖:
(二)編輯resources/folders/show.blade.php
<li class="border p-3 rounded hover:bg-gray-100
flex justify-between items-center"
x-data="{ editing: false, name: '{{ $sub->name }}' }">
{{-- 左側:資料夾名稱 --}}
<div class="flex items-center gap-2">
📁
{{-- 顯示模式 --}}
<template x-if="!editing">
<span @dblclick="editing = true"
class="font-semibold text-blue-600 cursor-pointer">
{{ $sub->name }}
</span>
</template>
{{-- 編輯模式 --}}
<template x-if="editing">
<form method="POST"
action="{{ route('folders.update', $sub) }}"
class="flex items-center gap-1">
@csrf
@method('PATCH')
<input type="text"
name="name"
x-model="name"
@keydown.enter.prevent="$el.form.submit()"
@keydown.escape="editing = false"
class="border rounded p-1 text-sm w-32"
autofocus>
<button class="text-green-600 text-sm">
儲存
</button>
<button type="button"
@click="editing = false"
class="text-gray-500 text-sm">
取消
</button>
</form>
</template>
</div>
{{-- 右側操作 --}}
<div class="flex gap-2 items-center">
{{-- 開啟 --}}
<a href="{{ route('folders.show', $sub) }}"
class="text-sm text-blue-500">
開啟
</a>
{{-- 重新命名 --}}
<button @click="editing = true"
class="text-sm text-gray-600">
重新命名
</button>
{{-- 刪除 --}}
<form method="POST"
action="{{ route('folders.destroy', $sub) }}"
onsubmit="return confirm('確定要刪除這個資料夾及其所有子資料夾嗎?')">
@csrf
@method('DELETE')
<button class="text-sm text-red-600">
刪除
</button>
</form>
</div>
</li>
@empty
<li class="text-gray-400">此資料夾尚無子資料夾</li>
十、問題說明05:
在解決九、問題說明04時,發現刪除資料夾後,會回到根資料夾。因此,刪除資料夾後,希望能回到[父資料夾]。
(一)編輯App/Http/Controllers/FolderController.php
在解決九、問題說明04時,發現刪除資料夾後,會回到根資料夾。因此,刪除資料夾後,希望能回到[父資料夾]。
(一)編輯App/Http/Controllers/FolderController.php
public function destroy(Folder $folder){
// 安全檢查:只能看自己的資料夾
abort_if($folder->user_id !== Auth::id(), 403);
// 🔑 刪除前先記住 parent
$parentId = $folder->parent_id;
// 你的 migration 已經設定 cascadeOnDelete
// 子資料夾會自動刪除
$folder->delete();
// 有 parent → 回到父資料夾
if ($parentId) {
return redirect()->route('folders.show', $parentId);
}
// 沒 parent → 回到根目錄
return redirect()->route('folders.index');
}
如下圖:
如下圖:
1.編輯App/Http/Controllers/FolderController.php
->with('success', '資料夾已刪除');
如下圖: @if (session('success'))
<div class="mb-4 text-green-600">
{{ session('success') }}
</div>
@endif
如下圖:
3.編輯resources/folders/show.blade.php @if (session('success'))
<div class="mb-4 text-green-600">
{{ session('success') }}
</div>
@endif



























沒有留言:
張貼留言