Cómo Crear un Sistema CRUD con Laravel-Livewire
En esta oportunidad realizaremos un proyecto que nos permita implementar un sistema de contactos utilizando Laravel Livewire (awesome work! Caleb Porzio) a través del método CRUD (Create, Read, Update, Delete) pero con toda la magia y funcionalidad que nos entrega laravel-livewire.
1. Crear nuestro proyecto en Laravel
laravel new contactos
2. Ingresar a tu proyecto e instalar Tailwindcss
cd contactos
Para Tailwindcss como preset puedes utilizar el comando (más info):
npx use-tailwind-preset
en mi caso utilizo la opción “yes” para la generación de los archivos necesarios para para la autenticación de usuarios “auth files”.
O seguir la documentación oficial para instalar y configurar lo que requieras.
“Siempre recuerda que debes configurar tu entorno con las variables correspondientes a la base de datos, idioma y lo que requieras”
3. Definir la ruta
Abrir el archivo routes/web.php
y definir la ruta que utilizaremos para todas las operaciones CRUD (puesto que laravel livewire manejará todo lo demás por nosotros).
Route::view('contacts', 'users.contacts');
4. Genera la vistas para el CRUD
Si te fijas, al determinar una ruta del tipo users.contacts
implica que deberás crearla dentro de la ruta resources/views/
y luego generar el archivo contacts.blade.php
debiera quedar así:
Dentro del archivo contacts.blade.php
debemos agregar el componente de laravel-livewire que crearemos en el próximo paso, quedando de la siguiente manera:
@extends('layouts.app')@section('content')
<div class="flex justify-center mx-auto p-4 max-w-4xl rounded shadow mb-4">
@livewire('contact')
</div>
@endsection
5. Generar el modelo ‘Contact’
La alternativa más simple y directa es generar el modelo a través del siguiente comando (adicionando el flag -m
para generar la migración de inmediato):
php artisan make:model Contact -m
El modelo debiera incorporar solo la variable protected $guarded = [];
esto puesto que estamos en un ambiente de prueba y nos permite agregar todos los campos que quisiéramos pasar a la BD. Debiera verse así:
<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Contact extends Model
{
protected $guarded = [];
}
En este ejemplo solo utilizaremos dos campos, el Nombre y el correo electrónico, por lo que la migración debiera ser muy simple. Solo agrega las siguientes dos líneas a la migración nueva generada:
public function up()
{
Schema::create('contacts', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('email')->unique(); $table->timestamps();
});
}
El correo está marcado como
unique()
con el objeto de evitar agregar dos usuarios con el mismo email.
Por úlitmo, correr el siguiente comando para generar la tabla en tu base de datos:
php artisan migrate
6. Instalar Laravel Livewire
Es muy simple, solo debes correr el siguiente comando en tu terminal:
composer require livewire/livewire
Hay que incorporar @livewireStyles
antes del </head>
y @livewireScripts
antes de la etiqueta </body>
en el archivo resources/views/layouts/app.blade.php
quedando así:
<!doctype html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"><!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}"><title>{{ config('app.name', 'Laravel') }}</title><!-- Styles -->
<link href="{{ mix('css/app.css') }}" rel="stylesheet"> @livewireStyles</head>
<body class="bg-gray-100 h-screen antialiased leading-none">
<div id="app">
<nav class="bg-blue-900 shadow mb-8 py-6">
<div class="container mx-auto px-6 md:px-0">
<div class="flex items-center justify-center">
<div class="mr-6">
<a href="{{ url('/') }}" class="text-lg font-semibold text-gray-100 no-underline">
{{ config('app.name', 'Laravel') }}
</a>
</div>
<div class="flex-1 text-right">
@guest
<a class="no-underline hover:underline text-gray-300 text-sm p-3" href="{{ route('login') }}">{{ __('Login') }}</a>
@if (Route::has('register'))
<a class="no-underline hover:underline text-gray-300 text-sm p-3" href="{{ route('register') }}">{{ __('Register') }}</a>
@endif
@else
<span class="text-gray-300 text-sm pr-4">{{ Auth::user()->name }}</span><a href="{{ route('logout') }}"
class="no-underline hover:underline text-gray-300 text-sm p-3"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">{{ __('Logout') }}</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="hidden">
{{ csrf_field() }}
</form>
@endguest
</div>
</div>
</div>
</nav>@yield('content')
</div><!-- Scripts -->
<script src="{{ mix('js/app.js') }}"></script> @livewireScripts</body>
</html>
7. Crear el componente de Laravel-Livewire
Es posible crear los componentes de Laravel-Livewire a través de un comando artisan:
php artisan make:livewire contact
Con ello se crearán dos archivos. El primero app/Http/Livewire/Contact.php
y el otro resources/views/livewire/contact.blade.php
.
La estructura del primer archivo deberá quedar así:
<?phpnamespace App\Http\Livewire;use App\Contact as Contactos;
use Livewire\Component;class Contact extends Component
{
public $data, $name, $email, $selected_id;
public $updateMode = false; public function render()
{
$this->data = Contactos::all();
return view('livewire.contact');
} private function resetInput()
{
$this->name = null;
$this->email = null;
} public function store()
{
$this->validate([
'name' => 'required|min:5',
'email' => 'required|email:rfc,dns'
]); Contactos::create([
'name' => $this->name,
'email' => $this->email
]); $this->resetInput();
} public function edit($id)
{
$record = Contactos::findOrFail($id); $this->selected_id = $id;
$this->name = $record->name;
$this->email = $record->email; $this->updateMode = true;
} public function update()
{
$this->validate([
'selected_id' => 'required|numeric',
'name' => 'required|min:5',
'email' => 'required|email:rfc,dns'
]); if ($this->selected_id) {
$record = Contactos::find($this->selected_id);
$record->update([
'name' => $this->name,
'email' => $this->email
]); $this->resetInput();
$this->updateMode = false;
} } public function destroy($id)
{
if ($id) {
$record = Contactos::where('id', $id);
$record->delete();
}
}
}
Hay que observar con detención todos los componentes de esta clase. Es acá donde se realizarán todas las operaciones CRUD. Hemos declarado las siguientes propiedades como públicas ( $data, $name, $email, $select_id, $updateMode
) las que serán cargadas de nuestro componente en la vista. Esta clase de componente realiza las acciones típicas de un controlador en Laravel.
8. Crear las vistas de los componentes de Laravel-Livewire
Ahora hay que crear dos archivos adicionales en la carpeta resources/views/livewire
, el primero create.blade.php
y el segundo update.blade.php
. Con esto tendremos tres archivos dentro de esa carpeta:
El archivo contact.blade.php
debe contener la siguiente estructura y contenido:
<div>
@if($updateMode)
@include('livewire.update')
@else
@include('livewire.create')
@endif<table class="table-auto w-full">
<thead>
<tr class="bg-gray-200">
<th class="px-4 py-2">#</th>
<th class="px-4 py-2">Nombre</th>
<th class="px-4 py-2">Email</th>
<th class="px-4 py-2">acciones</th>
</tr>
</thead>
<tbody>
@forelse ($data as $item)
<tr class="text-center">
<td class="border px-4 py-2">{{ $item->id }}</td>
<td class="border px-4 py-2">{{ $item->name }}</td>
<td class="border px-4 py-2">{{ $item->email }}</td>
<td class="border px-4 py-2">
<button wire:click="edit({{ $item->id }})" class="px-2 py-1 bg-blue-200 text-blue-500 hover:bg-blue-500 hover:text-white rounded">Editar</button>
<button wire:click="destroy({{ $item->id }})" class="px-2 py-1 bg-red-200 text-red-500 hover:bg-red-500 hover:text-white rounded">Borrar</button>
</td>
</tr>
@empty
<tr class="text-center">
<td colspan="4" class="py-3 italic">No hay información</td>
</tr>
@endforelse
</tbody>
</table>
</div>
El siguiente archivo, create.blade.php
posee el siguiente código:
<div class="w-full">
<div class="flex flex-wrap justify-between items-center mb-16">
<div class="w-auto pr-3">
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="name">Nombre</label>
<input class="appearance-none block w-full bg-gray-200 text-gray-700 border {{ $errors->has('name') ? ' border-red-500' : 'border-gray-200' }} rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white" id="name" wire:model="name" type="text" placeholder="Nombre completo...">
@error('name')
<span class="text-red-500 text-xs italic">{{ $message }}</span>
@enderror
</div>
<div class="w-auto px-3">
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="email">Email</label>
<input class="appearance-none block w-full bg-gray-200 text-gray-700 border {{ $errors->has('name') ? ' border-red-500' : 'border-gray-200' }} rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500" id="email" wire:model="email" type="text" placeholder="Correo electrónico...">
@error('email')
<span class="text-red-500 text-xs italic py-1">{{ $message }}</span>
@enderror
</div>
<div class="w-auto pl-3 text-right">
<div class="pt-5">
<button wire:click="store()" class="px-3 py-2 bg-purple-200 text-purple-500 hover:bg-purple-500 hover:text-purple-100 rounded">Agregar contacto</button>
</div>
</div>
</div>
</div>
El último archivo update.blade.php
debe contener el código:
<div class="w-full">
<div class="flex flex-wrap justify-between items-center mb-16">
<input type="hidden" wire:model="selected_id">
<div class="w-auto pr-3">
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="name">Nombre</label>
<input wire:model="name" type="text" class="appearance-none block w-full bg-gray-200 text-gray-700 border {{ $errors->has('name') ? ' border-red-500' : 'border-gray-200' }} rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white">
@error('name')
<span class="text-red-500 text-xs italic">{{ $message }}</span>
@enderror
</div>
<div class="w-auto px-3">
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="email">Email</label>
<input wire:model="email" type="text" class="appearance-none block w-full bg-gray-200 text-gray-700 border {{ $errors->has('email') ? ' border-red-500' : 'border-gray-200' }} rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500">
@error('email')
<span class="text-red-500 text-xs italic py-1">{{ $message }}</span>
@enderror
</div>
<div class="w-auto pl-3 text-right">
<button wire:click="update()" class="px-3 py-2 bg-orange-200 text-orange-500 hover:bg-orange-500 hover:text-orange-100 rounded">Actualizar contacto</button>
</div>
</div>
</div>
9. Capturas de pantalla del flujo
Ingresa primero a la dirección de tu proyecto, en este caso contactos.test/contacts
y debieras ver una pantalla similar a esta:
En esta primera vista debieras notar que por defecto se presenta la palabra “no hay información” esto se debe a la utilización del loop
@forelse
y luego@empty
lo que nos permite pasar un mensaje en caso que no existan valores.
Agrega el nombre completo y el correo de tu primer contacto (los archivos están con la validación de ambos campos y los mensajes de error incluidos). Debieras tener una pantalla similar a esta:
Ahora puedes editar la información presionando el botón “editar”:
Por último, puedes borrar el contacto presionando el botón “borrar”. El usuario automáticamente será eliminado de tu base de datos y de la pantalla.
10. Consideraciones finales
Tu sistema está listo para ser utilizado en algún proyecto. Espero te motives a aprender más de Laravel, Laravel-Livewire (pssst… te paso un dato, Caleb además ha creado un microframework de javascript llamado “alpine.js”, la magia se amplifica!)
https://github.com/alpinejs/alpine
Finalmente podrás utilizar un sistema totalmente “mágico” para el ingreso, edición o borrado de tus contactos. Espero que esta aplicación CRUD explicada paso a paso sirva para comenzar a utilizar de mayor y mejor forma Laravel-Livewire.
Gracias por tu lectura.
Si te ha gustado, podrías darme un aplauso y seguirme :)
Puedes compartir libremente esta publicación en tus redes sociales si te ha resultado útil.