Laravel 8

Créer un blog – social, erreurs, traductions et événement

Nous avons dans le précédent article mis en place le formulaire de contact et les pages. Maintenant on va compléter le blog en gérant les liens sociaux. Nous allons aussi harmoniser les pages d’erreur (404 et autres) pour qu’elles conviennent à l’esthétique du blog. D’autre part on va prévoir un événement commun pour la création d’un utilisateur, un article, un contact ou un commentaire pour ensuite pouvoir notifier les personnes concernées. Enfin on va passer tous les textes en français.

Vous pouvez télécharger le code final de cet article ici.

Les liens sociaux

Dans notre blog on trouve les liens sociaux en deux emplacements :

On va rendre tout ça modifiable par l’administrateur parce que ça peut évoluer.

Pour ces liens on prévoit ces données :

  • une url
  • un titre

Et on se passera de date.

La migration

Comme on l’a fait déjà plusieurs fois on crée simultanément le modèle et la migration (on n’aura pas besoin de factory et de contrôleur) :

php artisan make:model Follow -m

On code la migration :

public function up()
{
    Schema::create('follows', function (Blueprint $table) {
        $table->id();
        $table->string('href');
        $table->string('title');
    });
}

Le modèle Follow

Dans le modèle on ajoute la propriété $fillable, on précise l’absence de date et on enlève le trait pour le factory :

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Follow extends Model
{
    protected $fillable = ['href', 'title'];

    public $timestamps = false;
}

La population

Dans DatabaseSeeder on génère 4 enregistrements :

// Social
DB::table('follows')->insert([
    ['title' => 'Twitter', 'href' => '#'],
    ['title' => 'Facebook', 'href' => '#'],
    ['title' => 'Dribbble', 'href' => '#'],
    ['title' => 'Instagram', 'href' => '#'],
]);

Vous pouvez régénérer toute la base (on est obligé pour avoir la population) :

php artisan migrate:fresh –seed

Vérifiez que vous avez bien généré les 4 enregistrements :

L’envoi des données

On va compléter HomeComposer pour envoyer systématiquement les liens sociaux :

use App\Models\{ Category, Page, Follow };

...

public function compose(View $view)
{
    $view->with([
        'categories' => Category::has('posts')->get(),
        'pages'      => Page::select('slug', 'title')->get(),
        'follows'    => Follow::all(),
    ]);
}

Les vues

On va maintenant mettre à jour le layout (font.layout) pour afficher dans le footer les liens à partir des données de la table :

<div class="column large-2 medium-3 tab-6 s-footer__social-links">
    
    <h5>@lang('Follow Us')</h5>

    <ul>
        @foreach($follows as $follow)
            <li><a href="{{ $follow->href }}">{{ $follow->title }}</a></li>
        @endforeach
    </ul>

</div>

Pour ce qui concerne le diaporama (heros) ça se passe dans la vue front.index :

<div class="s-hero__social hide-on-mobile-small">
    <p>@lang('Follow')</p>
    <span></span>
    <ul class="s-hero__social-icons">
    @foreach($follows as $follow)
        <li>
            <a href="{{ $follow->href }}">
                <i 
                    class="fab fa-{{ $follow->title === 'Facebook' ? 'facebook-f' : lcfirst($follow->title) }}" 
                    aria-hidden="true">
                </i>
            </a>
        </li>
    @endforeach
    </ul>
</div>

Vérifiez que les liens aux deux emplacements correspondent bien à ceux de la base.

Les traductions

Pour le moment notre blog est en anglais mais on a prévu les traductions de façon systématique. Il est temps de franciser les textes. Pour vous simplifier la vie je vous propose d’aller chercher les fichiers de traduction directement dans le ZIP à télécharger :

Récupérez tout, même les versions anglaises parce que j’ai ajouté des choses.

Dans le fichier config.app passez au français :

'locale' => 'fr',

Vérifiez que ça fonctionne partout :

