Tutoriel Laravel 9 #7 : Créer des routes, des contrôleurs et des vues

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

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') }}
Nouveau Tutoriel

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.