Laravel 5

Créer une application : les articles (back-end)

Article modifié le 28/10/2015

Dans le précédent article on a vu comment sont gérés les articles et leurs commentaires au niveau du front-end. Nous allons à présent nous intéresser à la face cachée, non pas de la force, mais de l’application pour la gestion des articles par les administrateurs et les rédacteurs.

Si les administrateurs doivent avoir un accès total à tous les articles, commentaires et médias, les rédacteurs doivent être limités à leur propre production. Il ne serait pas judicieux de les laisser modifier l’article d’un autre rédacteur. Quant aux utilisateurs de base ils ne doivent évidemment avoir accès à rien de tout cela.

Voyons comment cela est réalisé dans l’application.

Le panneau

Sur son tableau de bord l’administrateur trouve un bloc qui concerne les articles :

img82

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 :

/**
* 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 :

/**
 * Get number of records.
 *
 * @return array
 */
public function getNumber()
{
	$total = $this->model->count();

	$new = $this->model->whereSeen(0)->count();

	return compact('total', 'new');
}

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 :

img83

Il dispose alors d’une vue globale sur les articles existants :

img84

Un rédacteur aboutit directement à cette page et ne dispose que de ses articles.

A 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 mis à part la visualisation d’un article qui se contente de le générer dans le front-end.

Le tri

 Lorsque les articles ne sont pas triés on a les deux petits sélecteurs qui apparaissent :

img85

Lorsqu’on clique sur les sélecteurs ont passe en tri décroissant et seul le sélecteur inférieur apparaît :

img86

Lorsqu’on clique à nouveau on passe en mode tri croissant et seul le sélecteur supérieur apparaît :

img87

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 :

// 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 :

/**
 * 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 :

/**
 * 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 :

img88

En voici le code :

@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 :

.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.

Publication et vu

L’administrateur ou le rédacteur dispose pour chaque article d’une case à cocher pour publier ou dé-publier un article :

img89

Cette action est aussi gérée en Ajax et on a une petite animation en attendant qu’elle s’effectue :

img90

Voici le code Javascript qui gère côté client :

// 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 :

/**
 * 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 :

/**
 * Update "active" in post.
 *
 * @param  array  $inputs
 * @param  int    $id
 * @return void
 */
public function updateActive($inputs, $id)
{
	$post = $this->getById($id);
	$post->active = $inputs['active'] == 'true';	
	$post->save();			
}

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.

Créer un article

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 :

img91                    img92

C’est la méthode create du contrôleur BlogController qui reçoit la requête :

/**
 * Show the form for creating a new resource.
 *
 * @return Response
 */
public function create()
{
	$url = config('medias.url');
	
	return view('back.blog.create')->with(compact('url'));
}

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 :

img93

Si vous regardez le code de cette vue vous n’allez pas trouver grand chose :

@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 :

<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 :

img94

Le permalien est géré dynamiquement avec une fonction Javascript :

$("#title").keyup(function(){
		var str = sansAccent($(this).val());
		str = str.replace(/[^a-zA-Z0-9\s]/g,"");
		str = str.toLowerCase();
		str = str.replace(/\s/g,'-');
		$("#permalien").val(str);        
	});

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 article. J’ai évoqué dans le même article l’intégration de FileManager.

Enfin une zone permet la saisie des tags.

La validation

La soumission du formulaire aboutit à la méthode store du contrôleur BlogController :

/**
 * 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 :

<?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ègles 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 :

img95

Elle ne comporte qu’une règle :

<?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 :

public function boot()
{
	Validator::resolver(function($translator, $data, $rules, $messages)
	{
	    return new Validation($translator, $data, $rules, $messages);
	});
}

Le message est prévu dans resources/lang/fr et en/validation.php. Ainsi en cas de mauvaise saisie on obtient ce résultat :

img96

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.

L’enregistrement

Si la validation se passe bien le contrôleur fait appel à la méthode store du repository BlogRepository :

/**
 * 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 :

/**
 * 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éja dans la base, et enfin les attacher à l’article.

Modifier un article

La modification d’un article a évidemment beaucoup de code en commun avec la création d’un article.

Le formulaire

C’est cette fois la méthode edit du contrôleur BlogController qui est utilisée :

/**
 * 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 :

/**
 * Get post collection.
 *
 * @param  int  $id
 * @return array
 */
public function GetByIdWithTags($id)
{
    return $this->model->with('tags')->findOrFail($id);
}

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 :

/**
 * Determine if the given post can be changed by the user.
 *
 * @param  \App\Models\User  $user
 * @param  \App\Models\Post  $post
 * @return bool
 */
public function change(User $user, Post $post)
{
    return $user->id === $post->user_id;
}

D’autre pas un administrateur a tous les droits et peut aussi modifier un article même s’il ne lui apparatient pas :

/**
 * Grant all abilities to administrator.
 *
 * @param  \App\Models\User  $user
 * @param  string  $ability
 * @return bool
 */
public function before(User $user, $ability)
{
    if ($user->isAdmin()) {
        return true;
    }
}

Le contrôleur génère la vue :

img97

Avec aussi peu de code que pour la création :

@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.

La validation

La validation est presque identique puisqu’elle utilise la même requête de formulaire que nous avons déjà vu ci-dessus (PostRequest). Comment est-ce qu’on fait la différence ? Tout simplement en testant la présence du paramètres blog dans la requête :

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'
	];
}

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.

L’enregistrement

Si la validation se passe bien le contrôleur fait appel à la méthode update du repository BlogRepository :

/**
 * 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.

Supprimer un article

La suppression d’un article s’effectue à partir du bouton « Supprimer » de la liste des articles :

img98

C’est cette fois la méthode destroy du contrôleur BlogController qui est utilisée :

/**
 * 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 :

/**
 * Destroy a post.
 *
 * @param  App\Models\Post $post
 * @return void
 */
public function destroy($post)
{
    $post->tags()->detach();
    
    $post->delete();
}

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 :

img99

Les commentaires

L’administrateur dispose également sur son tableau de bord d’un bloc pour les commentaires :

img02

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 :

img03

Voici le panneau de gestion des commentaires :

img04

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 :

img05

L’affichage des commentaires est assurée par une boucle :

@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

Supprimer un commentaire

La suppression d’un commentaire est assurée par la méthode destroy du contrôleur CommentController :

/**
 * 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 :

/**
 * Destroy a model.
 *
 * @param  int $id
 * @return void
 */
public function destroy($id)
{
	$this->getById($id)->delete();
}

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 :

img06

Le changement s’effectue par action sur la case à cocher « valide ». La requête est envoyée en Ajax :

// 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 :

img07

La requête arrive à la méthode valid du contrôleur CommentController :

/**
 * 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 :

/**
 * Valid user.
 *
 * @param  bool  $valid
 * @param  int   $id
 * @return void
 */
public function valide($valid, $id)
{
	$user = $this->getById($id);
	$user->valid = $valid == 'true';
	$user->save();
}

Marquer le commentaire

Un commentaire non lu apparaît avec un fond jaune :

img08

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 :

/**
 * 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 :

/**
 * Update a comment.
 *
 * @param  bool  $vu
 * @param  int   $id
 * @return void
 */
public function update($seen, $id)
{
	$comment = $this->getById($id);
	$comment->seen = $seen == 'true';
	$comment->save();
}

Nous avons ainsi fait le tour de la gestion des articles côté back-end.

Print Friendly, PDF & Email

Laisser un commentaire