Normalement on a tout jusqu’à la fin de ce projet…

Les pages d’erreur

On ne pense pas toujours aux pages d’erreur mais il est judicieux d’éviter d’afficher une page trop sommaire ou carrément laide. Par défaut Laravel en propose des très épurées :

On va améliorer ça en commençant par créer un layout dans un dossier dédié :

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="{{ asset('css/vendor.css') }}">
    <link rel="stylesheet" href="{{ asset('css/styles.css') }}">
    <style>
        html,
        body {
            background-color: #ccc;
        }
        body {
            text-align: center;
            text-shadow: 0 1px 3px rgba(0,0,0,.5);
        }
        .site-wrapper {
            display: table;
            width: 100%;
            height: 100%; /* For at least Firefox */
            min-height: 100%;
            -webkit-box-shadow: inset 0 0 100px rgba(0,0,0,.5);
            box-shadow: inset 0 0 100px rgba(0,0,0,.5);
        }
        .site-wrapper-inner {
            display: table-cell;
            vertical-align: middle;
        }
    </style>

</head>

<body>

    <div class="site-wrapper">
        <div class="site-wrapper-inner">
              @yield('content')
        </div>
    </div>

</body>
</html>

On ajoute une vue partielle :

<h1>{{ __('errors.error-' . $number) }}</h1>
<p class="lead">{{ __('errors.error-' . $number . '-info') }}</p>
@if($number != '503')
    <p class="lead">
        <a href="{{ url('/') }}" class="btn btn--primary">{{ __('Home') }}</a>
    </p>
@endif

On complète avec les 3 erreurs les plus classiques :

On y retrouve le même code avec juste le numéro de l’erreur qui change :

@extends('errors.layout')

@section('content')
    @include('errors.partial', ['number' => '403'])
@endsection

On a un nouvel aspect :

C’est en français grâce aux fichiers de traductions copiés précédemment.

Un événement

Le blog va vivre alors l’administrateur et les rédacteurs ont besoin d’être informés s’il se passe quelque chose. En particulier s’il y a un nouveau :

  • utilisateur
  • article
  • commentaire
  • contact

Plutôt que de créer quelque chose on va un peu détourner l’utilisation classique du système de notification de Laravel. Par défaut seul le modèle User est concerné mais on a vu dans les précédents articles que les modèles Post, Contact et Comment utilisent aussi ce système. On va ajouter un événement qui va surveille la création de l’une de ces entités et, si c’est le cas, mémoriser cette création dans la table des notifications.

Si on regarde dans EventServiceProvider on voit déjà un événement déclaré :

protected $listen = [
    Registered::class => [
        SendEmailVerificationNotification::class,
    ],
];

Comme on n’a pas prévu la vérification des emails cet événement ne nous sert à rien mais on peut le garder au cas où… On va en ajouter un autre :

use App\Events\ModelCreated;
use App\Listeners\ModelCreated as ModelCreatedListener;

...

protected $listen = [
    ...
    ModelCreated::class => [
        ModelCreatedListener::class,
    ],
];

On déclare un événement et une écoute qu’on n’a pas encore créés mais comme Laravel est très gentil on va lancer une commande Artisan :

php artisan event:generate

Et on va avoir nos classes automatiquement générées :

Pour l’événement on va prévoir ce code :

<?php

namespace App\Events;

use Illuminate\ {
    Queue\SerializesModels,
    Database\Eloquent\Model,
    Foundation\Events\Dispatchable
};

class ModelCreated
{
    use Dispatchable, SerializesModels;

    public $model;

    public function __construct(Model $model)
    {
        $this->model = $model;
    }
}

Donc on se contente de transmettre le modèle concerné.

Et pour l’écoute :

<?php

namespace App\Listeners;

use App\Events\ModelCreated as EventModelCreated;
use App\Notifications\ModelCreated as ModelCreatedNotification;

