Enregistrement des routes
Avant de commencer à ajouter nos routes, nous allons créer rapidement nos contrôleurs, nous y reviendrons par la suite pour les modifier :
php artisan make:controller CategoryController --invokable
php artisan make:controller TagController --invokable
php artisan make:controller PostController
Nous pouvons maintenant mettre à jours nos routes dans le fichier routes/web.php
use App\Http\Controllers\CategoryController;
use App\Http\Controllers\IndexController;
use App\Http\Controllers\PostController;
use App\Http\Controllers\TagController;
Route::get('/', IndexController::class);
Route::get('/category/{slug}', CategoryController::class);
Route::get('/tag/{slug}', TagController::class);
Route::get('/post/{slug}', [PostController::class, 'show']);
Nous n’avons pas utilisé le contrôleur à action unique pour le contrôleur PostController parce que nous allons ajouter une fonction search
dans le prochain article.
Contrôleurs
Contrôleur d'index
<?php
namespace
App\Http\Controllers;
use App\Models\Post;
use App\Models\Tag;
use App\Models\Category;
use Illuminate\Http\Request;
class IndexController extends Controller {
public function __invoke() {
//obtient les messages qui sont publiés, triés par ordre décroissant de "id".
$posts = Post::query()->where('is_published',true) ->orderBy('id','desc') ->get(); //obtenir les articles vedettes $featured_posts = Post::query() ->where('is_published',true) ->where('is_featured',true) ->orderBy('id','desc') ->take(5) ->get(); //obtient toutes les catégories $categories = Category::all(); //obtient tous les tags $tags = Tag::all(); //obtient les 5 derniers articles $recent_posts = Post::query() ->where('is_published',true) ->orderBy('created_at','desc') ->take(5) ->get(); //assigner les variables à la vue correspondante return view('home', [ 'posts' => $posts, 'featured_posts' => $featured_posts, 'categories' => $categories, 'tags' => $tags, 'recent_posts' => $recent_posts ]); } }
Contrôleur de catégorie
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use App\Models\Tag;
use App\Models\Category;
use Illuminate\Http\Request;
class CategoryController extends Controller
{
public function __invoke($slug)
{
//obtient la catégorie demandée
$category = Category::query()
->where('slug', $slug)
->firstOrFail();
//obtenir les messages de cette catégorie
$posts = $category->posts()
->where('is_published',true)
->orderBy('id','desc')
->get();
//obtient toutes les catégories
$categories = Category::all();
//obtient tous les tags
$tags = Tag::all();
//obtient les 5 derniers messages
$recent_posts = Post::query()
->where('is_published',true)
->orderBy('created_at','desc')
->take(5)
->get();
//assigner les variables à la vue correspondante
return view('category', [
'category' => $category,
'posts' => $posts,
'categories' => $categories,
'tags' => $tags,
'recent_posts' => $recent_posts
]);
}
}
Contrôleur des tags
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use App\Models\Tag;
use App\Models\Category;
use Illuminate\Http\Request;
class TagController extends Controller
{
public function __invoke($slug)
{
//obtient la tag par rapport au slug
$tag = Tag::query()
->where('slug', $slug)
->firstOrFail();
//obtient les articles publié en fonction du tag
$posts = $tag->posts()
->where('is_published',true)
->orderBy('id','desc')
->get();
//obtient tous les articles
$categories = Category::all();
//obtient tous les tags
$tags = Tag::all();
//obtient les 5 articles récents
$recent_posts = Post::query()
->where('is_published',true)
->orderBy('created_at','desc')
->take(5)
->get();
//assigner les variables à la vue
return view('tag', [
'tag' => $tag,
'posts' => $posts,
'categories' => $categories,
'tags' => $tags,
'recent_posts' => $recent_posts
]);
}
}
Contrôleur des articles
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use App\Models\Tag;
use App\Models\Category;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function show($slug)
{
//obtient le message demandé, s'il est publié.
$post = Post::query()
->where('is_published', true)
->where('slug', $slug)
->firstOrFail();
//obtient toutes les catégories
$categories = Category::all();
//obtient tous les tags
$tags = Tag::all();
//obtient les 5 derniers messages
$recent_posts = Post::query()
->where('is_published', true)
->orderBy('created_at', 'desc')
->take(5)
->get();
//assigner les variables à la vue
return view('post', [
'post' => $post,
'categories' => $categories,
'tags' => $tags,
'recent_posts' => $recent_posts,
]);
}
}
Vues
Dans ce tutoriel, nous allons utiliser un template Bootstrap pour nos vues.Vous pouvez télécharger le code source ici :
En supposant que vous comprenez le fonctionnement de HTML, CSS et JS. Voici la structure des vues blades que nous allons concevoir :
- views
- _partials
- posts-list.blade.php
- sidebar.blade.php
- master.blade.php
- home.blade.php
- category.blade.php
- tag.blade.php
- post.blade.php
- _partials
Mise en page master.blade.php
<!DOCTYPE html>
<html lang="fr">
<head>
@yield('meta')
@yield('title')
<!-- Bootstrap core CSS -->
<link href="{{asset('vendor/bootstrap/css/bootstrap.css')}}" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="{{asset('css/blog-home.css')}}" rel="stylesheet">
<link href="{{asset('css/css/blog-post.css')}}" rel="stylesheet">
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
<div class="container">
<a class="navbar-brand" href="/">{{setting('site.title')}}</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive"
aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item active">
<a class="nav-link" href="/">Accueil</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://www.gekkode.com/category/developpement/laravel/">Laravel
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://www.gekkode.com/category/developpement/tutoriel/">Tutoriels</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- Page Content -->
<div class="container">
@yield('content')
</div>
<!-- /.container -->
<!-- Footer -->
<footer class="py-5 bg-dark">
<div class="container">
<p class="m-0 text-center text-white">Copyright
© {{setting('site.title')}} <?php echo date("Y"); ?></p>
</div>
<!-- /.container -->
</footer>
<!-- Bootstrap core JavaScript -->
<script src="{{asset('vendor/bootstrap/js/jquery/jquery.min.js')}}"></script>
<script src="{{asset('vendor/bootstrap/js/bootstrap.bundle.min.js')}}"></script>
</body>
</html>
Ligne 11, {{asset('vendor/css/bootstrap.min.css')}}
génère l’URL /public/vendor/css/bootstrap.min.css
. Liste des messages posts-list.blade.php
@foreach($posts as $post)
<!-- Blog Post -->
<div class="card mb-4">
<img class="card-img-top" src="{{Illuminate\Support\Facades\Storage::url($post['featured_image'])}}" alt="Card image cap">
<div class="card-body">
<h2 class="card-title">{{$post['title']}}</h2>
<p class="card-text">{{Illuminate\Support\Str::limit(strip_tags($post['content']), 200, '...')}}</p>
<a href="http://localhost:8000/post/{{$post['slug']}}" class="btn btn-primary">En savoir plus →</a>
</div>
<div class="card-footer text-muted">
Posté le {{$post->created_at->format('d/m/Y')}} par {{$post->user['name']}}
</div>
</div>
@endforeach
Barre latérale sidebar.blade.php
<!-- Sidebar Widgets Column -->
<div class="col-md-4">
<!-- Search Widget -->
<div class="card my-4">
<h5 class="card-header">Rechercher</h5>
<form class="card-body" action="" method="GET" role="search">
<div class="input-group">
<input type="text" class="form-control" placeholder="Rechercher..." name="q">
<span class="input-group-btn">
<button class="btn btn-secondary" type="submit">Go!</button>
</span>
</div>
</form>
</div>
<!-- Categories Widget -->
<div class="card my-4">
<h5 class="card-header">Catégories</h5>
<div class="card-body">
<div class="row">
<div class="col-lg-6">
<ul class="list-unstyled mb-0">
@foreach($categories as $category)
<li>
<a href="http://localhost:8000/category/{{$category['slug']}}">{{$category['name']}}</a>
</li>
@endforeach
</ul>
</div>
</div>
</div>
</div>
<!-- Tags Widget -->
<div class="card my-4">
<h5 class="card-header">Tags</h5>
<div class="card-body">
<div class="row">
<div class="col-lg-6">
<ul class="list-unstyled mb-0">
@foreach($tags as $tag)
<li>
<a href="http://localhost:8000/tag/{{$tag['slug']}}">{{$tag['name']}}</a>
</li>
@endforeach
</ul>
</div>
</div>
</div>
</div>
<!-- Recent Posts Widget -->
<div class="card my-4">
<h5 class="card-header">Articles récents</h5>
<div class="card-body">
<div class="row">
<div class="col-lg-12">
<ul class="list-unstyled mb-0">
@foreach($recent_posts as $post)
<li>
<a href="http://localhost:8000/post/{{$post['slug']}}">{{$post['title']}}</a>
</li>
<hr>
@endforeach
</ul>
</div>
</div>
</div>
</div>
<!-- Side Widget -->
<div class="card my-4">
<h5 class="card-header">Tutoriels</h5>
<div class="card-body">
<ul class="list-unstyled mb-0">
<li>
<a href="https://www.gekkode.com/developpement/tutoriel-laravel-8-pour-les-debutants/">Tutoriel Laravel 8 pour Débutants</a>
</li>
</ul>
</div>
</div>
</div>
Page d'accueil home.blade.php
@extends('master')
@section('meta')
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="{{setting('site.description')}}">
<meta name="author" content="Gekkode">
@endsection
@section('title')
<title>{{setting('site.title')}}</title>
@endsection
@section('content')
<div class="row">
<!-- Blog Entries Column -->
<div class="col-md-8">
<h1 class="my-4">Laravel Blog
<small>Page d'accueil</small>
</h1>
@include('_partials.posts-list')
</div>
@include('_partials.sidebar')
</div>
@endsection
Page de catégorie category.blade.php
@extends('master')
@section('meta')
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="{{setting('site.description')}}">
<meta name="author" content="Gekkode">
@endsection
@section('title')
<title>{{setting('site.title')}} - Categories:{{$category['name']}}</title>
@endsection
@section('content')
<div class="row">
<!-- Blog Entries Column -->
<div class="col-md-8">
<h1 class="my-4">Catégories:
<small>{{$category['name']}}</small>
</h1>
@include('_partials.posts-list')
</div>
@include('_partials.sidebar')
</div>
@endsection
Page d'un tag tag.blade.php
@extends('master')
@section('meta')
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="{{setting('site.description')}}">
<meta name="author" content="Gekkode">
@endsection
@section('title')
<title>{{setting('site.title')}} - Tag:{{$tag['name']}}</title>
@endsection
@section('content')
<div class="row">
<!-- Blog Entries Column -->
<div class="col-md-8">
<h1 class="my-4">Tag:
<small>{{$tag['name']}}</small>
</h1>
@include('_partials.posts-list')
</div>
@include('_partials.sidebar')
</div>
@endsection
Page des articles post.blade.php
@extends('master')
@section('meta')
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="{{setting('site.description')}}">
<meta name="author" content="Gekkode">
@endsection
@section('title')
<title>{{$post['title']}} - {{setting('site.title')}}</title>
@endsection
@section('content')
<div class="row">
<!-- Post Content Column -->
<div class="col-lg-8">
<!-- Title -->
<h1 class="mt-4">{{$post['title']}}</h1>
<!-- Author -->
<p class="lead">
par
{{$post->user['name']}}
</p>
<hr>
<!-- Date/Time -->
<p>Posté le {{$post->created_at->format('d/m/Y')}}</p>
<hr>
<!-- Preview Image -->
<img class="img-fluid rounded" src="{{Illuminate\Support\Facades\Storage::url($post->featured_image)}}" alt="">
<hr>
<!-- Post Content -->
{!! $post->content !!}
<hr>
</div>
@include('_partials.sidebar')
</div>
@endsection
Ligne 39, {!! $post->content !!}
Obtenir le contenu de l’article. {!! !!}
doit être utilisé, sinon les balises HTML ne fonctionneront pas.
Par défaut, Blade {{ }}
sont automatiquement envoyées par l’intermédiaire de l’interface PHP htmlspecialchars
de PHP pour éviter les attaques XSS. Voyager
Rappel : Voyager intègre une gestion des configurations d’où on peut paramétrer le nom du site et la description notamment, c’est ici que vous allez pouvoir donner un nom à votre site et une description pour les informations de base de notre site web. Allez dans les paramètres et voici ce que vous verrez :
Pour accéder à ces informations :
{{ setting('site.title') }}
Tutoriel Laravel 9
Newsletter
Ne manquez jamais les nouveaux conseils, tutoriels et autres.
Pas de spam, jamais. Nous ne partagerons jamais votre adresse électronique et vous pouvez vous désabonner à tout moment.