Personalizar Shinobi
Configuración de roles con el paquete Shinobi
Continuando la entrada configuración de Shinobi se procede a crear los controladores y las vistas del sistema de roles para poder gestionar desde el proyecto la asignación de permisos a los usuarios.
CONTROLADORES
A continuación se muestra el controlador de usuarios y de roles. Interesante destacar el método constructor de los dos controladores, que contienen una lista de middleware que se encuentran comentados y que supone otra forma de añadir los middleware en lugar de añadirlos al final de cada ruta en el archivo de rutas como se explica en la entrada anterior.
Controlador de usuarios
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use App\User;
use Caffeinated\Shinobi\Models\Role;
class UserController extends Controller
{
public function __construct(){
//los middleware se pueden implementar en el archivo de rutas
//o aquí en el constructor
/*
$this->middleware("permission:users.create")->only(["create","store"]);
//$this->middleware("permission:users.index")->only("index");
$this->middleware("permission:users.edit")->only("edit","update");
$this->middleware("permission:users.show")->only("show");
$this->middleware("permission:users.destroy")->only("destroy");
*/
}
public function index(Request $request)
{
$users=User::paginate();
return view("users.index", compact("users"));
}
public function show(User $user)
{
return view ("users.show", compact("user"));
}
public function edit(User $user)
{
$roles=Role::get()->all();
return view("users.edit",compact("user","roles"));
}
public function update(Request $request, User $user)
{
//actualizar usuario
$user->update($request->all());
//actualizar roles
$user->roles()->sync($request->get("roles"));
return redirect()->route("users.edit",$user->id)
->with("info","Usuario actualizado con éxito");
}
public function destroy(User $user)
{
$user->delete();
return back()->with("info", "Eliminado correctamente");
}
}
Controlador de roles
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Caffeinated\Shinobi\Models\Permission;
use Caffeinated\Shinobi\Models\Role;
class RoleController extends Controller
{
public function __construct(){
//los middleware se pueden implementar en el archivo de rutas
//o aquí en el constructor
/*
$this->middleware("permission:roles.create")->only(["create","store"]);
$this->middleware("permission:roles.index")->only("index");
$this->middleware("permission:roles.edit")->only("edit","update");
$this->middleware("permission:roles.show")->only("show");
$this->middleware("permission:roles.destroy")->only("destroy");
*/
}
public function index()
{
$roles=Role::paginate();
return view("roles.index",compact("roles"));
}
public function create()
{
$permissions=Permission::get();
return view("roles.create", compact("permissions"));
}
public function store(Request $request)
{
$role=Role::create($request->all());
$role->permissions()->sync($request->get("permissions"));
return redirect()->route("roles.edit", $role->id)
->with("info", "Role guardado con éxito");
}
public function show(Role $role)
{
return view("roles.show",compact("role"));
}
public function edit(Role $role)
{
$permissions=Permission::get();
return view("roles.edit", compact("role", "permissions"));
}
public function update(Request $request, Role $role)
{
$role->update($request->all());
$role->permissions()->sync($request->get("permissions"));
return redirect()->route("roles.edit", $role->id)
->with("info", "Role actualizado con éxito");
}
public function destroy($id)
{
$role=Role::find($id)->delete();
return back()->with("info", "El registro se ha eliminado correctamente");
}
}
VISTAS
Las vistas muestran el listado de usuarios y el listado de roles respectivamente mediante una tabla. Las llaves junto a los signos de admiración pertenecen a un formulario de tipo LaravelCollective que se ha añadido en el campo de eliminar de las dos vistas.
Vista de usuarios (index)
@extends("layout/layout_blog")
@section("content")
<div class="container ">
<div class="row ">
<div class="col-md-8 mt-3 flex-first ">
<div class="panel panel-default">
<div class="panel-heading text-center" >
Usuarios
</div>
<div class="panel-body">
<table class="table table-striped table-hover">
<thead>
<tr>
<th width="10px">ID</th>
<th>Nombre</th>
<th colspan="3"> </th>
</tr>
</thead>
<tbody>
@foreach($users as $user)
<tr>
<td>{{ $user->id }}</td>
<td>{{ $user->name }}</td>
<td width="10px">
@can("users.show")
<a href="{{ route("users.show", $user->id) }}"
class="btn btn-sm btn-default">
Ver
</a>
@endcan
</td>
<td width="10px">
@can("users.edit")
<a href="{{ route("users.edit", $user->id) }}"
class="btn btn-sm btn-default">
Editar
</a>
@endcan
</td>
<td width="10px">
@can("users.destroy")
- <!-- necesario Laravel/Collective -->
{!! Form::open(["route" => ["users.destroy", $user->id],
"method" => "DELETE"]) !!}
<button class="btn btn-sm btn-danger">
Eliminar
</button>
{!! Form::close() !!}
@endcan
</td>
</tr>
@endforeach
</tbody>
</table>
{{ $users->render() }}
</div>
</div>
</div>
</div>
</div>
@endsection
Vista de roles (index)
@extends("layout/layout_blog")
@section("content")
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2 mt-3 ">
<div class="panel panel-default">
<div class="panel-heading" >
Roles
@can("roles.create")
<a href="{{ route("roles.create") }}"
class="btn btn-sm btn-primary floatR">
Crear
</a>
@endcan
</div>
<div class="panel-body">
<table class="table table-striped table-hover">
<thead>
<tr>
<th width="10px">ID</th>
<th>Nombre</th>
<th colspan="3"> </th>
</tr>
</thead>
<tbody>
@foreach($roles as $role)
<tr>
<td>{{ $role->id }}</td>
<td>{{ $role->name }}</td>
<td width="10px">
@can("roles.index")
<a href="{{ route("roles.show", $role->id) }}"
class="btn btn-sm btn-default">
Ver
</a>
@endcan
</td>
<td width="10px">
@can("roles.edit")
<a href="{{ route("roles.edit", $role->id) }}"
class="btn btn-sm btn-default">
Editar
</a>
@endcan
</td>
<td width="10px">
@can("roles.destroy")
{!! Form::open(["route" => ["roles.destroy", $role->id],
"method" => "DELETE"]) !!}
<button class="btn btn-sm btn-danger">
Eliminar
</button>
{!! Form::close() !!}
@endcan
</td>
</tr>
@endforeach
</tbody>
</table>
{{ $roles->render() }}
</div>
</div>
</div>
</div>
</div>
@endsection
Solo queda añadir las vistas del detalle (show), el formulario de creación (create) y el formulario de edición (edit).
Vista detalle de usuarios (show)
@extends("layout/layout_blog")
@section("content")
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2 mt-3 ">
<div class="panel panel-default">
<div class="panel-heading text-center" >
Usuarios
</div>
<div class="panel-body">
<p><strong>Nombre</strong> {{ $user->name }}</p>
<p><strong>Email</strong> {{ $user->email }}</p>
</div>
</div>
</div>
</div>
</div>
@endsection
Vista detalle de roles (show)
@extends("layout/layout_blog")
@section("content")
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2 mt-3 ">
<div class="panel panel-default">
<div class="panel-heading text-center" >
Roles
</div>
<div class="panel-body">
<p><strong>Nombre</strong> {{ $role->name }}</p>
<p><strong>Slug</strong> {{ $role->slug }}</p>
<p><strong>Descripción</strong> {{ $role->description }}</p>
</div>
</div>
</div>
</div>
</div>
@endsection
El formulario de creación y edición se puede optimizar con LaravelCollective haciendo uso de un único formulario y añadiéndolo con un include. Para el caso de usuarios solo es necesaria la edición ya que el módulo auth ya contiene un formulario definido para la creación de usuarios. Sin embargo se realiza el mismo mecanismo que en roles para mantener la misma estructura de código.
Vista de formulario usuarios (form)
<div class="form-group">
{{ Form::label("name","Nombre") }}
{{ Form::text("name",null,["class" => "form-control"]) }}
</div>
<hr>
<h3>Lista de roles</h3>
<div class="form-group">
<ul class="list-unstyled">
@foreach($roles as $role)
<li>
<label>
{{ Form::checkbox("roles[]",$role->id,null) }}
{{ $role->name }}
<em>({{ $role->description ?: "N/A" }})</em>
</label>
</li>
@endforeach
</ul>
</div>
<div class="form-group">
{{ Form::submit("Guardar",["class" => "btn btn-sm btn-primary"]) }}
</div>
Vista de formulario roles (form)
<div class="form-group">
{{ Form::label("name","Nombre") }}
{{ Form::text("name",null,["class" => "form-control"]) }}
</div>
<div class="form-group">
{{ Form::label("slug","URL Amigable") }}
{{ Form::text("slug",null,["class" => "form-control"]) }}
</div>
<div class="form-group">
{{ Form::label("description","Descripción") }}
{{ Form::text("description",null,["class" => "form-control"]) }}
</div>
<hr>
<h3>Permiso especial</h3>
<div class="form-group">
<label>{{ Form::radio("special", "all-access") }} Acceso Total</label>
<label>{{ Form::radio("special", "no-access") }} Ningún acceso</label>
</div>
<h3>Lista de roles</h3>
<div class="form-group">
<ul class="list-unstyled">
@foreach($permissions as $permission)
<li>
<label>
{{ Form::checkbox("permissions[]",$permission->id,null) }}
{{ $permission->name }}
<em>({{ $permission->description ?: "Sin descripción" }})</em>
</label>
</li>
@endforeach
</ul>
</div>
<div class="form-group">
{{ Form::submit("Guardar",["class" => "btn btn-sm btn-primary"]) }}
</div>
A continuación se muestra el código de las vistas de creación y edición que contienen los formularios anteriores añadidos con un include. La vista de edición de usuario es la vista que permite marcar o desmarcar de la lista de roles existentes al usuario editado.
Vista de edición de usuarios (edit)
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Producto</div>
<div class="panel-body">
{!! Form::model($user, ["route" => ["users.update",$user->id],
"method" => "PUT" ]) !!}
@include("users.partials.form")
{!! Form::close() !!}
</div>
</div>
</div>
</div>
</div>
@endsection
La vista de creación está compuesta por cajas de texto para introducir el nombre, la url amigable y la descripción, además de toda la lista de permisos existentes que permiten asignar el permiso o los permisos definidos para el nuevo rol.
Vista de creación de roles (create)
@extends('layout/layout_blog')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">
Role
</div>
<div class="panel-body">
{!! Form::open(["route" => "roles.store"]) !!}
@include("roles.partials.form")
{!! Form::close() !!}
</div>
</div>
</div>
</div>
</div>
@endsection
La vista de edición es igual que la de creación pero con los datos mostrados
Vista de edición de roles (edit)
@extends('layout/layout_blog')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Role</div>
<div class="panel-body">
{!! Form::model($role, ["route" => ["roles.update",$role->id],
"method" => "PUT" ]) !!}
@include("roles.partials.form")
{!! Form::close() !!}
</div>
</div>
</div>
</div>
</div>
@endsection
Para poder comentar es necesario iniciar sesión