I. Le panneau▲
Sur son tableau de bord, l'administrateur trouve un bloc qui concerne les articles :
Il peut ainsi savoir combien il y a d'articles et combien il y en a de nouveaux.
On a déjà vu que le tableau de bord est géré par la méthode admin du contrôleur AdminController :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
/**
* Show the admin panel.
*
*
@param
App\Repositories\ContactRepository
$contact_gestion
*
@param
App\Repositories\BlogRepository
$blog_gestion
*
@param
App\Repositories\CommentRepository
$comment_gestion
*
@return
Response
*/
public function admin(
ContactRepository $contact_gestion
,
BlogRepository $blog_gestion
,
CommentRepository $comment_gestion
)
{
$nbrMessages
=
$contact_gestion
->
getNumber();
$nbrUsers
=
$this
->
user_gestion->
getNumber();
$nbrPosts
=
$blog_gestion
->
getNumber();
$nbrComments
=
$comment_gestion
->
getNumber();
return view('
back.index
'
,
compact('
nbrMessages
'
,
'
nbrUsers
'
,
'
nbrPosts
'
,
'
nbrComments
'
));
}
Et que les quantités sont déterminées dans la méthode getNumber du repository de base BaseRepository :
Et que tout ça est envoyé dans la vue resources/views/back/index.blade.php.
Pour accéder à la gestion des articles, l'administrateur peut cliquer sur le bloc ou utiliser le menu latéral :
Il dispose alors d'une vue globale sur les articles existants :
Un rédacteur aboutit directement à cette page et ne dispose que de ses articles.
À ce niveau les actions possibles sont :
- trier les articles par titre, date, publication, auteur et vu ;
- publier ou dépublier un article ;
- marquer un article vu ou non vu ;
- voir un article ;
- modifier un article ;
- supprimer un article ;
- créer un article.
Nous allons voir comment est traitée chacune de ces possibilités mise à part la visualisation d'un article qui se contente de le générer dans le front-end.
II. Le tri▲
Lorsque les articles ne sont pas triés, on a les deux petits sélecteurs qui apparaissent :
Lorsqu'on clique sur les sélecteurs, on passe en tri décroissant et seul le sélecteur inférieur apparaît :
Lorsqu'on clique à nouveau, on passe en mode tri croissant et seul le sélecteur supérieur apparaît :
Ces actions sont gérées en Ajax pour ne pas avoir à recharger la page, mais juste le tableau.
Il y a évidemment un traitement en JavaScript pour gérer le visuel et s'occuper de la requête Ajax :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
// Sorting gestion
$(
'a.order'
).click
(
function(
e) {
e.preventDefault
(
);
// Sorting direction
var sens;
if(
$(
'span'
,
this).hasClass
(
'fa-unsorted'
)) sens =
'aucun'
;
else if (
$(
'span'
,
this).hasClass
(
'fa-sort-desc'
)) sens =
'desc'
;
else if (
$(
'span'
,
this).hasClass
(
'fa-sort-asc'
)) sens =
'asc'
;
// Set to zero
$(
'a.order span'
).removeClass
(
).addClass
(
'fa fa-fw fa-unsorted'
);
// Adjust selected
$(
'span'
,
this).removeClass
(
);
var tri;
if(
sens ==
'aucun'
||
sens ==
'asc'
) {
$(
'span'
,
this).addClass
(
'fa fa-fw fa-sort-desc'
);
tri =
'desc'
;
}
else if(
sens ==
'desc'
) {
$(
'span'
,
this).addClass
(
'fa fa-fw fa-sort-asc'
);
tri =
'asc'
;
}
// Wait icon
$(
'.breadcrumb li'
).append
(
'<span id="tempo" class="fa fa-refresh fa-spin"></span>'
);
// Send ajax
$.ajax
({
url
:
'blog/order'
,
type
:
'GET'
,
dataType
:
'json'
,
data
:
"name="
+
$(
this).attr
(
'name'
) +
"&sens="
+
tri
}
)
.done
(
function(
data) {
$(
'tbody'
).html
(
data.
view);
$(
'.link'
).html
(
data.
links);
$(
'#tempo'
).remove
(
);
}
)
.fail
(
function(
) {
$(
'#tempo'
).remove
(
);
alert
(
'
{{
trans('back/blog.fail'
) }}
'
);
}
);
}
)
C'est la méthode indexOrder du contrôleur BlogController qui reçoit la requête :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
/**
* Display a listing of the resource.
*
*
@param
Illuminate\Http\Request
$request
*
@return
Response
*/
public function indexOrder(Request $request
)
{
$statut
=
$this
->
user_gestion->
getStatut();
$posts
=
$this
->
blog_gestion->
index(
10
,
$statut
==
'
admin
'
?
null :
$request
->
user()->
id,
$request
->
name,
$request
->
sens
);
$links
=
$posts
->
appends([
'
name
'
=>
$request
->
name,
'
sens
'
=>
$request
->
sens
]
);
if($request
->
ajax()) {
return response()->
json([
'
view
'
=>
view('
back.blog.table
'
,
compact('
statut
'
,
'
posts
'
))->
render(),
'
links
'
=>
$links
->
setPath('
order
'
)->
render()
]
);
}
$links
->
setPath(''
)->
render();
$order
=
(object)[
'
name
'
=>
$request
->
name,
'
sens
'
=>
'
sort-
'
.
$request
->
sens
];
return view('
back.blog.index
'
,
compact('
posts
'
,
'
links
'
,
'
order
'
));
}
On a un middleware pour protéger cette méthode :
$this
->
middleware('
redac
'
,
[
'
except
'
=>
[
'
indexFront
'
,
'
show
'
,
'
tag
'
,
'
search
'
]]
);
On veut que ce soit au moins un rédacteur (redac).
C'est la méthode index du repository BlogRepository qui gère au niveau de la base :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
/**
* Get post collection.
*
*
@param
int
$n
*
@param
int
$user_id
*
@param
string
$orderby
*
@param
string
$direction
*
@return
Illuminate\Support\Collection
*/
public function index($n
,
$user_id
=
null,
$orderby
=
'
created_at
'
,
$direction
=
'
desc
'
)
{
$query
=
$this
->
model
->
select('
posts.id
'
,
'
posts.created_at
'
,
'
title
'
,
'
posts.seen
'
,
'
active
'
,
'
user_id
'
,
'
slug
'
,
'
username
'
)
->
join
('
users
'
,
'
users.id
'
,
'
=
'
,
'
posts.user_id
'
)
->
orderBy($orderby
,
$direction
);
if($user_id
)
{
$query
->
where('
user_id
'
,
$user_id
);
}
return $query
->
paginate($n
);
}
On transmet les paramètres nécessaires :
- $n : nombre de pages pour la pagination ;
- $user_id : identifiant si on a affaire à un rédacteur (pour sélectionner uniquement ses articles), sinon null ;
- $orderby : champ de tri ;
- $direction : direction de tri.
Le contrôleur retourne le code généré de la vue :
En voici le code :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
@foreach
($posts
as
$post
)
<
tr {!!
!
$post
->
seen &&
session('statut'
) ==
'admin'
?
'class="warning"'
:
''
!!}
>
<
td class
=
"
text-primary
"
><strong>
{{
$post
->
title }}
<
/strong
></td
>
<
td>
{{
$post
->
created_at }}
<
/td
>
<
td>
{!!
Form::
checkbox('active'
,
$post
->
id,
$post
->
active) !!}
<
/td
>
@if
(session('statut'
) ==
'admin'
)
<
td>
{{
$post
->
username }}
<
/td
>
<
td>
{!!
Form::
checkbox('seen'
,
$post
->
id,
$post
->
seen) !!}
<
/td
>
@endif
<
td>
{!!
link_to('blog/'
.
$post
->
slug,
trans('back/blog.see'
),
[
'class'
=>
'btn btn-success btn-block btn'
]
) !!}
<
/td
>
<
td>
{!!
link_to_route('blog.edit'
,
trans('back/blog.edit'
),
[
$post
->
id],
[
'class'
=>
'btn btn-warning btn-block'
]
) !!}
<
/td
>
<
td>
{!!
Form::
open([
'method'
=>
'DELETE'
,
'route'
=>
[
'blog.destroy'
,
$post
->
id]]
) !!}
{!!
Form::
destroy(trans('back/blog.destroy'
),
trans('back/blog.destroy-warning'
)) !!}
{!!
Form::
close() !!}
<
/td
>
<
/tr
>
@endforeach
On récupère donc côté client tout le HTML pour régénérer le tableau des articles. Dans le JavaScript :
2.
3.
4.
5.
.done
(
function(
data) {
$(
'tbody'
).html
(
data.
view);
$(
'.link'
).html
(
data.
links);
$(
'#tempo'
).remove
(
);
}
)
On remplace le HTML, on régénère les liens de pagination et on supprime la petite animation d'attente de résultat de l'action.
III. Publication et vu▲
L'administrateur ou le rédacteur dispose pour chaque article d'une case à cocher pour publier ou dépublier un article :
Cette action est aussi gérée en Ajax et on a une petite animation en attendant qu'elle s'effectue :
Voici le code JavaScript qui gère côté client :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
// Active gestion
$(
document
).on
(
'change'
,
':checkbox[name="active"]'
,
function(
) {
$(
this).hide
(
).parent
(
).append
(
'<i class="fa fa-refresh fa-spin"></i>'
);
var token =
$(
'input[name="_token"]'
).val
(
);
$.ajax
({
url
:
'
{{
url('postactive'
) }}
'
+
'/'
+
this.
value,
type
:
'PUT'
,
data
:
"active="
+
this.
checked +
"&_token="
+
token
}
)
.done
(
function(
) {
$(
'.fa-spin'
).remove
(
);
$(
'input:checkbox[name="active"]:hidden'
).show
(
);
}
)
.fail
(
function(
) {
$(
'.fa-spin'
).remove
(
);
chk =
$(
'input:checkbox[name="active"]:hidden'
);
chk.show
(
).prop
(
'checked'
,
chk.is
(
':checked'
) ?
null
:
'checked'
).parents
(
'tr'
).toggleClass
(
'warning'
);
alert
(
'
{{
trans('back/blog.fail'
) }}
'
);
}
);
}
);
C'est la méthode updateActive du contrôleur BlogController qui reçoit la requête :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
/**
* Update "active" for the specified resource in storage.
*
*
@param
Illuminate\Http\Request
$request
*
@param
int
$id
*
@return
Response
*/
public function updateActive(
Request $request
,
$id
)
{
$this
->
blog_gestion->
updateActive($request
->
all(),
$id
);
return response()->
json();
}
Cette méthode est protégée par middleware comme on l'a vu pour la précédente.
C'est la méthode updateActive du repository BlogRepository qui gère au niveau de la base :
Le contrôleur renvoie une réponse JSON et le JavaScript agit selon la réussite ou l'échec.
Je ne détaille pas le fonctionnement pour les cases à cocher « Vu » puisque le code est quasiment identique à celui de la publication.
IV. Créer un article▲
IV-A. Le formulaire▲
Le formulaire de création d'un article est affiché par action sur le bouton « Ajouter un article » ou à partir du menu latéral :
C'est la méthode create du contrôleur BlogController qui reçoit la requête :
On voit qu'on va chercher l'URL pour le gestionnaire de médias dans la configuration.
Le contrôleur génère alors la vue :
Si vous regardez le code de cette vue, vous n'allez pas trouver grand-chose :
2.
3.
4.
5.
@extends
('back.blog.template'
)
@section
('form'
)
{!!
Form::
open([
'url'
=>
'blog'
,
'method'
=>
'post'
,
'class'
=>
'form-horizontal panel'
]
) !!}
@stop
En effet le reste du code est commun avec la vue pour la modification des articles. D'où la présence du template (resources/views/back/blog/template.blade.php) dont voici la partie du code qui génère le formulaire :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
<
div class
=
"
col-sm-12
"
>
@yield
('form'
)
<
div class
=
"
form-group checkbox pull-right
"
>
<
label>
{!!
Form::
checkbox('active'
) !!}
{{
trans('back/blog.published'
) }}
<
/label
>
<
/div
>
{!!
Form::
control('text'
,
0
,
'title'
,
$errors
,
trans('back/blog.title'
)) !!}
<
div class
=
"
form-group
{!!
$errors
->
has('slug'
) ?
'has-error'
:
''
!!}
"
>
{!!
Form::
label('slug'
,
trans('back/blog.permalink'
),
[
'class'
=>
'control-label'
]
) !!}
{!!
url('/'
) .
'/ '
.
Form::
text('slug'
,
null
,
[
'id'
=>
'permalien'
]
) !!}
<
small class
=
"
text-danger
"
>
{!!
$errors
->
first('slug'
) !!}
<
/small
>
<
/div
>
{!!
Form::
control('textarea'
,
0
,
'summary'
,
$errors
,
trans('back/blog.summary'
)) !!}
{!!
Form::
control('textarea'
,
0
,
'content'
,
$errors
,
trans('back/blog.content'
)) !!}
{!!
Form::
control('text'
,
0
,
'tags'
,
$errors
,
trans('back/blog.tags'
),
isset($tags
)?
implode(','
,
$tags
) :
''
) !!}
{!!
Form::
submit(trans('front/form.send'
)) !!}
{!!
Form::
close() !!}
<
/div
>
Avec cet aspect :
Le permalien est géré dynamiquement avec une fonction JavaScript :
Sont créées également deux zones de saisie (pour le sommaire et pour le contenu) avec CKEditor dont je vous ai déjà parlé dans un précédent tutoriel. J'ai évoqué dans le même tutoriel l'intégration de FileManager.
Enfin une zone permet la saisie des tags.
IV-B. La validation▲
La soumission du formulaire aboutit à la méthode store du contrôleur BlogController :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
/**
* Store a newly created resource in storage.
*
*
@param
App\Http\Requests\PostRequest
$request
*
@return
Response
*/
public function store(PostRequest $request
)
{
$this
->
blog_gestion->
store($request
->
all(),
$request
->
user()->
id);
return redirect('
blog
'
)->
with('
ok
'
,
trans('
back/blog.stored
'
));
}
On a évidemment une validation assurée par la requête de formulaire PostRequest :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
<?php
namespace
App\Http\Requests;
use
App\Models\Post;
class
PostRequest extends
Request {
/**
* Get the validation rules that apply to the request.
*
*
@return
array
*/
public
function
rules()
{
$id
=
$this
->
blog ?
','
.
$this
->
blog :
''
;
return
[
'title'
=>
'required|max:255'
,
'summary'
=>
'required|max:65000'
,
'content'
=>
'required|max:65000'
,
'slug'
=>
'required|unique:posts,slug'
.
$id
,
'tags'
=>
'tags'
];
}
}
Les règles de validation sont classiques, mise à part celle qui concerne les tags. Il est fait appel à la règle « tags » qui n'est pas une règle de base de Laravel, mais constituée spécifiquement pour l'application.
Il y a une classe spéciale pour les règles de validation ajoutées :
Elle ne comporte qu'une règle :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
<?php
namespace
app\Services;
use
Illuminate\Validation\Validator;
class
Validation extends
Validator {
public
function
validateTags($attribute
,
$value
,
$parameters
)
{
return
preg_match("/^[A-Za-z0-9-éèàù]{1,50}?(,[A-Za-z0-9-éèàù]{1,50})*$/"
,
$value
);
}
}
Pour que cette classe soit connue de Laravel, on la déclare dans la méthode boot du provider AppServiceProvider :
Le message est prévu dans resources/lang/fr et en/validation.php. Ainsi en cas de mauvaise saisie on obtient ce résultat :
Le reste de la validation est classique.
Nota : il aurait été possible de prévoir l'expression régulière directement dans les règles de validation de la requête de formulaire, mais j'ai préféré montrer un exemple de réalisation de règle spécifique.
IV-C. L'enregistrement▲
Si la validation se passe bien le contrôleur fait appel à la méthode store du repository BlogRepository :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
/**
* Create a post.
*
*
@param
array
$inputs
*
@param
int
$user_id
*
@return
void
*/
public function store($inputs
,
$user_id
)
{
$post
=
new $this
->
model;
$post
=
$this
->
savePost($post
,
$inputs
,
$user_id
);
// Tags gestion
if(array_key_exists('
tags
'
,
$inputs
) &&
$inputs
[
'
tags
'
]
!=
''
) {
$tags
=
explode('
,
'
,
$inputs
[
'
tags
'
]
);
foreach ($tags
as $tag
) {
$tag_ref
=
$this
->
tag->
whereTag($tag
)->
first();
if(is_null($tag_ref
)) {
$tag_ref
=
new $this
->
tag();
$tag_ref
->
tag =
$tag
;
$post
->
tags()->
save($tag_ref
);
}
else {
$post
->
tags()->
attach($tag_ref
->
id);
}
}
}
}
Il est fait ici appel à une méthode commune avec la modification d'un article :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
/**
* Create or update a post.
*
*
@param
App\Models\Post
$post
*
@param
array
$inputs
*
@param
bool
$user_id
*
@return
App\Models\Post
*/
private function savePost($post
,
$inputs
,
$user_id
=
null)
{
$post
->
title =
$inputs
[
'
title
'
];
$post
->
summary =
$inputs
[
'
summary
'
];
$post
->
content =
$inputs
[
'
content
'
];
$post
->
slug =
$inputs
[
'
slug
'
];
$post
->
active =
isset($inputs
[
'
active
'
]
);
if($user_id
) $post
->
user_id =
$user_id
;
$post
->
save();
return $post
;
}
La gestion la plus délicate concerne évidemment les tags. Il faut faire une boucle pour les traiter tous, vérifier s'ils existent déjà dans la base, et enfin les attacher à l'article.
V. Modifier un article▲
La modification d'un article a évidemment beaucoup de code en commun avec la création d'un article.
V-A. Le formulaire▲
C'est cette fois la méthode edit du contrôleur BlogController qui est utilisée :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
/**
* Show the form for editing the specified resource.
*
*
@param
App\Repositories\UserRepository
$user_gestion
*
@param
int
$id
*
@return
Response
*/
public function edit(
UserRepository $user_gestion
,
$id
)
{
$post
=
$this
->
blog_gestion->
getByIdWithTags($id
);
$this
->
authorize('
change
'
,
$post
);
$url
=
config('
medias.url
'
);
return view('
back.blog.edit
'
,
array_merge($this
->
blog_gestion->
edit($post
),
compact('
url
'
)));
}
Il faut aller chercher les informations existantes (titre, sommaire, contenu, tags…) avec la méthode GetByIdWithTags du repository BlogRepository :
Remarquez la précaution prise pour limiter la modification d'un article à son créateur :
$this
->
authorize('
change
'
,
$post
);
On trouve la méthode correspondante dans app/Policies/PostPolicy.php :
D'autre part un administrateur a tous les droits et peut aussi modifier un article même s'il ne lui appartient pas :
Le contrôleur génère la vue :
Avec aussi peu de code que pour la création :
2.
3.
4.
5.
@extends
('back.blog.template'
)
@section
('form'
)
{!!
Form::
model($post
,
[
'route'
=>
[
'blog.update'
,
$post
->
id],
'method'
=>
'put'
,
'class'
=>
'form-horizontal panel'
]
) !!}
@stop
Cette fois, on a Form::model pour avoir nos champs de saisie automatiquement complétés par le modèle $post. Le formulaire est évidemment le même avec les champs complétés.
V-B. La validation▲
La validation est presque identique puisqu'elle utilise la même requête de formulaire que nous avons déjà vue ci-dessus (PostRequest). Comment est-ce qu'on fait la différence ? Tout simplement, en testant la présence du paramètre blog dans la requête :
Si on a ce paramètre, alors on ajoute l'id de l'article en cours de modification pour ne pas tomber sur une erreur de validation parasite parce que le slug existe forcément déjà dans la base.
V-C. L'enregistrement▲
Si la validation se passe bien le contrôleur fait appel à la méthode update du repository BlogRepository :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
/**
* Update a post.
*
*
@param
array
$inputs
*
@param
App\Models\Post
$post
*
@return
void
*/
public function update($inputs
,
$post
)
{
$post
=
$this
->
savePost($post
,
$inputs
);
// Tag gestion
$tags_id
=
[];
if(array_key_exists('
tags
'
,
$inputs
) &&
$inputs
[
'
tags
'
]
!=
''
) {
$tags
=
explode('
,
'
,
$inputs
[
'
tags
'
]
);
foreach ($tags
as $tag
) {
$tag_ref
=
$this
->
tag->
whereTag($tag
)->
first();
if(is_null($tag_ref
)) {
$tag_ref
=
new $this
->
tag();
$tag_ref
->
tag =
$tag
;
$tag_ref
->
save();
}
array_push($tags_id
,
$tag_ref
->
id);
}
}
$post
->
tags()->
sync($tags_id
);
}
On se retrouve avec un code très proche de celui pour la création.
VI. Supprimer un article▲
La suppression d'un article s'effectue à partir du bouton « Supprimer » de la liste des articles :
C'est cette fois la méthode destroy du contrôleur BlogController qui est utilisée :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
/**
* Remove the specified resource from storage.
*
*
@param
int
$id
*
@return
Response
*/
public function destroy($id
)
{
$post
=
$this
->
blog_gestion->
getById($id
);
$this
->
authorize('
change
'
,
$post
);
$this
->
blog_gestion->
destroy($post
);
return redirect('
blog
'
)->
with('
ok
'
,
trans('
back/blog.destroyed
'
));
}
On a la même autorisation que pour la modification.
Le contrôleur appelle la méthode destroy du repository BlogRepository :
On commence par détacher les tags et ensuite on supprime l'article.
Ensuite le contrôleur redirige sur la même page avec un message en session :
VII. Les commentaires▲
L'administrateur dispose également sur son tableau de bord d'un bloc pour les commentaires :
Le code pour afficher le bloc est identique à celui que l'on a vu pour les articles.
Il y a également dans le menu un lien vers les commentaires :
Voici le panneau de gestion des commentaires :
L'administrateur peut ici :
- supprimer un commentaire ;
- valider l'utilisateur pour les commentaires ;
- marquer le commentaire comme « lu ».
La vue utilisée est celle-ci :
L'affichage des commentaires est assuré par une boucle :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
@foreach
($comments
as
$comment
)
<
div class
=
"
panel
{!!
$comment
->
seen?
'panel-default'
:
'panel-warning'
!!}
"
>
<
div class
=
"
panel-heading
{!!
$comment
->
user->
valid?
''
:
'border-red'
!!}
"
>
<
table class
=
"
table
"
>
<
thead>
<
tr>
<
th class
=
"
col-lg-3
"
>
{{
trans('back/comments.author'
) }}
<
/th
>
<
th class
=
"
col-lg-3
"
>
{{
trans('back/comments.date'
) }}
<
/th
>
<
th class
=
"
col-lg-3
"
>
{{
trans('back/comments.post'
) }}
<
/th
>
<
th class
=
"
col-lg-1
"
>
{{
trans('back/comments.valid'
) }}
<
/th
>
<
th class
=
"
col-lg-1
"
>
{{
trans('back/comments.seen'
) }}
<
/th
>
<
th class
=
"
col-lg-1
"
></th
>
<
/tr
>
<
/thead
>
<
tbody>
<
tr>
<
td class
=
"
text-primary
"
><strong>
{{
$comment
->
user->
username }}
<
/strong
></td
>
<
td>
{{
$comment
->
created_at }}
<
/td
>
<
td>
{{
$comment
->
post->
title }}
<
/td
>
<
td>
{!!
Form::
checkbox('valide'
,
$comment
->
user->
id,
$comment
->
user->
valid) !!}
<
/td
>
<
td>
{!!
Form::
checkbox('seen'
,
$comment
->
id,
$comment
->
seen) !!}
<
/td
>
<
td>
{!!
Form::
open([
'method'
=>
'DELETE'
,
'route'
=>
[
'comment.destroy'
,
$comment
->
id]]
) !!}
{!!
Form::
destroy(trans('back/comments.destroy'
),
trans('back/comments.destroy-warning'
),
'btn-xs'
) !!}
{!!
Form::
close() !!}
<
/td
>
<
/tr
>
<
/tbody
>
<
/table
>
<
/div
>
<
div class
=
"
panel-body
"
>
{!!
$comment
->
content !!}
<
/div
>
<
/div
>
@endforeach
VII-A. Supprimer un commentaire▲
La suppression d'un commentaire est assurée par la méthode destroy du contrôleur CommentController :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
/**
* Remove the specified resource from storage.
*
*
@param
Illuminate\Http\Request
$request
*
@param
int
$id
*
@return
Response
*/
public function destroy(
Request $request
,
$id
)
{
$this
->
comment_gestion->
destroy($id
);
if($request
->
ajax())
{
return response()->
json([
'
id
'
=>
$id
]
);
}
return redirect('
comment
'
);
}
Nous avons déjà vu cette méthode lorsque nous avons étudié le front-end. La requête était alors effectuée en Ajax. Dans la partie administration, on la fait de façon classique.
C'est la méthode destroy du repository de base Baserepository qui assure la suppression dans la base :
VII-B. Valider l'utilisateur▲
Par sécurité un utilisateur nouvellement inscrit ne voit pas apparaître ses commentaires, il faut qu'un administrateur le valide. Évidemment une fois que cette action est effectuée tous les autres commentaires apparaissent immédiatement.
Tant qu'un utilisateur n'est pas validé, tous ses commentaires apparaissent bordés de rouge :
Le changement s'effectue par action sur la case à cocher « valide ». La requête est envoyée en Ajax :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
// Valide gestion
$(
":checkbox[name='valide']"
).change
(
function(
) {
var cases =
$(
":checkbox[name='valide'][value='"
+
this.
value +
"']"
);
cases.prop
(
'checked'
,
this.
checked);
cases.parents
(
'.panel-heading'
).toggleClass
(
'border-red'
);
cases.hide
(
).parent
(
).append
(
'<i class="fa fa-refresh fa-spin"></i>'
);
var token =
$(
'input[name="_token"]'
).val
(
);
$.ajax
({
url
:
'
{!!
url('uservalid'
) !!}
'
+
'/'
+
this.
value,
type
:
'PUT'
,
data
:
"valid="
+
this.
checked +
"&_token="
+
token
}
)
.done
(
function(
) {
$(
'.fa-spin'
).remove
(
);
$(
'input[type="checkbox"]:hidden'
).show
(
);
}
)
.fail
(
function(
) {
$(
'.fa-spin'
).remove
(
);
var cases =
$(
'input[type="checkbox"]:hidden'
);
cases.parents
(
'.panel-heading'
).toggleClass
(
'border-red'
);
cases.show
(
).prop
(
'checked'
,
cases.is
(
':checked'
) ?
null
:
'checked'
);
alert
(
'
{{
trans('back/comments.fail'
) }}
'
);
}
);
}
);
Une petite animation signifie à l'administrateur que l'action est en cours :
La requête arrive à la méthode valid du contrôleur CommentController :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
/**
* Validate an user
*
*
@param
Illuminate\Http\Request
$request
*
@param
App\Repositories\UserRepository
$user_gestion
*
@param
int
$id
*
@return
Response
*/
public function valid(
Request $request
,
UserRepository $user_gestion
,
$id
)
{
$user_gestion
->
valide($request
->
input('
valid
'
),
$id
);
return response()->
json();
}
C'est finalement la méthode valide du repository UserRepository qui assure la modification dans la base :
VII-C. Marquer le commentaire▲
Un commentaire non lu apparaît avec un fond jaune :
Le changement s'effectue par action sur la case à cocher « Vu ». La requête est envoyée en Ajax selon un principe identique à celui de la validation de l'utilisateur.
La requête arrive à la méthode updateSeen du contrôleur CommentController :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
/**
* Update "seen" in the specified resource in storage.
*
*
@param
Illuminate\Http\Request
$request
*
@param
int
$id
*
@return
Response
*/
public function updateSeen(
Request $request
,
$id
)
{
$this
->
comment_gestion->
update($request
->
input('
seen
'
),
$id
);
return response()->
json();
}
C'est finalement la méthode update du repository CommentRepository qui assure la modification dans la base :
Nous avons ainsi fait le tour de la gestion des articles côté back-end.
VIII. Remerciements▲
Nous remercions Maurice Chavelli qui nous autorise à publier ce tutoriel.
Nous tenons également à remercier Winjerome pour la mise au gabarit et Claude Leloup pour la relecture orthographique.