跳至内容

05. 编辑 Chirps

让我们添加一个其他流行的以鸟类为主题的微博平台中缺少的功能——编辑 Chirps 的功能!

路由

首先,我们将更新我们的路由文件以启用 chirps.editchirps.update 路由,用于我们的资源控制器。chirps.edit 路由将显示用于编辑 Chirp 的表单,而 chirps.update 路由将接受来自表单的数据并更新模型。

routes/web.php
<?php
 ...
use App\Http\Controllers\ChirpController;
use App\Http\Controllers\ProfileController;
use Illuminate\Support\Facades\Route;
 
Route::get('/', function () {
return view('welcome');
});
 
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');
 
Route::middleware('auth')->group(function () {
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
});
 
Route::resource('chirps', ChirpController::class)
- ->only(['index', 'store'])
+ ->only(['index', 'store', 'edit', 'update'])
->middleware(['auth', 'verified']);
 ...
require __DIR__.'/auth.php';
 

此控制器的路由表现在如下所示

动词 URI 操作 路由名称
GET /chirps index chirps.index
POST /chirps store chirps.store
GET /chirps/{chirp}/edit edit chirps.edit
PUT/PATCH /chirps/{chirp} update chirps.update

链接到编辑页面

接下来,让我们链接新的 chirps.edit 路由。我们将使用 Breeze 附带的 x-dropdown 组件,该组件仅显示给 Chirp 作者。我们还将通过比较 Chirp 的 created_at 日期与其 updated_at 日期来显示 Chirp 是否已被编辑的指示。

resources/views/chirps/index.blade.php
<x-app-layout>
<div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8">
<form method="POST" action="{{ route('chirps.store') }}">
@csrf
<textarea
name="message"
placeholder="{{ __('What\'s on your mind?') }}"
class="block w-full border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm"
>{{ old('message') }}</textarea>
<x-input-error :messages="$errors->get('message')" class="mt-2" />
<x-primary-button class="mt-4">{{ __('Chirp') }}</x-primary-button>
</form>
 
<div class="mt-6 bg-white shadow-sm rounded-lg divide-y">
@foreach ($chirps as $chirp)
<div class="p-6 flex space-x-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-gray-600 -scale-x-100" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
</svg>
<div class="flex-1">
<div class="flex justify-between items-center">
<div>
<span class="text-gray-800">{{ $chirp->user->name }}</span>
<small class="ml-2 text-sm text-gray-600">{{ $chirp->created_at->format('j M Y, g:i a') }}</small>
+ @unless ($chirp->created_at->eq($chirp->updated_at))
+ <small class="text-sm text-gray-600"> &middot; {{ __('edited') }}</small>
+ @endunless
</div>
+ @if ($chirp->user->is(auth()->user()))
+ <x-dropdown>
+ <x-slot name="trigger">
+ <button>
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
+ <path d="M6 10a2 2 0 11-4 0 2 2 0 014 0zM12 10a2 2 0 11-4 0 2 2 0 014 0zM16 12a2 2 0 100-4 2 2 0 000 4z" />
+ </svg>
+ </button>
+ </x-slot>
+ <x-slot name="content">
+ <x-dropdown-link :href="route('chirps.edit', $chirp)">
+ {{ __('Edit') }}
+ </x-dropdown-link>
+ </x-slot>
+ </x-dropdown>
+ @endif
</div>
<p class="mt-4 text-lg text-gray-900">{{ $chirp->message }}</p>
</div>
</div>
@endforeach
</div>
</div>
</x-app-layout>

创建编辑表单

让我们创建一个新的 Blade 视图,其中包含一个用于编辑 Chirp 的表单。这与创建 Chirp 的表单类似,只是我们将发布到 chirps.update 路由,并使用 @method 指令指定我们正在进行“PATCH”请求。我们还将使用现有的 Chirp 消息预填充字段。

