Objectif du Workshop

Créer un blog basique qui contiendra des articles créer par des utilisateurs. Votre blog devra avoir les fonctionnalités suivantes:


Durant ce Workshop, différentes technologies seront utilisées pour la création du blog. Le but principal étant de s'initier au framework Laravel, ainsi, ne perdez pas de temps sur le front-end (aspect visuel) du site.

Rendu final de votre application

A la fin de ce workshop, vous aurez:

Installation de Laragon

Durant ce projet, nous utiliserons un environnement pré-configurés sous Laragon.

Installation Windows 10

Configuration de l'environnement

  1. Télécharger le logiciel Laragon sous Windows https://laragon.org/download/ en version Full.
  2. Clic-droit - "Créer un site web rapidement" - Laravel
  3. Entrez le nom de votre projet (ex: workshop)
  4. Recharger le serveur web (bouton "STOP" puis "Démarrer")
  5. Ouvrir le projet à http://{projectName}.test/

Configuration

Afin d'optimiser le temps sur le développement et non sur l'administration d'un serveur, nous avons pré-configurés tout ce dont vous aurez besoin.

Pour retrouver votre fichier où est installé Laravel, utilisez le bouton "Dossier www" qui vous y redirigera.

Votre serveur web est configuré par défaut sur le port 80.

Un gestionnaire MySQL (PhpMyAdmin) est configuré par défaut, disponible en cliquant sur le bouton "Base de données".

Configurations MySQL:

Hôte: localhost

Port: 3306

Utilisateur: root
Aucun mot de passe n'est configur

Comment y accéder ?

Vous pouvez y accéder en cliquant sur le bouton "Terminal". Les principales commandes que vous aurez besoin d'utiliser seront disponible sous votre systeme Windows.

Késako ?

Le framework Laravel met à votre disposition Artisan qui est une console vous permettant de générer et gérer votre site. Pour l'utiliser, il vous suffit d'être à la racine de votre projet et d'exécuter php artisan tu verras alors apparaître la liste des commandes disponibles.

Cette console va donc nous permettre de générer les différentes parties de notre architecture MVC, à savoir: nos models, nos migrations, nos controllers, ...

Mais vous pourrez aussi interagir directement avec votre site: maintenance, task scheduling, mailings, routes, déploiement...

Testez par vous même comme cet outil peut être intéressant: php artisan down

Rendez-vous sur votre site et observez les changements. Pour sortir du mode maintenance, il vous suffit d'utiliser php artisan up

Imaginez maintenant le temps que vous auriez mit à réaliser un mode maintenance aussi user-friendly si vous n'utiliserez aucun framework ?

Pour commencer notre blog, il va falloir coder notre système d'authentification. Ainsi, différentes pages sont à ne pas oublier pour avoir un système complet et efficace:


Et si je te disais que tu avais 2 minutes pour faire ça ?

Et si je te disais que c'était vraiment faisable en 2 minutes ?

Laravel Authentification

https://laravel.com/docs/7.x/authentication

Ce nom peut paraitre barbare mais c'est pourtant l'un des points fort de Laravel. Tout un système d'authentification complet est embarqué dans le framework.

Quel gain de temps...

A notre clavier, mettons ce que nous avons découvert en pratique: Artisan.

  1. Installons le package laravel/ui qui contient toutes les views et routes que nous aurons besoin pour l'authentification: composer require laravel/ui
  2. On génère l'authentification php artisan ui vue --auth
  3. Il nous reste qu'à installer nos bibliothèques requises via npm puis à compiler le tout dans le fichier public/: npm install puis npm run dev

Et si je vous disais qu'en plus d'avoir générer tout le code d'authentification il avait fait encore mieux que ça ? Spécialement pour nous, Artisan vient de générer tout le contenu front-end sous Bootstrap ainsi que toutes les views.

Une petite visite sur: http://localhost/login pour observer le travail et le bien-être qu'un framework procure 😍

https://laravel.com/docs/7.x/migrations

Les migration sont un système permettant de gérer vos bases de données. C'est l'un des points essentiels pour ce genre de site afin de sauvegarder nos données. Les migrations permettent aussi de créer des schémas de bases de données plus ou moins complexes.

Toutes nos migrations se trouvent dans database/migrations/

