Shopping : la maintenance
Pour toute application on a forcément à faire de la maintenance : évolution du code, mises à jour… Il faut pouvoir rendre le site inaccessible par moment pour effectuer des changements impactants mais il faut quand même pouvoir accéder au site en tant qu’administrateur. D’autre part mettre en cache certaines choses (les routes et la configuration) améliore les performances. Nous allons nous occuper de ça dans cet article.
Vous pouvez télécharger un ZIP du projet ici.
Le mode maintenance
Laravel permet de mettre une application en mode maintenance avec une commande :
php artisan down
On tombe alors sur une page avec ce message :
On ne peut pas vraiment dire que c’est explicite et en plus comment maintenant accéder au site ?
On revient en mode normal avec cette commande :
php artisan up
On peut aussi préciser le texte de la page :
php artisan down --message="Site en maintenance. Un peu de patience"
On peut ajouter une adresse IP autorisée :
php artisan down --message="Site en maintenance. Un peu de patience" --allow=127.0.0.1
On peut aussi complètement changer le look de la page d’erreur en créant une page resources/views/errors/503.blade.php.
Mais toutes ces commande avec Artisan ne sont pas pratique, et il faut un accès SSH, alors on va faciliter tout ça avec une interface propre.
Contrôleur et route
On crée un nouveau contrôleur :
php artisan make:controller Back\MaintenanceController --resource
On ne garde que les méthodes edit et update.
On ajoute les deux routes :
Route::prefix('admin')->middleware('admin')->namespace('Back')->group(function () { ... Route::name('maintenance.edit')->get('maintenance/modification', 'MaintenanceController@edit'); Route::name('maintenance.update')->put('maintenance', 'MaintenanceController@update'); });
On code la méthode edit :
public function edit(Request $request) { $active = app()->isDownForMaintenance(); $ip = $request->ip(); $message = config('messages.maintenance'); return view('back.maintenance.edit', compact('active', 'ip', 'message')); }
On fait plusieurs choses :
- on vérifie si le site est en mode maintenance
- on lit l’adresse IP
- on prépare le message à afficher sur la page de maintenance
On ajoute le message dans config.messages (en anticipant pour les messages de mise à jour) :
return [ ... 'maintenance' => 'La boutique est en mode maintenance.', 'maintenanceupdated' => 'Le mode maintenance a bien été mis à jour.', 'cacheupdated' => 'Le cache a bien été mis à jour.', ];
Un composant pour la vue
On crée un nouveau composant :
php artisan make:component CheckboxCustom
<?php namespace App\View\Components; use Illuminate\View\Component; class CheckboxCustom extends Component { public $name; public $label; public $value; public $off; public $on; /** * Create a new component instance. * * @return void */ public function __construct($name, $label, $off, $on, $value = '') { $this->name = $name; $this->label = $label; $this->off = $off; $this->on = $on; $this->value = $value; } /** * Get the view / contents that represent the component. * * @return \Illuminate\View\View|string */ public function render() { return view('components.checkbox-custom'); } }
<div class="form-group"> <div class="custom-control custom-switch custom-switch-off-{{ $off }} custom-switch-on-{{ $on }}"> <input type="checkbox" class="custom-control-input" id="{{ $name }}" name="{{ $name }}" @if(old($name, $value)) checked @endif> <label class="custom-control-label" for="{{ $name }}">{{ $label }}</label> </div> </div>
La vue du formulaire
On crée une vue pour le formulaire :
@extends('back.layout') @section('main') <div class="container-fluid"> @if(session()->has('alert')) <div class="alert alert-warning alert-dismissible fade show" role="alert"> {{ session('alert') }} <button type="button" class="close" data-dismiss="alert" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> @endif <div class="row"> <div class="col-sm-12"> <div class="card"> <h5 class="card-header">Mode maintenance</h5> <form method="POST" action="{{ route('maintenance.update') }}"> <div class="card-body"> @method('PUT') @csrf <x-inputbs4 name="ip" type="text" label="Adresse IP autorisée" :value="$ip" :required="true" ></x-inputbs4> <x-inputbs4 name="message" type="text" label="Message à afficher" :value="$message" :required="true" ></x-inputbs4> <x-checkbox-custom name="active" label="Mode maintenance" off="success" on="danger" :value="$active" ></x-checkbox-custom> <div class="form-group row mb-0"> <div class="col-md-12"> <button type="submit" class="btn btn-primary">Enregistrer</button> </div> </div> </div> </form> </div> </div> </div> </div> @endsection
On complète config.titles pour le titre de la page :
return [ ... 'maintenance' => [ 'edit' => 'Maintenance', ], ];
Et on obtient le formulaire avec l’url …/admin/maintenance/modification :
La mise à jour
Pour la mise à jour des données on code la méthode update du contrôleur :
use Illuminate\Support\Facades\Artisan; ... public function update(Request $request) { $request->validate([ 'ip' => 'required|ip', 'message' => 'required|string|max:255', ]); Artisan::call($request->has('active') ? 'down --allow=' . $request->ip . ' --message="' . $request->message . '"' : 'up'); return back()->withInput()->with('alert', config('messages.maintenanceupdated')); }
On fait la validation pour mes deux entrées. On utilise Artisan pour la mise à jour. Au retour on affiche un message :
La mise en cache
On va maintenant s’occuper de la mise en cache des routes et de la configuration. Là aussi on dispose des commandes config:cache et route: cache avec leur réciproque config:clear et route:clear. Mais on va faire quelque chose de plus convivial.
Dans la méthode edit du contrôleur on ajoute des données pour le cache :
public function edit(Request $request) { $active = app()->isDownForMaintenance(); $ip = $request->ip(); $message = config('messages.maintenance'); $path = base_path('bootstrap/cache/'); $config = file_exists($path . 'config.php'); $route = file_exists($path . 'routes-v7.php'); return view('back.maintenance.edit', compact('active', 'ip', 'message', 'config', 'route')); }
Les fichiers du cache sont ici :
Leur présence indique que le cache est actif, c’est ce qu’on vérifie dans la méthode.
On crée la méthode cache dans le contrôleur pour la mise à jour :
public function cache(Request $request) { Artisan::call($request->has('config') ? 'config:cache' : 'config:clear'); Artisan::call($request->has('route') ? 'route:cache' : 'route:clear'); $request->session()->flash('alert', config('messages.cacheupdated')); return back(); }
Avec sa route :
Route::prefix('admin')->middleware('admin')->namespace('Back')->group(function () { ... Route::name('cache.update')->put('cache', 'MaintenanceController@cache'); });
Dans la vue on ajoute la partie pour le cache :
@extends('back.layout') @section('main') ... <div class="col-sm-12"> <div class="card"> <h5 class="card-header">Cache</h5> <form method="POST" action="{{ route('cache.update') }}"> <div class="card-body"> @method('PUT') @csrf <x-checkbox-custom name="config" label="Cache de la configuration" off="info" on="warning" :value="$config" ></x-checkbox-custom> <x-checkbox-custom name="route" label="Cache des routes" off="info" on="warning" :value="$route" ></x-checkbox-custom> <div class="form-group row mb-0"> <div class="col-md-12"> <button type="submit" class="btn btn-primary">Enregistrer</button> </div> </div> </div> </form> </div> </div> </div> </div> @endsection
On affiche un message à la mise à jour :
Attention lorsque vous mettez en cache : les mises à jour du code ne sont plus actives !
Le menu
Il ne nous reste plus qu’à compléter le menu dans back.layout pour accéder à notre formulaire :
<li class="nav-item has-treeview {{ menuOpen( 'shop.edit', 'shop.update', 'pays.index', 'pays.edit', 'pays.create', 'plages.edit', 'colissimos.edit', 'etats.index', 'etats.edit', 'etats.create', 'etats.destroy.alert', 'pages.index', 'pages.edit', 'pages.create', 'pages.destroy.alert', 'maintenance.edit' ) }}"> <a href="#" class="nav-link {{ currentRouteActive( 'shop.edit', 'shop.update', 'pays.index', 'pays.edit', 'pays.create', 'plages.edit', 'colissimos.edit', 'etats.index', 'etats.edit', 'etats.create', 'etats.destroy.alert', 'pages.index', 'pages.edit', 'pages.create', 'pages.destroy.alert', 'maintenance.edit' ) }}"> <i class="nav-icon fas fa-cogs"></i> <p> Administration <i class="right fas fa-angle-left"></i> </p> </a> <ul class="nav nav-treeview"> ... <x-menu-item :href="route('maintenance.edit')" :sub=true :active="currentRouteActive('maintenance.edit')"> Maintenance </x-menu-item> </ul> </li>
Conclusion
Avec cet article s’achève sans doute cette série sur la création d’une application de commerce en ligne en espérant qu’elle vous a plue.