class ModelCreated
{
    /**
     * Handle the event.
     *
     * @param  EventModelCreated  $event
     * @return void
     */
    public function handle(EventModelCreated $event)
    {
        $event->model->notify(new ModelCreatedNotification);
    }
}

On crée une notification pour le modèle.

On crée la notification :

php artisan make:notification ModelCreated

Là on va juste préciser qu’on veut une notification dans la base :

public function via($notifiable)
{
    return ['database'];
}

Mais pour que ça fonctionne il faut déclencher l’événement, donc dans chacun des modèles User, Post, Comment et Contact on ajoute ce code :

use App\Events\ModelCreated;

...

class User extends Authenticatable
{
    ...

    protected $dispatchesEvents = [
        'created' => ModelCreated::class,
    ];

Laravel comporte un certain nombre d’événements par défaut, ici on utilise created pour le modèle.

Pour voir si ça fonctionne on va créer un utilisateur à partir du formulaire d’enregistrement. Normalement on doit avoir un enregistrement dans la table notifications :

On a les noms de l’événement et du modèle, ça nous suffira pour l’administration !

Pour un commentaire on aura :

Conclusion

Et voilà notre frontend totalement codé ! Dans le prochain article on commencera à s’occuper du backend…

 

Print Friendly, PDF & Email

13 commentaires

  • fabBlab

    Petite erreur au début de l’article où il est indiqué :
    « Vous pouvez régénérer toute la base (on est obligé pour avoir la population) :
    php artisan:migrate –seed »
    La bonne commande étant :
    php artisan migrate:fresh –seed

    Sinon, chez moi la traduction du placeholder du moteur de recherche du blog reste désespérement en anglais ! (Search for…), même après avoir changer le texte anglais dans le layout !
    Et j’ai actualisé les différents caches, mais sans succès pour l’instant.

    Quant aux dates, elles ne sont pas non plus « traduites ». Le cours indiquait d’utiliser Carbon pour ce faire.

    Dernier point, concernant la page d’erreur il est indiqué que « C’est en français grâce aux fichiers de traductions copiés précédemment. » Mais contrairement à la capture d’écran, la vue partielle n’affiche que le numéro de l’erreur. De plus, il n’y a pas d’entrée correspondant au message affiché dans la capture dans le fichier de traduction.

    Je pinaille 🙂 mais je suis conscient du boulot qu’il y a derrière ce TP de démonstration !
    C’est vraiment chouette de partager tout ça.

    • bestmomo

      Salut,

      Merci pour la lecture attentive !

      J’ai corrigé pour la migration dans l’article.

      Pour la traduction des dates il faut ajouter cette ligne dans le boot de AppServiceProvider :
      setlocale(LC_TIME, config('app.locale'));

      Pour le reste en installant les fichiers du ZIP tout fonctionne correctement chez moi.

  • KABA

    J’ai ce message d’erreur que je n’arrive pas à resoudre:

    ErrorException

    Array to string conversion

    at C:\laragon\www\myblog\vendor\laravel\framework\src\Illuminate\Support\Str.php:524
    520▕
    521▕ $result = array_shift($segments);
    522▕
    523▕ foreach ($segments as $segment) {
    ➜ 524▕ $result .= (array_shift($replace) ?? $search).$segment;
    525▕ }
    526▕
    527▕ return $result;
    528▕ }

    1 C:\laragon\www\myblog\vendor\laravel\framework\src\Illuminate\Support\Str.php:524
    Illuminate\Foundation\Bootstrap\HandleExceptions::handleError(« Array to string conversion », « C:\laragon\www\myblog\vendor\laravel\framework\src\Illuminate\Support\Str.php »)

    2 C:\laragon\www\myblog\vendor\laravel\framework\src\Illuminate\Database\QueryException.php:57
    Illuminate\Support\Str::replaceArray(« ? », « insert into `comments` (`post_id`, `user_id`, `body`, `children`, `updated_at`, `created_at`) values (?, ?, ?, ?, ?, ?) »)

Laisser un commentaire