Vlastní blog v Laravel: Layout a zobrazení článků

Aktualizováno pro Laravel 10

V tomto díle se podíváme, jak vytvořit základní layout v Laravelu, který můžete použít pro všechny své stránky. Tento layout bude obsahovat navigaci a hlavičku. Obsah každé stránky bude měnitelný, aniž byste museli upravovat samotný layout.

Laravel využívá pro šablony Blade, který umožňuje psát dynamický obsah přímo do HTML šablon. Blade poskytuje snadno čitelný a jednoduchý zápis pro vkládání PHP kódu a řízení logiky zobrazení. V našem případě jsme vytvořili layout, který obsahuje navigaci a hlavičku.

Zde je základní struktura našeho layoutu v resources/views/layouts/app.blade.php:

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1">
		<meta name="csrf-token" content="{{ csrf_token() }}">

		<title>@yield('title', 'Můj blog')</title>

		<!-- Fonts -->
		<link rel="preconnect" href="https://fonts.bunny.net">
		<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet"/>
		<script src="https://cdn.tailwindcss.com"></script>
	</head>
	<body class="bg-gray-100">
		<nav class="bg-white p-4 shadow-md">
			<div class="container mx-auto">
				<ul class="flex">
					<li class="mr-4">
						<a href="/" class="text-blue-500 hover:text-blue-800">Domů</a>
					</li>
				</ul>
			</div>
		</nav>

		<div class="container mx-auto mt-8">
			@yield('content')
		</div>

		<script src="{{ asset('js/app.js') }}"></script>
	</body>
</html>

V této šabloně používáme několik Blade direktiv:

  • @yield: Tato direktiva slouží k vložení obsahu z dceřiné šablony. V našem případě máme dvě sekce - title a content. Sekce title má výchozí hodnotu 'My Laravel App', která se použije, pokud dceřiná šablona tuto sekci nepřepíše.
  • {{ }}: Dvojité složené závorky umožňují vkládat proměnné nebo výrazy PHP. V našem případě používáme funkci asset() pro načítání CSS a JavaScript souborů.

Nyní si představme dceřinou šablonu, která rozšiřuje náš layout - resources/views/posts/index.blade.php:

@extends('layouts.app')

@section('title', 'Homepage')

@section('content')
	<h1 class="text-2xl font-semibold mb-4">Články</h1>

	<div class="py-12">
		<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
			<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
				<div class="p-6 text-gray-900">
					{{-- obsah --}}
				</div>
			</div>
		</div>
@endsection

V této dceřiné šabloně používáme následující direktivy:

  • @extends: Tato direktiva říká, že naše dceřiná šablona rozšiřuje layout layouts.app. Výsledný HTML kód bude obsahovat kombinaci obou šablon.
  • @section: Tato direktiva definuje obsah, který se vloží do @yield direktivy v layoutu. V našem případě máme dvě sekce - title a content. title sekce přepisuje výchozí hodnotu v layoutu, zatímco content sekce obsahuje vlastní obsah stránky.

Při vytváření dalších stránek stačí vytvořit novou Blade šablonu, která rozšiřuje layout layouts.app a definuje sekci content s obsahem této stránky. To umožňuje jednoduše měnit obsah stránek, aniž byste museli upravovat samotný layout.

Například, pokud chcete vytvořit stránku "O nás", vytvořte nový soubor resources/views/static/about.blade.php a přidejte následující kód:

@extends('layouts.app')

@section('title', 'O nás')

@section('content')
	<h1>O nás</h1>
	<p>Tady můžete napsat informace o vaší společnosti, týmu atd.</p>
@endsection

Tímto způsobem můžete snadno vytvářet nové stránky, které sdílejí stejný základní layout, ale mají různý obsah.

Šablona s výpisem článků

Nyní si upravíme šablonu resources/views/posts/index.blade.php, kde si zobrazíme tabulku s výpisem všech našich článků. Namísto {{-- obsah --}} vložíme toto:

<table class="border-collapse table-auto w-full text-sm">
						<thead>
							<tr>
								<th class="border-b font-medium p-4 pl-8 pt-0 pb-3 text-slate-400 text-left">Název</th>
								<th class="border-b font-medium p-4 pl-8 pt-0 pb-3 text-slate-400 text-left">Vytvořeno</th>
								<th class="border-b font-medium p-4 pl-8 pt-0 pb-3 text-slate-400 text-left">Upraveno</th>
								<th class="border-b font-medium p-4 pl-8 pt-0 pb-3 text-slate-400 text-left">Akce</th>
							</tr>
						</thead>
						<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">
									</td>
								</tr>
							@endforeach
						</tbody>
					</table>