Vous y retrouverez alors différents fichiers sous la forme 2014_20_12_000000_create_xxx_table.php

Ces fichiers comprennent une série d'instruction qui va ensuite permettre de générer et structurer votre base de donnée.

Configuration de notre base de donnée

Pour pouvoir accéder aux commandes de migration (via Artisan), il faut impérativement configurer notre base de donnée. Sans cela, vous aurez une erreur vous disant que Laravel ne parvient pas à se connecter au serveur MySQL.

Les configurations de notre serveur se trouvent dans 1 seul et unique fichier: .env

Ce fichier étant assez intuitif, je te laisse ajuster les configurations à ta guise de manière à faire fonctionner le serveur MySQL.

Migrations Laravel Authentification

L'authentification ayant été généré par Laravel, la migration pour les données des utilisateurs l'est aussi. Vous avez donc (si toutes les étapes ont été respectés) un ou plusieurs fichiers dans vos migrations.

Quelques commandes utiles:

php artisan migrate:status : Aperçu de toutes vos migrations et de leur statut (migré ou non)

php artisan migrate : Effectue les migrations qui n'ont pas encore été faites (function up())

php artisan migrate:rollback : Vous permet de reverse vos migrations (function down()) . Vous pouvez ajouter une option --step=X pour appliquer ce rollback aux X dernières migrations.

Il ne vous reste donc plus qu'à valider le tout et effectuer votre première migration générée par Laravel Authentification.

Structure de notre blog

Avant toute chose, il faut réfléchir à la meilleure structure de notre base de donnée pour permettre d'enregistrer toutes les données nécessaires et le plus proprement possible.

Dans notre cas, nous allons réaliser un blog. Nous aurons donc différents "modules" (que nous appelerons ultérieurement des models).

