Cuando trabajamos con aplicaciones empresariales, hay muchas tablas de la base de datos que requieren de un mantenimiento por parte del usuario. Crear las lógicas de presentación y lógicas de negocio, suele ser una tarea tediosa y repetitiva. Para solucionar este problema, tenemos varios paquetes de Laravel que nos pueden ayudar con esta tarea. Porque a fin de cuentas, Laravel se encarga de realizar por nosotros tareas que no aportan valor a nuestra aplicación y un mantenimiento de tabla es una de ellas.
¿Qué es un CRUD?
CRUD es el acrónimo en inglés que utilizamos para el mantenimiento de tablas, con las operaciones de Creación, Lectura, Modificación y Borrado (Create, Read, Update y Delete). Es decir esos mantenimientos sencillos en los que lo único que se hace es modificar la información de base de datos sin tener operaciones encadenadas. Solamente unas cuantas validaciones de formato y puede que de rango de valores.
Hay múltiples herramientas que nos pueden ayudar en el diseño de la lógica de negocio y las pantallas necesarias para estas operaciones, pero nosotros vamos a utilizar un paquete de los muchos disponibles en los repositorios de Composer.
Partimos de una aplicación que tiene un frontal que se apoya en Bootstrap para el CSS de frontal y para localizar el mejor paquete de los disponibles en Packagist, realizamos una búsqueda de los dos términos CRUD y Bootstrap con la etiqueta Laravel.
De las opciones que nos presenta, nos vamos a quedar con una de las primeras (en mi búsqueda la segunda) que es CRUD Generator de Ibex. La documentación en Packagist no es mucha, pero suficiente para ver que es compatible con nuestra versión 11 de Laravel y nos incluye un enlace a su repositorio de GitHub. Es aquí donde tenemos toda la documentación.
Cuando utilices un paquete, fíjate en la compatibilidad con las versiones más recientes de Laravel, lo ideal es que utilice tu misma versión mayor y que que tu código utilice la última. En caso de versiones anteriores, podría ser compatible con tu código, pero es importante que tu desarrollo esté lo más actualizado posible para poder utilizar toda la potencia y seguridad de los paquetes más recientes.
Artículo recomendado: ¿Estás listo para migrar tus aplicaciones a Laravel 11?
Instalando el paquete
Como en todos los casos que instalamos un paquete desde el repositorio, ejecutamos composer, pero en este caso, utilizamos un modificador:
composer require ibex/crud-generator --dev
Lenguaje del código: JavaScript (javascript)
El modificador o bandera dev nos sirve para indicar que se trata de un paquete que solamente es necesario para el desarrollo de nuestro proyecto. Si ya estás acostumbrado a utilizar paquetes de test como phpunit o pest
Esto es importante para que cuando llevemos nuestro proyecto a producción no incluya paquetes innecesarios. Especialmente si están orientados a desarrollo, ya que podrían suponer una vulnerabilidad en la seguridad de Laravel.
Aunque tras la instalación del paquete ya tengamos creado el comando, no estará disponible hasta que no lo publiquemos con
php artisan vendor:publish --tag=crud
Si ahora ejecutamos el listado de comandos de artisan, visualizamos en la lista de comandos disponibles el nuevo
php artisan list
...
make
make:cast Create a new custom Eloquent cast class
make:channel Create a new channel class
make:command Create a new Artisan command
make:component Create a new view component class
make:controller Create a new controller class
make:crud Create bootstrap Laravel CRUD operations
make:event Create a new event class
make:exception Create a new custom exception class
make:factory Create a new model factory
make:job Create a new job class
make:listener Create a new event listener class
make:livewire Create a new Livewire component
make:mail Create a new email class
make:middleware Create a new middleware class
make:migration Create a new migration file
make:model Create a new Eloquent model class
make:notification Create a new notification class
make:observer Create a new observer class
make:policy Create a new policy class
make:provider Create a new service provider class
make:request Create a new form request class
make:resource Create a new resource
make:rule Create a new validation rule
make:scope Create a new scope class
make:seeder Create a new seeder class
make:test Create a new test class
...
Lenguaje del código: CSS (css)
A crear cruds
Ahora que ya tenemos nuestro nuevo comando disponible vamos a ponerlo en práctica creando un mantenimiento de una tabla.
La ejecución del comando es sencilla, solamente debemos indicar como parámetro el nombre de la tabla sobre la que queremos realizar el mantenimiento.
Este es un paquete bastante purista, por lo que la tabla debe seguir los estándares de nomenclatura de Laravel y por lo tanto estar en plural.
Yo he solicitado la creación de un CRUD para una tabla y un modelo ya disponible en mi proyecto (y en todos), el de usuarios, por lo que me pide confirmación de sobreescritura del modelo. Si fuera sobre una tabla que aún no tiene creado modelo, no nos haría esta pregunta. Le decimos que no y continuamos:
Creating Views ...
Please add route below:
Route::resource('users', UserController::class);
Created Successfully.
Lenguaje del código: JavaScript (javascript)
Y ya están creadas las vistas!
Para poder acceder a las vistas recién creadas desde nuestra aplicación, así como la lógica de control que llevan detrás, nos pide que añadamos una sola línea a nuestro fichero de configuración de rutas.
Importante: no te olvides de añadir la clase del nuevo controlador, porque en caso contrario, tendrás un error al intentar visualizar las páginas más adelante.
Por el camino nos ha ido creando fuentes en distintas ubicaciones del proyecto
- Modelo: En este ejemplo no lo crea, puesto que el modelo de Usuarios es básico en cualquier instalación de Laravel, pero si no fuera así nos incluiría un modelo con sus campos fillables
- Controlador: Nos genera un controlador completo con todas las operaciones necesarias para hacer un mantenimiento puro. Ten en cuenta que el borrado que realiza es físico, por lo que puede que en tu caso sea necesario modificar este método para transformarlo en un borrado lógico.
- Vistas: Y lo pongo en plural porque no nos genera un fichero, sino una carpeta con las vistas necesarias. Si has utilizado una plantilla genérica para tu proyecto y has seguido la nomenclatura recomendada, estará listo para usar, porque las nuevas vistas extienden de layouts.app y usa los yield content y template_title, para completar su funcionalidad.
Diseño las vistas creadas
Vamos a ver el código que nos ha creado para la vista Index
@extends('layouts.app')
@section('template_title')
User
@endsection
@section('content')
<div class="container-fluid">
<div class="row">
<div class="col-sm-12">
<div class="card">
<div class="card-header">
<div style="display: flex; justify-content: space-between; align-items: center;">
<span id="card_title">
{{ __('User') }}
</span>
<div class="float-right">
<a href="{{ route('users.create') }}" class="btn btn-primary btn-sm float-right" data-placement="left">
{{ __('Create New') }}
</a>
</div>
</div>
</div>
@if ($message = Session::get('success'))
<div class="alert alert-success m-4">
<p>{{ $message }}</p>
</div>
@endif
<div class="card-body bg-white">
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead class="thead">
<tr>
<th>No</th>
<th>Name</th>
<th>Email</th>
<th>Two Factor Secret</th>
<th>Two Factor Recovery Codes</th>
<th>Two Factor Confirmed At</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach ($users as $user)
<tr>
<td>{{ ++$i }}</td>
<td>{{ $user->name }}</td>
<td>{{ $user->email }}</td>
<td>{{ $user->two_factor_secret }}</td>
<td>{{ $user->two_factor_recovery_codes }}</td>
<td>{{ $user->two_factor_confirmed_at }}</td>
<td>
<form action="{{ route('users.destroy',$user->id) }}" method="POST">
<a class="btn btn-sm btn-primary " href="{{ route('users.show',$user->id) }}"><i class="fa fa-fw fa-eye"></i> {{ __('Show') }}</a>
<a class="btn btn-sm btn-success" href="{{ route('users.edit',$user->id) }}"><i class="fa fa-fw fa-edit"></i> {{ __('Edit') }}</a>
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger btn-sm"><i class="fa fa-fw fa-trash"></i> {{ __('Delete') }}</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
{!! $users->links() !!}
</div>
</div>
</div>
@endsection
Lenguaje del código: HTML, XML (xml)
Como podemos ver en la vista Index, nos ha creado todo el listado de campos y a la derecha nos añade botones para las demás operaciones del CRUD, de tal manera, que podemos visualizar, modificar o borrar. Además, en la parte superior tenemos la opción de creación de un elemento nuevo.
¿Y la paginación? Pues también está incluida. Si hemos utilizado Bootstrap en nuestro proyecto, tendrá todos los estilos aplicados para una excelente experiencia de usuario.
A probar!
Todavía no hemos terminado, nos falta la parte más importante, verificar que todo está en orden.
Levantamos nuestro servidor de pruebas y accedemos a la ruta http://localhost:8000/users para ver un listado de usuarios y aparecen los que hemos creado en nuestra aplicación:
Los textos están en inglés. No es un problema demasiado importante, puesto que el código viene listo para la internacionalización solamente tenemos que crear el fichero de recursos en la carpeta Lang para nuestro idioma y completar la lista de valores a traducir.
Me faltan campos
Si realizas el alta o la modificación de algún registro, puedes echar en falta alguno de los campos.
Este paquete, al igual que la mayoría, tiene una configuración por defecto y no siempre es la que mejor se adapta a nuestras necesidades.
Si te faltan campos como la contraseña, fecha alta o modificación, vete al fichero crud.php dentro de la carpeta config y busca la clave unwantedColumns.
Bajo esta entrada, encontrarás todos los campos que te faltan (y puede que alguno más). Elimina los que quieres que aparezcan y deja solamente los que quieras excluir.
Como gran ventaja, tienes que cada vez que ejecutas el comando va a comprobar esta lista, por lo que puedes ir modificándolo conforme a tus necesidades
/*
* Do not make these columns $fillable in Model or views
*/
'unwantedColumns' => [
'id',
'password',
'email_verified_at',
'remember_token',
'created_at',
'updated_at',
'deleted_at',
],
Lenguaje del código: PHP (php)
Por último, si haces un guardado verás que te falta una clase importante, la Custom Request.
Y es que este paquete nos crea la vista la presentación de errores incluida, por lo que necesita tener una request personalizada que realice estas validaciones.
Aunque podría crearla vacía, debemos hacerlo nosotros y programarla conforme a nuestras necesidades.
En mi caso, la creo con
php artisan make:request UserRequest
Lenguaje del código: CSS (css)
y solamente cambio la función authorize para autorizar las llamadas de cualquier usuario
public function authorize(): bool
{
return true;
}
Lenguaje del código: PHP (php)
Por supuesto, puedes modificar esta clase para añadir las validaciones que necesites en tus campos. Para no hacerlo demasiado complejo en este punto inicial, utilizamos simplemente la validación de obligatoriedad sobre el nombre y el email. Para ello añadimos en la función rules, que nos crea vacía los valores del array asociativo con el nombre del campo y la validación required:
public function rules(): array
{
return [
"name" => "required",
"email" => "required",
];
}
Lenguaje del código: PHP (php)
Si enviamos un alta de usuario sin indicar ningún valor, ya nos muestra los mensajes de error. Quedaría internacionalizar nuestra aplicación pero eso es algo que abordaremos de forma monográfica en otra ocasión:
Conclusión
En muchos lenguajes de programación y frameworks, nos tenemos que enfrentar a realizar este tipo de manipulaciones sencillas de datos, los temidos CRUD. Y no son temidos por su complejidad, sino porque son esas pequeñas tareas que son necesarias, pero que apenas aportan valor y consumen mucho tiempo de desarrollo.
Con la ayuda de los paquetes disponibles de forma pública en Laravel, podemos crear este tipo de mantenimiento de forma sencilla y en apenas unos minutos. Dejando más tiempo para abordar las tareas complejas de nuestras aplicaciones.