Vlastní blog v Laravel: Editace článku
Aktualizováno pro Laravel 10
V tomto díle se zaměříme na editaci stávajícího článku. Jako první si upravíme PostController
a vytvoříme si šablonu s formulářem pro editaci článku.
Formulář
V Http/Controllers/PostController.php
si upravíme metodu edit()
:
public function edit(Post $post)
{
$users = User::all();
$categories = Category::all();
return view('posts.edit', compact('post', 'users', 'categories'));
}
kde vracíme šablonu společně s daty o článku, který chceme upravit. Všimněte si, že jsem jako argument použil rovnou model Post
. Laravel umožňuje tzv. explicit binding, tedy definuje jak se má model vyhledat. V základním nastavení Laravel automaticky vyhledá model na základě jeho primárního klíče. Takže když například máte trasu Route::get('posts/{post}', ...
, Laravel se pokusí najít post (článek) s daným ID. Samozřejmě to nemusí být jen ID, ale může tam být cokoliv (v případě článků to bude nejčastěji podle jeho slug), nicméně to je potřeba definovat v modelu, o tom ale třeba někdy příště. Výhodou tohoto přístupu je, že máte automaticky načtený celý model a není tak potřeba znovu vytvářet sql dotaz pro vytažení dat. Nevýhodou pak je, že se vám automaticky vyberou i všechny sloupce v daném modelu, což občas nemusí být žádoucí (například při velkém počtu sloupců).
Dále si zde vytáhneme z databáze všechny uživatele a kategorie, protože ty pak budeme dávat na výběr při editaci článku.
Dalším krokem je vytvoření nové šablony s formulářem resources/views/posts/edit.blade.php
:
@extends('layouts.app')
@section('title', 'Editace článku')
@section('content')
<div class="container mx-auto px-4">
<h1 class="text-2xl font-bold mb-4">Editovat článek</h1>
<form action="{{ route('posts.update', $post->id) }}" method="POST">
@csrf
@method('PUT')
<div class="mb-4">
<label for="author" class="block text-sm font-bold mb-2">Autor:</label>
<select name="author_id" id="author" class="border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline">
@foreach($users as $user)
<option value="{{ $user->id }}" {{ $post->user_id === $user->id ? 'selected' : '' }}>{{ $user->name }}</option>
@endforeach
</select>
@error('author_id')
<span class="text-red-500 text-xs italic">{{ $message }}</span>
@enderror
</div>
<div class="mb-4">
<label for="category" class="block text-sm font-bold mb-2">Kategorie:</label>
<select name="category_id" id="category" class="border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline">
@foreach($categories as $category)
<option value="{{ $category->id }}" {{ $post->category_id === $category->id ? 'selected' : '' }}>{{ $category->name }}</option>
@endforeach
</select>
@error('category_id')
<span class="text-red-500 text-xs italic">{{ $message }}</span>
@enderror
</div>
<div class="mb-4">
<label for="title" class="block text-sm font-bold mb-2">Název článku:</label>
<input type="text" name="title" id="title" value="{{ $post->title }}" class="border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline">
@error('title')
<span class="text-red-500 text-xs italic">{{ $message }}</span>
@enderror
</div>
<div class="mb-4">
<label for="content" class="block text-sm font-bold mb-2">Obsah článku:</label>
<textarea name="content" id="content" rows="10" class="border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline">{{ $post->content }}</textarea>
@error('content')
<span class="text-red-500 text-xs italic">{{ $message }}</span>
@enderror
</div>
<button type="submit" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">
Upravit článek
</button>
</form>
</div>
@endsection
Princip formuláře je podobný jako v případě vytvoření nového článku. Hlavní rozdíl je v hodnotách, které jsou předvyplněny z existujícího článku ({{ $post->title }}
, {{ $post->content }}
) a také v přidání direktivy @method('PUT')
, která specifikuje HTTP metodu, kterou formulář použije k odeslání dat. Zatímco vytvoření nového článku používá metodu POST
, editace existujícího článku využívá metodu PUT
. Také zde vypisujeme uživatele a kategorie a pokud se nám shoduji jejich ID, pak je vybereme jako defaultní.
Aktualizace v databázi
V Http/Controllers/PostController.php
si upravíme metodu update()
:
public function update(Request $request, string $id)
{
$post = Post::findOrFail($id);
$request->validate([
'title' => 'required|max:255',
'content' => 'required',
'author_id' => 'required|exists:users,id',
'category_id' => 'required|exists:categories,id',
]);
$post->title = $request->input('title');
$post->slug = Str::slug($request->input('title'));
$post->content = $request->input('content');
$post->user_id = $request->input('author_id');
$post->category_id = $request->input('category_id');
$post->save();
return redirect()->route('posts.index')->with('success', 'Článek byl úspěšně upraven.');
}
Tato metoda funguje podobně jako metoda pro vytvoření článku. Nejprve se provede validace dat, poté se příslušným atributům modelu Post
přiřadí nové hodnoty a následně se provede uložení do databáze. Změny jsou tentokrát ale ukládány do existujícího záznamu, nikoliv do nového.
I zde jsem mohl v argumentech metody použít explicitní binding (jako v případě metody edit()
), nicméně jsem chtěl ukázat i jiný způsob.
Odkaz v seznamu článků
Na závěr si ještě upravíme tabulku se seznamem všech článku resources/views/posts/index.blade.php
kde si přidáme tlačítko na editaci daného článku:
...
<tbody class="bg-white">
@foreach ($posts as $post)
<tr>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400">{{ $post->title }}</td>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400">{{ $post->created_at }}</td>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400">{{ $post->updated_at }}</td>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400">
<a href="{{ route('posts.edit', $post->id) }}" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">Editovat</a>
</td>
</tr>
@endforeach
</tbody>
...
Všimněte si, že odkaz na editaci článku v navigaci potřebuje znát id
článku, který chceme editovat. Proto je v něm použita funkce route
s dvěma argumenty: název trasy a id
článku.
Není vám něco jasné, nefunguje nebo mám někde chybu? Napište do komentářů!
Zdrojové kódy pro tento díl naleznete na GitHubu
Seriál