Ceci est (un example d') un schéma de notre base de donnée qui est représentée par 3 models:

On peut aussi apercevoir sur ce schéma des liens entre chaque models, c'est lien seront appelés relationships: https://laravel.com/docs/7.x/eloquent-relationships

Vous allez donc devoir créer ces 3 models ainsi que leurs migrations. Pour cela, une commande existe et fait tout en une seule fois: php artisan make:model -m Model

Page principale ("/")

Actuellement, notre page ressemble à la page par défaut de Laravel.

Le contenu de cette page se trouve dans nos ressources: resources/views/welcome.blade.php

Nous allons pouvoir supprimer ce qui est à l'intérieur car le contenu proposé par Laravel ne correspond pas à ce que nous désirons, et le remplacer par ce code:

resources/views/welcome.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-12">
            <!--Our code here-->
        </div>
    </div>
</div>
@endsection

Quelques explications...

Chaque page est composée d'une route, d'un controller et d'une view.

Pour information, une view se terminent toujours par l'extension .blade.php et utilise le moteur de template Blade. Cela nous permet d'inclure des données, conditions, ... directement dans notre code HTML.

Ainsi, c'est pour cela que nous avons des balises qui commencent par @, il s'agit donc du moteur Blade qui interprète cela en PHP ensuite lors de l'affichage.

Mise en page de la liste des articles

resources/views/welcome.blade.php

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row mb-2">
            <!-- Post 1 -->
            <div class="col-md-6">
                <div class="row border mb-4 shadow-sm h-md-250">
                    <div class="col p-4 d-flex flex-column position-static">
                        <h3 class="mb-0">Title</h3>
                        <div class="mb-1 text-muted">Date</div>
                        <p class="card-text mb-auto">Some content limited to 200 characters...</p>
                        <a href="#" class="stretched-link">Voir le post</a>
                    </div>
                    <div class="d-lg-block">
                        <img class="bd-placeholder-img" width="200" height="250" src="https://www.webnode.com/blog/wp-content/uploads/2016/10/Blog-intro.jpg">
                    </div>
                </div>
            </div>
            <!-- End Post 1 -->
        </div>
    </div>
@endsection

Vous devriez obtenir le résultat suivant:

Restructuration de nos routes/views/controllers

Maintenant que nous avons une mise en page correcte de nos articles, il est temps de s'occuper de l'architecture de notre site qui est un peu en vrac. Des routes qui n'ont aucun sens: welcome, home... pourquoi ces noms ? Où est l'index ? Compliqué de s'y retrouver.

Par défaut, la view welcome ne dispose pas de controller. Nous allons donc renommer cette route en index et lui créer son controller.

Et maintenant, afin d'avoir une architecture correcte de notre site. Nous allons renommer la view home en user et cette vue contiendra ainsi l'espace de l'utilisateur une fois connecté.

Maintenant que nous avons notre architecture correcte, nous allons pouvoir modifier notre menu et dans le menu déroulant nous allons ajouter "Mon compte" qui retournera vers /user lorsque l'utilisateur est connecté.

-> Pas d'indice cette fois-ci, recherchez dans vos fichiers où se trouvent cela...

Affichage des données stockées

Il est temps d'afficher nos données stockées sur notre page "index" et rendre notre site dynamique avec les vrais articles que nous avons en base de donnée.

Pour cela, nous allons nous rendre dans notre controller correspondant et nous allons récupérer avec Eloquent nos différentes données.

La documentation officielle: https://laravel.com/docs/7.x/eloquent#retrieving-models

Comment envoyer des données à notre page ?

C'est très simple, il suffit de retourner ces mêmes données dans le view.

Exemple:

class IndexController extends Controller
{
    public function index()
    {
        return view('index')
            ->with('variable', 'value');
    }
}

Et dans notre view, nous pouvons récupérer notre variable de la manière suivante: {{ $variable }} qui affichera "value".

Dans notre cas, nous récupérerons un Query Builder qui contiendra toutes nos valeurs. Pour le parcourir il suffit de faire un foreach.
Exemple:

@foreach ($queryBuilder as $element)
    {{ $element->title }}
@endforeach

Création du controler

Notre site est basé sur la publication d'article, il nous reste donc à gérer la publication et la modification de nos articles.

Pour cela, nous utiliserons un CRUD qui signifie: Create, Read, Update, Delete. Laravel (et notamment Artisan) permettent de générer notre base de code, on appel cela un Resources Controller.

Plus d'informations sur la documentation officielle: https://laravel.com/docs/5.7/controllers#resource-controllers

Commençons!

Créer son CRUD en quelques étapes:

Tout se déroule dans le controller que nous venons de créer: app/Http/Controllers/PostController.php

Chaque fonction correspond à une route. Il est temps de remplir ces fonctions.

Que faire ?

Il est temps de créer les rendus (donnés en HTML ci-dessus) et de faire rediriger les fonctions correspondantes dans votre controller

Rendu HTML

Le rendu HTML de chaque page est donné ci-dessous:

resources/views/post/show.blade.php

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row mb-2">
            <div class="col-md-12 blog-main">
                <div class="row border-bottom mb-4">
                    <div class="col-md-8">
                        <h3 class="pb-4 font-italic">
                            Article #[ID]
                        </h3>
                    </div>
                    <!-- Only for the creator of the post -->
                    <div class="col-md-4 text-right">
                        <form>
                            <a class="btn btn-outline-primary" href="{{ route('posts.edit', $post) }}">Modifier</a>
                            <button type="submit" class="btn btn-outline-danger">Supprimer</button>
                        </form>
                    </div>
                    <!-- End: Only for the creator of the post -->
                </div>

                <div class="blog-post">
                    <h2 class="blog-post-title">[Article title]</h2>
                    <p class="blog-post-meta">[Date], par <a href="#">[Author]</a></p>
                    <p>Content</p>
                </div>
            </div>
        </div>
    </div>
@endsection

resources/views/post/create.blade.php

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="py-5 text-center">
            <h2>Publication d'un article</h2>
            <p class="lead">Remplir ce formulaire pour voir son article publié.</p>
        </div>

        <form>
            @csrf
            <div class="row">
                <div class="col-md-12">
                    <div class="mb-3">
                        <label for="title">Titre</label>
                        <input type="text" id="title" name="title" placeholder="Entrez le titre de votre article..." required="required" class="form-control">
                    </div>
                    <div class="mb-3">
                        <label for="title">Contenu</label>
                        <textarea id="content" name="content" placeholder="Entrez le contenu de votre article..." rows="10" required="required" class="form-control"></textarea>
                    </div>
                </div>
                <div class="col-md-12 text-right">
                    <button type="reset" class="btn btn-outline-secondary">Annuler</button>
                    <button type="submit" class="btn btn-outline-primary">Publier l'article</button>
                </div>
            </div>
        </form>
    </div>
@endsection

resources/views/post/edit.blade.php

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="py-5 text-center">
            <h2>Edition d'un article</h2>
            <p class="lead">Article #[ID]</p>
        </div>

        <form>
            @csrf
            <div class="row">
                <div class="col-md-12">
                    <div class="mb-3">
                        <label for="title">Titre</label>
                        <input type="text" id="title" name="title" value="[VALUE TITLE]" placeholder="Entrez le titre de votre article..." required="required" class="form-control">
                    </div>
                    <div class="mb-3">
                        <label for="content">Contenu</label>
                        <textarea id="content" name="content" placeholder="Entrez le contenu de votre article..." rows="10" required="required" class="form-control">[VALUE CONTENT]</textarea>
                    </div>
                </div>
                <div class="col-md-12 text-right">
                    <button type="reset" class="btn btn-outline-secondary">Annuler</button>
                    <button type="submit" class="btn btn-outline-primary">Editer l'article</button>
                </div>
            </div>
        </form>
    </div>
@endsection

Nous avons maintenant nos 3 pages: création, affichage et édition d'un article.

Création d'un article

Cette étape est cruciale pour tout site internet, la réalisation des formulaires.

Commençons par la création d'un article, profitez car sur celui là vous serez bien guidé!

resources/views/post/create.blade.php

<form action="{{ route('posts.store') }}" method="POST">
    @csrf
    @method('POST')
</form>

Voici un exemple de form. Quelques explications:

Une fois que nous appuyons sur un button de type submit, la requête sera alors envoyé à notre controler.

app/Http/Controllers/PostController.php

public function store(Request $request)
{
    dd($request->input());
}

Vous pourrez donc apercevoir, une fois le formulaire envoyé, des données similiaires à :

Nous retrouvons donc notre token CSRF, notre method et les différents composants de notre formulaire (dans notre cas: title, content).

Maintenant que nous avons toutes les données de notre formulaire, il nous reste qu'à vérifier qu'elles soient correctes et les enregistrer en base de donnée!

Pour cela nous utiliserons les validators: https://laravel.com/docs/5.8/validation

Voici le validator pour la création d'un post:

app/Http/Controllers/PostController.php

public function store(Request $request)
{
    $request->validate([
        'title' => 'required|min:5|unique:posts',
        'content' => 'required|min:15',
    ]);

    dd("form ok");
}

Affichage des erreurs dans la view:

resources/views/posts/create.blade.php

@if ($errors->any())
    <div class="alert alert-danger">
        <b>Erreurs:</b>
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

Maintenant que nous avons la validation de notre formulaire, nous n'avons plus qu'à enregistrer en base de donnée notre formulaire et retourner l'utilisateur sur le post.

app/Http/Controllers/PostController.php

public function store(Request $request)
{
    // On vérifie que les données du formulaires sont correctes
    $request->validate([
        'title' => 'required|min:5|unique:posts', // On vérifie que l'input "title" est présente, avec 5 char minimum et n'est pas utilisé par un autre article.
        'content' => 'required|min:15', // On vérifie que l'input "content" est présente.
    ]);

    // On enregistre les données
    $post = Post::create([
        'user_id' => Auth::user()->id, // 'user_id' de Post devient l'id de l'utilisateur actuel (celui qui créer le post).
        'title' => $request->input('title'), // On enregistre le titre
        'content' => $request->input('content'), // On enregistre le contenu
    ]);
    return (redirect()->route('posts.show', $post)); // On redirige l'utilisateur vers l'article qui vient d'être créer
}

Nous avons donc fini de coder la création d'un article. Ce code vous permettra de comprendre le fonctionnement.

Edition d'un article

C'est à vous cette fois-ci! Vous avez les clés en mains pour éditer votre article existant.

Suppression d'un article

La suppression d'un article est un peu différente, il s'agit d'un formulaire sans aucun input.

La pratique consiste donc à déclarer une nouvelle balise

qui redirige vers la route correspondante et y insérer à l'intérieur notre