resources/views/chirps/edit.blade.php
<x-app-layout>
<div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8">
<form method="POST" action="{{ route('chirps.update', $chirp) }}">
@csrf
@method('patch')
<textarea
name="message"
class="block w-full border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm"
>{{ old('message', $chirp->message) }}</textarea>
<x-input-error :messages="$errors->get('message')" class="mt-2" />
<div class="mt-4 space-x-2">
<x-primary-button>{{ __('Save') }}</x-primary-button>
<a href="{{ route('chirps.index') }}">{{ __('Cancel') }}</a>
</div>
</form>
</div>
</x-app-layout>

更新我们的控制器

让我们更新 ChirpController 上的 edit 方法以显示我们的表单。Laravel 将使用 路由模型绑定 自动从数据库加载 Chirp 模型,以便我们可以直接将其传递给视图。

然后,我们将更新 update 方法以验证请求并更新数据库。

即使我们只向 Chirp 的作者显示编辑按钮,我们仍然需要确保访问这些路由的用户已获得授权。

app/Http/Controllers/ChirpController.php
<?php
 ...
namespace App\Http\Controllers;
 
use App\Models\Chirp;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
+use Illuminate\Support\Facades\Gate;
use Illuminate\View\View;
 
class ChirpController extends Controller
{
 ...
/**
* Display a listing of the resource.
*/
public function index(): View
{
return view('chirps.index', [
'chirps' => Chirp::with('user')->latest()->get(),
]);
}
 
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
 
/**
* Store a newly created resource in storage.
*/
public function store(Request $request): RedirectResponse
{
$validated = $request->validate([
'message' => 'required|string|max:255',
]);
 
$request->user()->chirps()->create($validated);
 
return redirect(route('chirps.index'));
}
 
/**
* Display the specified resource.
*/
public function show(Chirp $chirp)
{
//
}
 
/**
* Show the form for editing the specified resource.
*/
- public function edit(Chirp $chirp)
+ public function edit(Chirp $chirp): View
{
- //
+ Gate::authorize('update', $chirp);
+ 
+ return view('chirps.edit', [
+ 'chirp' => $chirp,
+ ]);
}
/**
* Update the specified resource in storage.
*/
- public function update(Request $request, Chirp $chirp)
+ public function update(Request $request, Chirp $chirp): RedirectResponse
{
- //
+ Gate::authorize('update', $chirp);
+ 
+ $validated = $request->validate([
+ 'message' => 'required|string|max:255',
+ ]);
+ 
+ $chirp->update($validated);
+ 
+ return redirect(route('chirps.index'));
}
 ...
/**
* Remove the specified resource from storage.
*/
public function destroy(Chirp $chirp)
{
//
}
 
}

授权

默认情况下,authorize 方法将阻止所有人更新 Chirp。我们可以通过使用以下命令创建一个 模型策略 来指定谁被允许更新它。

php artisan make:policy ChirpPolicy --model=Chirp

这将在 app/Policies/ChirpPolicy.php 中创建一个策略类,我们可以更新它以指定只有作者被授权更新 Chirp。

app/Policies/ChirpPolicy.php
<?php
 ...
namespace App\Policies;
 
use App\Models\Chirp;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
 
class ChirpPolicy
{
 ...
use HandlesAuthorization;
 
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
//
}
 
/**
* Determine whether the user can view the model.
*/
public function view(User $user, Chirp $chirp): bool
{
//
}
 
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
//
}
 
/**
* Determine whether the user can update the model.
*/
public function update(User $user, Chirp $chirp): bool
{
- //
+ return $chirp->user()->is($user);
}
 ...
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, Chirp $chirp): bool
{
//
}
 
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, Chirp $chirp): bool
{
//
}
 
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, Chirp $chirp): bool
{
//
}
 
}

测试一下

现在来测试一下!使用下拉菜单编辑几个Chirps。如果你注册了另一个用户帐户,你会发现只有Chirp的作者才能编辑它。

An editted chirp

继续允许删除Chirps...