V sekci obsahu máme tabulku článků:

  • @foreach ($posts as $post): Tato Blade direktiva slouží pro procházení kolekcí článků. V našem případě je kolekce $posts předána z kontroleru. Pro každý článek v kolekci se provede blok kódu uvnitř direktivy @foreach.
  • < tr >...< /tr >: Pro každý článek vytvoříme nový řádek tabulky.
  • {{ $post->title }}, {{ $post->created_at }}, a {{ $post->updated_at }}: V jednotlivých buňkách tabulky zobrazujeme titulek, datum vytvoření a datum úpravy článku. Dvojité složené závorky {{ ... }} slouží k vypsání hodnoty proměnných.

Tento kód vytváří stránku s tabulkou článků a zobrazuje informace o jednotlivých článcích, které jsou předány z kontroleru pomocí proměnné $posts.

Controller s články

Když už máme šablonu, je potřeba vytvořit controller, který nám do šablony předá data. Abychom si práci ulehčili, vytvoříme si rovnou resource controller, což je speciální typ controlleru, který obsahuje metody pro základní CRUD operace (vytvoření, čtení, úprava a mazání) v souvislosti s určitým modelem. Pro vytvoření resource kontroleru použijeme následující Artisan příkaz:

php artisan make:controller PostController --resource

Tento příkaz vytvoří nový soubor PostController.php ve složce app/Http/Controllers. Přepínač --resource říká Artisanu, že chceme vytvořit controller s funkcemi pro základní CRUD operace. V nově vytvořeném controlleru vidíte, že obsahuje následující metody:

  1. index(): Zobrazuje seznam všech článků.
  2. create(): Zobrazuje formulář pro vytvoření nového článku.
  3. store(Request $request): Ukládá nově vytvořený článek do databáze.
  4. show($id): Zobrazuje detail jednoho článku.
  5. edit($id): Zobrazuje formulář pro úpravu článku.
  6. update(Request $request, $id): Aktualizuje článek v databázi.
  7. destroy($id): Odstraňuje článek z databáze.

Pro naše potřeby v tomto dílu nás bude zajímat pouze metoda index(). Tu si upravíme takto:

public function index()
{
    return view('posts.index', [
        'posts' => Post::query()->orderByDesc('created_at')->get()
    ]);
}

Podívejme se podrobněji na jednotlivé části této metody:

  • Post::query()->orderByDesc('created_at')->get(): Zde vytváříme dotaz na databázi pomocí Eloquent modelu Post. Řadíme články sestupně podle data vytvoření (nejnovější nahoře) a načítáme všechny záznamy z databáze pomocí metody get().
  • return view('posts.index', [...]): Metoda view() vytváří nový objekt View s názvem posts.index (reálná adresa pohledu v adresáři resources/views, tedy v posts/index.blade.php). Do šablony předáváme data pomocí asociativního pole, kde klíč posts obsahuje načtené články z databáze.

Posledním krokem je vytvoření routes, tedy reálných webových adres. Pro propojení metod controlleru s URL adresami musíme zaregistrovat trasy v souboru routes/web.php. Laravel umožňuje automaticky zaregistrovat všechny potřebné trasy pro resource controller pomocí jediné metody:

Route::resource('posts', 'PostController');

Tímto způsobem zaregistrujeme následující trasy:

  • GET posts pro metodu index()
  • GET posts/create pro metodu create()
  • POST posts pro metodu store()
  • GET posts/{post} pro metodu show()
  • GET posts/{post}/edit pro metodu edit()
  • PUT/PATCH posts/{post} pro metodu update()
  • DELETE posts/{post} pro metodu destroy()

Nyní máme vytvořený resource controller a zaregistrované trasy pro články. Jako poslední si vytvoříme novou routu pro šablonu "O nás" společně s controllerem.

Stránka "O nás"

Jako první si vytvoříme controller:

php artisan make:controller AboutUsController

Ve kterém si přidáme metodu index() která pouze vrátí šablonu about.blade.php kterou jsme si dříve v tomto díle vytvořili:

class AboutUsController extends Controller
{
    public function index()
    {
    	return view('static.about');
    }
}

Nakonec nám už chybí jen zaregistrovat novou routu v routes/web.php:

Route::get('about-us', [AboutUsController::class, 'index']);

Závěr

Všechny routy mám v angličtině, nicméně v reálu registrujeme české routy. Nic vám tedy nebrání zvolit si názvy cest jak chcete.

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