13 commentaires
Rdequidt
Salut bestmomo,
Débutant avec Laravel, quand je clcik sur la checkbox j’ai la réponse suivante:
The « –allow » option does not exist.
Pourquoi n’y a-t-il pas de « down allow » dans Laravel 8?
Pourriez-vous mettre à jour ce partie svp
Merci
bestmomo
Salut,
L’application a été créée avec Laravel 7, je suppose que tu utilises Laravel 8 où effectivement cette commande a été retirée. Il faudrait voir par quoi la remplacer…
llaforet
bonsoir,
oui, deux routes /home, il faut virer la /home en modifiant le RouteServiceProvider en conséquence.
Bestmomo, un très grand merci pour cet excellent tuto ! clair et fonctionnel, un vrai plaisir à suivre.
Hamdi
Bonjour BestMomo,
je tiens vraiment à vous remercier pour ce cours qui m’a permis d’apprendre tellement de choses. je l’ai suivi et appliqué du début jusqu’à la fin. Encore une fois merci. Continuer comme ça! vous êtes vraiment le Best!
bestmomo
Merci 😉
KABA
Bonsoir,
Comment peut-on vous contacter en privé Mr bestmomo pour un projet en Laravel?
bestmomo
Bonjour,
J’ai mis une adresse email dans la page des mentions légales. Mais je ne garantis pas de réponse rapide.
dogma52
Bonsoir.
Débutant avec Laravel, j’ai suivi votre cours sur https://openclassrooms.com/ que j’ai trouvé excellent : clair et complet.
Cette suite d’articles m’a permis de mieux comprendre l’architecture d’une app Laravel, et j’y ai appris également énormément.
Beaucoup de contenu utile, réutilisable (composants de vue, admin …).
Merci !
bestmomo
Bonsoir,
Merci d’apprécier.
ronald169
Sa a été pour moi un Regal j’ai appris beaucoup en très peu de temps et vraiment merci. A chaque leçon il y’a toujours quelque chose a découvrir que ce soit dans la syntaxe ou l’utilisation de plug-in Vuejs en passant dans la découverte de nouveau paquetage sans oublié se cours sur merise qui ne fesait pas partir du projet, cette boutique en ligne me confirme la grande usine a gaz qu’on peut utiliser dans tous nos projet temps au quotidien que dans de grande entreprise.
Avec cette écosystèmes qui est grandissant autour de laravel (livewire, alpineJs) si ce n’est pour citer ceux la nous attendrons nous a de nouveaux cours comme fut le cas avec Vuejs et bootstrap ?
PS: j’espère que oui.
bestmomo
Salut,
Au moins il y a quelqu’un qui a suivi jusqu’au bout 🙂
Pour la suite je ne sais pas encore, je fais en fonction de mon humeur !
golli
bonjour
merci et tres bon travail bestmomo
pour Cache des routes quand je l’active j’ai cette erreur :
LogicException
Unable to prepare route [home] for serialization. Another route has already been assigned name [home].
et quand j’active Mode maintenance
rien ne se passe !!
merci
bestmomo
Salut,
Apparemment il y a deux routes avec le nom « home »