Vlastní blog v Laravel: Zobrazení článku

Aktualizováno pro Laravel 10

Doteď jsme se zabývali především CRUD operacemi, tedy pro práci s články. Nicméně stále nám chybí zobrazení samotného článku, které si probereme v tomto díle.

Metoda pro zobrazení

Poslední metoda v Http/Controllers/PostController.php, která nám schází upravit, je show():

public function show(Post $post)  
{  
	return view('posts.post', compact('post'));  
}

Stejně jako v předchozích díle, i zde pro ulehčení využiji rovnou explicitní binding a vytáhnu si celý článek, který pak předám do šablony.

Relace pro autora a kategorii

Ve článku budeme chtít určitě zobrazit i jeho autora a kategorii. Díky tomu, že jsme si hned na začátku vytvořili v tabulce posts sloupce user_id a category_id, tak jsme si definovali vztah 1:n. Tedy že jeden uživatel/kategorie může mít mnoho článků, ale obráceně článek může mít pouze jednoho uživatele a kategorii. Více informací o relacích najdete v tomto seriálu.

Jedná se o nejjednodušší vazbu, kdy využijeme metodu belongsTo(). Jako první si upravíme model app/Models/Post.php, kde si přidáme novou metodu:

public function user()
{
	return $this->belongsTo(User::class);
}

V tomto případě se Eloquent pokusí najít User model, který má id shodující se s hodnotou ve sloupci user_id v modelu Post. Eloquent určuje cizí klíč na základě názvu relační metody (tedy v našem případě je to user), poté přidá příponu _ a nakonec následuje název primárního klíče z rodičovského modelu. Ve výsledku tedy Eloquent předpokládá, že cizí klíč na tabulku users bude user_id.

Laravel je však v tomto velmi flexibilní a v případě, že vaše relace nenásleduje tyto konvence, můžete jako druhý argument přidat vlastní cizí klíč:

public function user()
{
	return $this->belongsTo(User::class, 'jiny_cizi_klic');
}

Pokud váš rodičovský model nepoužívá sloupec id jako primární klíč nebo potřebujete svázat model s jiným sloupcem, pak můžete využít třetí argument metody belongsTo pro specifikování vlastního rodičovského klíče:

public function user()
{
	return $this->belongsTo(User::class, 'jiny_cizi_klic', 'rodicovsky_klic');
}

Úplně to samé pak platí pro model kategorie, kdy si do modelu Post přidáme novou metodu:

public function category()
{
	return $this->belongsTo(Category::class);
}

Šablona

Pro jednoduchost zde nebude žádná větší logika a vzhled uděláme co nejjednodušší. Vytvoříme si novou šablonu resources/views/posts/post.blade.php:

@extends('layouts.app')

@section('title', $post->title)

@section('content')
	<div class="py-12">
		<h1 class="text-2xl font-semibold mb-4">{{ $post->title }}</h1>
		<p>Autor: {{ $post->user->name }}</p>
		<p>Kategorie: {{ $post->category->name }}</p>
		<p>Vytvořeno: {{ $post->created_at->format('d.m.Y H:i') }}</p>
		<br>
		{{ $post->content }}
	</div>
@endsection

Do sekce title jsem přidal název článku abychom při načtení webové stránky měli v záhlaví rovnou název článku a ne výchozí text "Můj blog", id článku či něco podobného.

U autora a kategorie jsem využil vazeb, které jsme si před chvilkou vytvořili v modelu Post. Díky této syntaxi můžete libovolně přecházet do vazeb modelu. Jedná se o tzv. "lazy loading" a Laravel získává data uživatele jen tehdy, když se pokusíte přistoupit k vlastnosti modelu User. V praxi to znamená, že Laravel vykoná další dotaz na databázi, aby získal uživatele pro tento článek, když se pokusíte přistoupit k user. Po získání uživatele můžete přistupovat k jeho vlastnostem, jako je v našem případě name. Stejná logika pak platí i na kategorii.

Jako poslední zmíním formátování data a času. Když jsme hned na začátku seriálu vytvářeli migraci pro tabulku post tak jsme si vytvořili i dva nové timestamp sloupce created_at a update_at:

$table->timestamps();

// ktery je jen sugar syntax pro
$this->timestamp('created_at', $precision)->nullable();  
$this->timestamp('updated_at', $precision)->nullable();

Laravel automaticky převádí tyto sloupce na instanci typu Carbon. Carbon je PHP knihovna, která usnadňuje práci s daty a časy. Je založena na nativní PHP třídě DateTime, ale přidává mnoho užitečných funkcí a je mnohem příjemnější na použití.

Některé z funkcí Carbonu zahrnují:

  1. Snadnou manipulaci s daty: Carbon poskytuje metody pro přidávání a odečítání jednotek času (například dnů, měsíců, let, hodin, minut atd.) od daného data.
$now = Carbon::now();
$tomorrow = $now->addDay();
$lastWeek = $now->subWeek();
  1. Lidsky čitelný formát: Carbon umožňuje snadné formátování dat a časů pro výstup lidsky čitelným způsobem.
echo $now->diffForHumans();  // "1 second ago"
  1. Lokalizace: Carbon podporuje lokalizaci, takže můžete formátovat data a časy pro různé jazyky a kultury.
  2. Převod mezi časovými pásmy: Carbon usnadňuje převod dat a časů mezi různými časovými pásmy.
  3. Porovnání dat: Carbon poskytuje metody pro porovnání dvou dat a zjištění, které je dřívější nebo pozdější.
  4. Převod na a z timestampu: Carbon umožňuje snadné převádění mezi objekty Carbon a Unix timestampy.

Pokud máte v tabulce sloupec podobného typu datetime, pak ho můžete automaticky převádět do instance Carbonu pomocí přetypování v modelu Post:

protected  $casts  = [
	'valid_date'  =>  'datetime',
];

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 odkaz na daný článek:

<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">
				<a class="underline" href="{{ route('posts.show', $post->id) }}">{{ $post->title }}</a>
			</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>
				<form action="{{ route('posts.destroy', $post->id) }}" method="POST" class="inline">
					@csrf
					@method('DELETE')
					<button type="submit" class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded">Smazat</button>
				</form>
			</td>
		</tr>
	@endforeach
</tbody>

Závěr

A to je poslední díl této série. V případě zájmu můžu pokračovat v rozvíjení tohoto blogu a přidat registraci/přihlašování, další funkcionality, vylepšit vzhled a mnoho dalšího. Dejte vědět o co by jste měli zájem a zkusím něco sepsat.

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

  1. 1. Úvod a instalace
  2. 2. Příprava databáze
  3. 3. Layout a zobrazení článků
  4. 4. Vytvoření článku
  5. 5. Editace článku
  6. 6. Smazání článku
  7. 7. Zobrazení článku