
Créer un blog – l’administration
Nous en avons dans le précédent article terminé avec le frontend de notre blog. Il est possible qu’on y revienne pour ajouter des fonctionnalités mais pour le moment il comporte tout ce qu’on avait prévu au départ.
Nous allons à présent ouvrir un nouveau chapitre avec la création de l’administration du blog. On va avoir pas mal de choses à gérer : les utilisateurs, les catégories et articles, les commentaires, les contacts, les pages et les liens sociaux, sans parler des notifications. On a donc du pain sur la planche.
Dans un premier temps il faut faire un choix technologique. Comme je l’aime bien j’ai opté pour AdminLTE, comme je l’avais déjà fait pour mon exemple de commerce en ligne. On va d’ailleurs suivre le même processus.
Vous pouvez télécharger le code final de cet article ici.
AdminLTE
On trouve AdminLTE sur ce site :
On va le télécharger avec le bouton DOWNLOAD. On se retrouve avec un fichier compressé et après décompression on obtient tout ça :
Au moment où j’écris cet article la dernière version est la 3.1.0-RC.
Plutôt que d’utiliser les assets proposés on va plutôt charger les librairies avec des CDN, ce qui améliorera les performances (les serveurs sont performants et on travaille en parallèle).
On va par contre utiliser la page de démarrage starter.html.
On prend le code de la page starter.html, changer son nom pour layout.blade.php et ranger le fichier dans un dossier back des vues :
On crée une route provisoire pour accéder au layout :
Route::view('admin', 'back.layout');
Pour le moment on a aucun style parce qu’on n’a pas les assets alors on va arranger ça avec des CDN :
<!-- Font Awesome Icons --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css" /> <!-- Theme style --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/admin-lte/3.0.5/css/adminlte.min.css" /> ... <!-- jQuery --> <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script> <!-- Bootstrap 4 --> <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/js/bootstrap.bundle.min.js" ></script> <!-- AdminLTE App --> <script src="https://cdnjs.cloudflare.com/ajax/libs/admin-lte/3.0.5/js/adminlte.min.js"></script>
Maintenant on a quelque chose de correct mis à part les images, mais ça on en aura pas besoin :
On fait un grand ménage maintenant :
<!DOCTYPE html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>AdminLTE 3 | Starter</title> <!-- Google Font: Source Sans Pro --> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback"> <!-- Font Awesome Icons --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css" /> <!-- Theme style --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/admin-lte/3.0.5/css/adminlte.min.css" /> </head> <body class="hold-transition sidebar-mini"> <div class="wrapper"> <!-- Navbar --> <nav class="main-header navbar navbar-expand navbar-white navbar-light"> <!-- Left navbar links --> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" data-widget="pushmenu" href="#"><i class="fas fa-bars"></i></a> </li> <li class="nav-item d-none d-sm-inline-block"> <a href="{{ route('home') }}" class="nav-link">@lang('Show blog')</a> </li> <li class="nav-item d-none d-sm-inline-block"> <form action="{{ route('logout') }}" method="POST" hidden> @csrf </form> <a class="nav-link" href="{{ route('logout') }}" onclick="event.preventDefault(); this.previousElementSibling.submit();"> @lang('Logout') </a> </li> </ul> </nav> <!-- /.navbar --> <!-- Main Sidebar Container --> <aside class="main-sidebar sidebar-dark-primary elevation-4"> <!-- Sidebar --> <div class="sidebar"> <!-- Sidebar Menu --> <nav class="mt-2"> <ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false"> </ul> </nav> <!-- /.sidebar-menu --> </div> <!-- /.sidebar --> </aside> <!-- Content Wrapper. Contains page content --> <div class="content-wrapper"> <!-- Content Header (Page header) --> <!-- Content Header (Page header) --> <div class="content-header"> <div class="container-fluid"> <div class="row mb-2"> <div class="col-sm-12"> <h1 class="m-0 text-dark">Titre</h1> </div><!-- /.col --> </div><!-- /.row --> </div><!-- /.container-fluid --> </div> <!-- /.content-header --> <!-- Main content --> <div class="content"> <div class="container-fluid"> @yield('main') </div><!-- /.container-fluid --> </div> <!-- /.content --> </div> <!-- /.content-wrapper --> <!-- Main Footer --> <footer class="main-footer"> <!-- Default to the left --> <strong>Copyright © 2021 {{ config('app.name', 'Laravel') }}.</strong> </footer> </div> <!-- ./wrapper --> <!-- REQUIRED SCRIPTS --> <!-- jQuery --> <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script> <!-- Bootstrap 4 --> <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/js/bootstrap.bundle.min.js" ></script> <!-- AdminLTE App --> <script src="https://cdnjs.cloudflare.com/ajax/libs/admin-lte/3.0.5/js/adminlte.min.js"></script> </body> </html>
Maintenant qu’on a fait du vide il ne nous reste plus qu’à remplir…
On va quand même régler un petit détail avec le nom de l’application dans le fichier .env :
APP_NAME="Mon Blog"
Un composant pour le menu latéral
Comme le code va être répétitif on crée un composant anonyme pour les items du menu latéral :
@props(['route', 'sub', 'icon']) <li class="nav-item"> <a href="{{ route($route) }}" class="nav-link {{ currentRouteActive($route) }}"> <i class=" @isset($sub) far fa-circle @endisset nav-icon @isset($icon) fas fa-{{ $icon }} @endisset "></i> <p>{{ $slot }}</p> </a> </li>
Il suffit de lui envoyer ces informations :
- le nom de la route
- si c’est un sous-menu
- s’il y a une icône
Des helpers
Pour simplifier le codage on va aussi créer des helpers. Vous avez peut-être déjà remarqué qu’il y en a un dans le composant ci-dessus.
On ajoute ces 4 helpers dans le fichier app/helpers.php :
... if (!function_exists('currentRouteActive')) { function currentRouteActive(...$routes) { foreach ($routes as $route) { if(Route::currentRouteNamed($route)) return 'active'; } } } if (!function_exists('currentChildActive')) { function currentChildActive($children) { foreach ($children as $child) { if(Route::currentRouteNamed($child['route'])) return 'active'; } } } if (!function_exists('menuOpen')) { function menuOpen($children) { foreach ($children as $child) { if(Route::currentRouteNamed($child['route'])) return 'menu-open'; } } } if (!function_exists('isRole')) { function isRole($role) { return auth()->user()->role === $role; } }
Le but est d’ajouter les classes nécessaires pour l’apparence et de connaître facilement le rôle d’un utilisateur;
Des middlewares
On va avoir besoin plusieurs fois de savoir si l’utilisateur authentifié est administrateur ou rédacteur. Le plus simple est de créer deux middlewares :
php artisan make:middleware Admin php artisan make:middleware Redac
class Admin { public function handle(Request $request, Closure $next) { $user = $request->user(); if ($user && $user->role === 'admin') { return $next($request); } return redirect()->route('home'); } }
class Redac { public function handle(Request $request, Closure $next) { $user = $request->user(); if ($user && ($user->role === 'admin' || $user->role === 'redac')) { return $next($request); } return redirect()->route('home'); } }
Pour le middleware Redac on admet qu’un administrateur est aussi rédacteur. On enregistre ces middlewares dans app/Http/Kernel.php :
protected $routeMiddleware = [ ... 'admin' => \App\Http\Middleware\Admin::class, 'redac' => \App\Http\Middleware\Redac::class, ];
Contrôleur et route
On crée un contrôleur pour entrer dans l’administration :
php artisan make:controller Back\AdminController
On renvoie une vue avec la méthode index :
<?php namespace App\Http\Controllers\Back; use App\Http\Controllers\Controller; use Illuminate\Http\Request; class AdminController extends Controller { public function index() { return view('back.index'); } }
On ajoute la route pour appeler cette méthode :
use App\Http\Controllers\Back\AdminController; ... Route::prefix('admin')->group(function () { Route::middleware('redac')->group(function () { Route::name('admin')->get('/', [AdminController::class, 'index']); }); });
Toute les routes de l’administration seront préfixées admin. On protège l’accès avec le middleware redac qu’on a créé plus haut. L’administration ne doit être accessible que pour l’administrateur et les rédacteurs. J’ai créé des groupes parce qu’on aura de nombreuses routes concernées.
La vue index
On crée la vue back.index :
@extends('back.layout') @section('main') <div class="container-fluid"> <div class="row"> C'est ici qu'on va mettre du contenu. </div> </div> @endsection
Maintenant si on se connecte avec l’administrateur ou un rédacteur on arrive dans le tableau de bord avec l’url monblog.ext/admin :
Accès à l’administration
Pour accéder à cette administration le plus simple est de prévoir un lien dans la barre de navigation pour les utilisateurs concernés, c’est à dire l’administrateur et les rédacteurs. On complète donc cette barre dans la vue front.layout :
@guest ... @else @if(auth()->user()->role != 'user') <li> <a href="{{ url('admin') }}">@lang('Administration')</a> </li> @endif
Les titres
Pour les titres on va créer un fichier de configuration qui va faire correspondre une route avec un titre :
Pour le moment on n’a pas grand chose à y mettre :
<?php return [ 'admin' => 'Dashboard', ];
Dans AppServiceProvider on envoie les titres avec un composeur :
use Illuminate\Support\Facades\{ Blade, View, Route }; ... public function boot() { ... View::composer('back.layout', function ($view) { $title = config('titles.' . Route::currentRouteName()); $view->with(compact('title')); });
Dans back.layout on peut maintenant afficher le titre :
<h1 class="m-0 text-dark">@lang($title)</h1>
Le menu latéral
On va s’intéresser maintenant au menu latéral. On a déjà créé un composant ci-dessus pour afficher chaque item. Pour bien organiser ce menu on va, comme pour les titres, créer un fichier de configuration :
On y prévoit le titre, le rôle, la route et l’icône :
<?php return [ 'Dashboard' => [ 'role' => 'redac', 'route' => 'admin', 'icon' => 'tachometer-alt', ], ];
Dans la vue back.layout on lit ce fichier pour afficher le menu :
<!-- Sidebar Menu --> <nav class="mt-2"> <ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false"> @foreach(config('menu') as $name => $elements) @if($elements['role'] === 'redac' || auth()->user()->isAdmin()) @isset($elements['children']) <li class="nav-item has-treeview {{ menuOpen($elements['children']) }}"> <a href="#" class="nav-link {{ currentChildActive($elements['children']) }}"> <i class="nav-icon fas fa-{{ $elements['icon'] }}"></i> <p> @lang($name) <i class="right fas fa-angle-left"></i> </p> </a> <ul class="nav nav-treeview"> @foreach($elements['children'] as $child) @if(($child['role'] === 'redac' || auth()->user()->isAdmin()) && $child['name'] !== 'fake') <x-back.menu-item :route="$child['route']" :sub=true> @lang($child['name']) </x-back.menu-item> @endif @endforeach </ul> </li> @else <x-back.menu-item :route="$elements['route']" :icon="$elements['icon']"> @lang($name) </x-back.menu-item> @endisset @endif @endforeach </ul> </nav>
C’est équipé aussi pour les sous-menus. Comme ça pour la suite on aura juste à renseigner le fichier de configuration. Pour le moment on a juste l’item pour le tableau de bord :
Le tableau de bord
Que va-t-on mettre sur le tableau de bord ? On va afficher un bloc pour chacun des nouveaux éléments :
- nouvel utilisateur
- nouvel article
- nouveau commentaire
- nouveau contact
Il faudra tenir compte du fait que les rédacteurs ne sont concernés que par les nouveaux commentaires de leurs articles.
Un composant box
On crée un composant box qui sera utilisé pour chacune des catégories précitées :
@props([ 'type', 'number', 'title', 'route', 'model', ]) <div class="col-lg-3 col-6"> <div class="small-box bg-{{ $type }}"> <div class="inner"> <h3>{{ $number }}</h3> <p>@lang($title)</p> </div> <div class="icon"> <i class="ion ion-bag"></i> </div> <a href="#" class="small-box-footer">@lang('More info') <i class="fas fa-arrow-circle-right"></i></a> <form action="{{ route('purge', $model) }}" method="POST"> @csrf @method('PUT') <button type="submit" class="btn btn-{{ $type }} btn-block text-warning">@lang('Purge')</button> </form> </div> </div>
Il faut lui envoyer les information requises et il affiche gentiment le bloc.
Le contrôleur est les routes
On doit compléter le contrôleur AdminController pour :
- envoyer les informations pour afficher les blocs nécessaires
- procéder à la demande la purge des notifications lues
Voici le nouveau code complet pour le contrôleur :
<?php namespace App\Http\Controllers\Back; use App\Http\Controllers\Controller; use App\Models\{ User, Post, Comment, Contact }; use Illuminate\Support\Facades\DB; class AdminController extends Controller { public function index(Post $post, User $user, Comment $comment, Contact $contact) { $users = isRole('admin') ? $this->getUnreads($user) : null; $contacts = isRole('admin') ? $this->getUnreads($contact) : null; $posts = isRole('admin') ? $this->getUnreads($post) : null; $comments = $this->getUnreads($comment, isRole('redac')); return view('back.index', compact('posts', 'users', 'contacts', 'comments')); } protected function getUnreads($model, $redac = null) { $query = $redac ? $model->whereHas('post.user', function ($query) { $query->where('users.id', auth()->id()); }) : $model->newQuery(); return $query->has('unreadNotifications')->count(); } public function purge($model) { $model = 'App\Models\\' . ucfirst($model); DB::table('notifications')->where('notifiable_type', $model)->delete(); return back(); } }
On doit ajouter la route de la purge :
Route::prefix('admin')->group(function () { Route::middleware('redac')->group(function () { ... Route::name('purge')->put('purge/{model}', [AdminController::class, 'purge']); }); });
La vue index
Il ne reste plus qu’à utiliser le composant dans la vue back.index :
@extends('back.layout') @section('main') <div class="container-fluid"> <div class="row"> @if($posts) <x-back.box type='info' :number='$posts' title='New posts' route='posts.indexnew' model='post'> </x-back.box> @endif @if($users) <x-back.box type='success' :number='$users' title='New users' route='users.indexnew' model='user'> </x-back.box> @endif @if($contacts) <x-back.box type='primary' :number='$contacts' title='New contacts' route='contacts.indexnew' model='contact'> </x-back.box> @endif @if($comments) <x-back.box type='danger' :number='$comments' title='New comments' route='comments.indexnew' model='comment'> </x-back.box> @endif </div> </div> @endsection
On envoie des routes qu’on a pas encore créées mais on règlera ça plus tard.
On a l’affichage d’un bloc pour chaque entité s’il y en a au moins une nouvelle. Je n’ai pas poussé le codage jusqu’à adapter l’orthographe du pluriel si on a un seul élément.
J’ai un peu détourné le système de notification de Laravel pour mettre ça en place mais pourquoi pas ?
Conclusion
Ca y est, notre administration est en place, on va pouvoir à présent traiter toutes les données du blog. On commencera ça dans le prochain article.


44 commentaires
DIM
Bonjour Best , voici ma table de route:
Route::prefix(‘admin’)->group(function(){
Route::middleware([
‘auth:sanctum’,
config(‘jetstream.auth_session’),
‘verified’,
])->group(function () {
Route::get(‘/’,[AdminController::class,’index’])->name(‘admin’);
// Route::get(‘/dashboard’, function () {
// return view(‘dashboard’);
// })->name(‘dashboard’);
Route::resource(‘events’, EventController::class)->except([‘show’]);
Route::resource(‘contact_list’,BackContactController::class)->only([‘index’,’destroy’]);
Route::resource(‘posts’, PostController::class)->except([‘show’]);
Route::resource(‘categories’, CategoryController::class)->except([‘show’]);
Route::resource(‘services’,ServiceController::class)->except([‘show’]);
Route::resource(‘products’,ProductController::class)->except([‘show’]);
});
});
Route::get(‘/’, HomeController::class)->name(‘home’);
Route::name(‘services.show’)->get(‘{category_slug}/{service_slug}’,[FrontServiceController::class,’show’]);
Route::name(‘category’)->get(‘category/{category:slug}’, [FrontPostController::class, ‘category’]);
Route::get(‘/blog’, [FrontPostController::class,’index’])->name(‘blog’);
Route::resource(‘/contact’, ContactController::class, [‘only’ => [‘create’, ‘store’]]);
Route::name(‘posts.display’)->get(‘{slug}’, [FrontPostController::class, ‘show’]);
Route::group([‘prefix’ => ‘laravel-filemanager’, ‘middleware’ => ‘auth’,’web’], function () {
Lfm::routes();
});
quasiment toutes les routes qui suivent la route home ne fonctionnenent plus , il y a conflit apparemment peux-tu stp me l’expliquer
bestmomo
Ta route Home intercepte pratiquement tout. Elle n’est pas sélective. Il faut vraiment faire attention à l’ordre des routes. Ça arrive souvent ce genre de chose.
DIM
que dois-je faire ? , n’est-il pas possible de faire un article sur ça ?
bestmomo
Il suffit de mettre les route en mettant en premier les routes les plus sélectives. Par exemple si tu as la route :
Route::get(‘/{ref}’, MyController::class, ‘index’);
Et
Route::get(‘/name’, MyController::class, ‘save’);
Si tu gardes cet ordre, tu vois que la première route va capter l’url de la seconde.
DIM
Merci best j’ai réordonné mes routes et ça marche sauf une
Route::get(‘/’, HomeController::class)->name(‘home’);
Route::resource(‘contact’, ContactController::class, [‘only’ => [‘create’, ‘store’]]);
Route::get(‘blog’, [FrontPostController::class,’index’])->name(‘blog’);
Route::name(‘category’)->get(‘category/{category:slug}’, [FrontPostController::class, ‘category’]);
Route::name(‘posts.display’)->get(‘{slug}’, [FrontPostController::class, ‘show’]);
Route::name(‘services.show’)->get(‘{category_slug}/{service_slug}’,[FrontServiceController::class,’show’]);
la dernière
bestmomo
Je ne vois rien dans les 5 précédentes qui pourrait intercepter cette route…
DIM
Bonjour best.
je réalise un projet et j’ai ces routes qui suivent dans mon web.php
« name(‘home’);
Route::get(‘/blog’, [FrontPostController::class,’index’])->name(‘blog’);
Route::resource(‘contact’, ContactController::class, [‘only’ => [‘create’, ‘store’]]);
Route::name(‘posts.display’)->get(‘{slug}’, [FrontPostController::class, ‘show’]);
Route::name(‘category’)->get(‘category/{category:slug}’, [FrontPostController::class, ‘category’]);
Route::name(‘services.show’)->get(‘{category_slug}/{service_slug}’,[FrontServiceController::class,’show’]);
Route::get(‘/certification/finance_pub/’, function(){
return view(‘front.fin_pub_cert’);
})->name(‘fin_pub_cert’);
// Route::get(‘/certification/IT/’, function(){
// return view(‘front.it_cert’);
// })->name(‘it_cert’);
// Route::get(‘/certification/project_management/’, function(){
// return view(‘front.gestion_projet_cert’);
// })->name(‘project_management’);
// Route::get(‘/certification/strat_cert/’, function(){
// return view(‘front.strat_cert’);
// })->name(‘strategie’);
Route::group([‘prefix’ => ‘laravel-filemanager’, ‘middleware’ => ‘auth’,’web’], function () {
Lfm::routes();
});
// ====================================== Admin route ==========================================
Route::prefix(‘admin’)->group(function(){
Route::middleware([
‘auth:sanctum’,
config(‘jetstream.auth_session’),
‘verified’,
])->group(function () {
Route::get(‘/’,[AdminController::class,’index’])->name(‘admin’);
// Route::get(‘/dashboard’, function () {
// return view(‘dashboard’);
// })->name(‘dashboard’);
Route::resource(‘events’, EventController::class);
Route::get(‘contacts’,[BackContactController::class,’index’])->name(‘contacts.index’);
Route::resource(‘posts’, PostController::class)->except([‘show’]);
Route::resource(‘categories’, CategoryController::class)->except([‘show’]);
});
});
» quand j’éssaie d’accéder à l’administration la route ( admin ) j(ai une erreur 404 tandis que je l’apelle bien par son nom , je ne sais vraiment pas comment m’y prendre alors je demande l’aide du maitre
bestmomo
Salut,
Je vois que tu utilises Sanctum, vérifie que tu l’as bien configuré, supprime le dans la route pour voir si ça vient de là.
Au cas où vide le cache : php artisan route:clear
DIM
salut best je ne saisi pas le phénomène mais apparement les routes resources bloquent ce qui venait après , j’ai donc mis mes routes administratives au dessus et ça marche sans rien modifier d’autres .
Merci d’avoir réagi
bestmomo
Salut,
Je ne vois aucun conflit de nom dans tes routes pourtant… Mais bon si ça marche…
DIM
Bonjour Bestmomo qu’est ce qui peut empecher le menu d’etre lu voici mon menu :
@foreach(config(‘menu’) as $name => $elements)
@isset($elements[‘children’])
{{ $name }}
@foreach($elements[‘children’] as $child)
@if($child[‘name’] !== ‘fake’)
{{ $child[‘name’] }}
@endif
@endforeach
{{ $name }}
@endisset
@endforeach
</ul
</nav
bestmomo
Salut,
La syntaxe et la logique est bonne, je l’ai testé, il n’y a juste pas de mise en forme.
DIM
j’ai finalement ajouté la gestion des utilisateurs pour refaire ce qui a été fait sur cet article
merci
DIM
cette partie a sauté au niveau de index.blade.php
@if($membres)
@endif
bestmomo
Salut,
Oui si tu as ajouté une cétégorie il faut tout faire suivre…
DIM
je n’ai pas trop compris Bestmomo qu’est ce qu’il faut faire suivre ?
DIM
et à quel niveau il faut faire suivre ?
DIM
Bonjour Bestmomo j’ai une erreur au niveau du composant menu-item.blade.php ; mon projet est différent de celui ci et j’éssaie de suivre la meme logique :
l’erreur est la suivante : Missing required parameter for [Route: membres.edit] [URI: admin/membres/{membres}/edit] [Missing parameter: membres].
mes routes : Route::prefix(‘admin’)->group(function () {
1 Route::resource(‘membres’, MembreController::class);
2 Route::name(‘membres.edit’)->get(‘membres/{membres}/edit’, [MembreController::class, ‘edit’]);
3 Route::name(‘admin’)->get(‘/’, [AdminController::class, ‘index’]);
4 Route::name(‘purge’)->put(‘purge/{model}’, [AdminController::class, ‘purge’]);
5 Route::name(‘membres.indexnew’)->get(‘newmembres’, [MembreController::class, ‘index’]);
});
la route concernée est la 3ème .
voici le controller et la méthode concernée :
public function index(Membre $membre )
{
$membres = $this->getUnreads($membre);
return view(‘index’, compact(‘membres’));
}
la vue index :
@extends(‘layout’)
@section(‘main’)
@if($membres)
@endif
@endsection
le layout est le meme que pour le projet du blog sauf que moi je ne gère pas les roles des utilisateurs
j’ai éssayé de bidouiller comme ceci :
@foreach(config(‘menu’) as $name => $elements)
@isset($elements[‘children’])
{{$name}}
@foreach($elements[‘children’] as $child)
@lang($child[‘name’])
@endforeach
@lang($name)
@endisset
@endforeach
Et le composant du menu-item.blade se présente comme ceci :
@props([‘route’, ‘sub’, ‘icon’])
{{ $slot }}
.
Néanmoins j’obtiens l’erreur ci dessus sur la vue menu-item.blade
azizoux
Bonjour,
J’ai remarqué qu’en reduisant la taille de l’ecran sur l’interface admin, la bar de menu pour gerer les articles et les commentaire disparait et il n’y a pas moyen de le faire apparaitre.
bestmomo
Salut,
La barre de menu disparaît parce qu’on passe en mode mobile, mais il y a un bouton en haut à gauche pour faire apparaître le menu.
zitounisd
Merci encore une fois pour ce tutorial , à la fin j’ai eu l’erreur suivantes :
BadMethodCallException
Call to undefined method App\Models\Contact::unreadNotifications()
est ce que je dois avoir une colonne unread dans la table notifications
Ferfalam
Salut BESTMOMO, dis à ce niveau du tutoriel est ce que tu as essayé de créer un nouvel utilisateur ? Car moi j’ai une erreur à la création d’un utilisateur
Error
Class ‘App\Models\ModelCreated’ not found
Ferfalam
[Problème résolu]
J’avais éffectué une mauvaise importation de ModelCreated dans les Models User, Posts, Comments,…
zitounisd
c’est résolu , j’ai oublié d’ajouter notifiable dans le modèle contact
AmmaLove
Salut ! Merci beaucoup pour le tutoriel.
Mais est ce que les boxes doivent s’afficher dans le Dashboard a ce niveau du tutoriel ?
car chez moi les boxes ne s’affiche
Merci !
bestmomo
Salut,
Oui ça doit s’afficher s’il y a de nouvelles entités.
Thibaut
bjr
j’ai encore un soucis, j’ai avancé jusqu’ici mais j’ai a nveau une error :ErrorException
Undefined variable: title (View: C:\laragon\www\blog-tutoriel\resources\views\components\back\box.blade.php)
Toutes ces variables:@props([‘type’,’number’,’title’,’route’,’model’,])ne sont pas reconnues ,sauf la variable route
pourtant je suis exactement le tutos
bestmomo
Salut,
Je vois pas trop le souci là étant donné que ces variables sont bien renseignées dans la vue index. Si tu installes le projet à partir du fichier ZIP à télécharger ça fonctionne ?
Thibaut
honnetement j’ai tt essaye mais rien a faire, toujours la meme erreur et je ne comprends pas prkoi, n ya t il pas un autre moyen d’afficher les notifications sur mon tableau de bord?
bestmomo
A la limite tu n’utilises pas de composant et tu codes tout directement dans la vue index. Mais ton erreur est étrange, tu as quelle version de PHP ?
Thibaut
bjr
ma version de php est 7.4.9 j’ai pas puis installer le version 8 sur laragon, j’ai pourtant suivi tout les tutos qui traite la question, ils disent la mm chose mais lorsque je veux le faire j’ai apache qui ne demarre pas
bestmomo
Pas encore vraiment besoin d’utiliser PHP 8, mais si vraiment tu la veux il doit aussi falloir modifier un peu la configuration d’Apache.
Edit : tu as toutes les explications avec une vidéo bien faite ici. Je viens d’essayer et PHP 8 fonctionne bien. Par contre je reçois des erreurs PHP sur mes projets, il doit falloir régénérer les librairies.
Thibaut
j’ai finalement compris d’où venait le probleme, le soucis c’est que moi j’ai pris l’habitude de creer mes components via la ligne de commande php artisan make:components »le nom » et lorsque je fais ça un dossier view/compenent est creer avec une class portant le nom de mon component, or je devez aussi définir les données requises du composant dans son constructeur de classe, mais je ne l’avais pas fait du tout , du coup il ne voyez pas les variables dans mon component. alors pour ne pas avoir de probleme j’ai tout simplement tout supprimé et recreer mes component manuellement et tout marche de nouveau.
j’aurai puis declarer les variables dans les class de mes component mais la je voulais plus de complication
bestmomo
Ah d’accord !
D’ailleurs pour un composant qui nécessite un traitement complémentaire c’est utile de créer une classe, sinon je n’en vois pas l’intérêt.
Thibaut
par rapport au passage a php8 sur laragon, j’ai de nveau suivi les instruction du lien que tu ma donne et jai cette cette error:service Apache can not start, Reason Unknown, Please check Apache log file; et lorque je regarde le fichier log j’ai cett erreur:
httpd: Syntax error on line 546 of C:/laragon/bin/apache/httpd-2.4.35-win64-VC15/conf/httpd.conf: Syntax error on line 2 of C:/laragon/etc/apache2/mod_php.conf: Can’t locate API module structure `php8_module’ in file C:/laragon/bin/php/php-8.0.3-Win32-vs16-x64/php8apache2_4.dll: No error
[Sat Mar 27 16:25:38.029378 2021] [core:warn] [pid 864:tid 568] AH00098: pid file C:/laragon/bin/apache/httpd-2.4.35-win64-VC15/logs/httpd.pid overwritten — Unclean shutdown of previous Apache run?
PHP Warning: ‘C:\\WINDOWS\\SYSTEM32\\VCRUNTIME140.dll’ 14.15 is not compatible with this PHP build linked with 14.28 in Unknown on line 0
[Sat Mar 27 16:25:38.556782 2021] [:emerg] [pid 864:tid 568] AH00020: Configuration Failed, exiting
[Sat Mar 27 16:25:47.054210 2021] [core:warn] [pid 17780:tid 548] AH00098: pid file C:/laragon/bin/apache/httpd-2.4.35-win64-VC15/logs/httpd.pid overwritten — Unclean shutdown of previous Apache run?
PHP Warning: ‘C:\\WINDOWS\\SYSTEM32\\VCRUNTIME140.dll’ 14.15 is not compatible with this PHP build linked with 14.28 in Unknown on line 0
[Sat Mar 27 16:25:47.138180 2021] [:emerg] [pid 17780:tid 548] AH00020: Configuration Failed, exiting
bestmomo
Il faudrait peut-être prendre une version d’Apache plus récente, moi j’ai la 2.4.46 et ça passe (Laragon installe par défaut la 2.4.35).
webwatson
Merci pour ce tuto!
Puis-je avoir une explication sur cette methode et ce paramètre ((…$routes)
if (!function_exists('currentRouteActive')) {
function currentRouteActive(...$routes)
{
foreach ($routes as $route) {
if(Route::currentRouteNamed($route)) return 'active';
}
}
}
bestmomo
Quand on a un nombre non connu de paramètres à passer à une fonction on peut utiliser le token …, on retrouve tous les paramètres dans un tableau qu’on peut parcourir. Ici on passe des noms de routes et si l’une dentre elle est la route actuelle on renvoie le nom de la classe active pour caractériser l’item du menu.
webwatson
Merci pour l’explication. M. Besmomomoi j’ai déjà vu votre visage sur openclassrom…lol
bensa
Bonjour,
svp pouvez vous m’expliquer le fonctionnement de ce code dans l’index de AdminController:
$query = $redac ?
$model->whereHas('post.user', function ($query) {
$query->where('users.id', auth()->id());
j’ai pas bien compris d’ou vient ‘post.user’ et ‘users.id’
merci beaucoup
bestmomo
Salut,
Pour les rédacteurs les seules notifications concernent les commentaires, dans ce cas on sait donc que le modèle est Comment. Dans ce modèle on a une relation avec Post et dans Post on a une relation avec User. Donc ici on demande si le commentaire en question appartient à un article (post) qui lui-même appartient à un auteur (user) qui est celui qui est actuellement authentifié (auth()->id()). De cette manière on n’affiche que les nouveaux commentaires qui concernent les articles de l’auteur connecté.
Pour users.id on fait juste référence à la colonne id de la table users, pour éviter une ambiguité dans la requête parce que toutes les tables ont une colonne id.
bensa
D’accord c’est claire votre explication
merci c’est un plaisir de lire votre tuto
ronald169
Salut Best comment tu vas ? j’ai juste une remarque a faire au niveau du Controller Admin. Pourquoi ne pas allé dans la meme logique comme dans Controller encréant les repositories ?
bestmomo
Salut,
C’est finalement très personnel les repositories. Je commence à en créer quand je vois qu’un contrôleur risque d’être un peu trop encombré de code pour récupérer des données. Par exemple pour les articles c’était tout à fait judicieux, comme on l’a vu. Ici ça ne l’est pas, surtout qu’on va chercher des informations dans 5 tables différentes. Mais bon, c’est juste ma vision des choses.
Bonne journée !