Formulario de contacto Laravel 9 y Livewire
Image by Tumisu from Pixabay

En este tutorial aprenderás a crear un formulario de contacto con Laravel 9 y Livewire con lo que tendrá funcionalidades reactivas como la validación en tiempo real. Este tutorial te dará bases para futuros proyectos. Sin más, manos a la obra.

Requisitos previos

  1.  Contar con un entorno de desarrollo como XAMPP, Wamp o Laragon.
  2.  Composer instalado globalmente en tu sistema operativo.
  3.  Node instalado.
  4.  Para el envío de emails desde localhost contar con una cuenta de Mailtrap.

1. Crear proyecto en Laravel 9

Abre una terminal de comandos en la raíz de tu entorno de desarrollo, para crear un nuevo proyecto en Laravel 9 ejecuta la siguiente instrucción:

composer create-project laravel/laravel formulario-laravel-9-livewire

Ingresa a la nueva carpeta del proyecto:

cd formulario-laravel-9-livewire

2. Instalar Livewire y crear componente

Para instalar Livewire en tu proyecto Laravel, en la terminal ejecuta el siguiente comando:

composer require livewire/livewire

En cada layout de tu proyecto en donde usarás Livewire antes del cierre de las etiquetas head y body agrega las siguientes directivas (en mi caso yo no uso layout):

<html>
<head>
    ...
    <livewire:styles />
</head>
<body>
    ...
    <livewire:scripts />
</body>
</html>

Ahora que ya tienes Livewire instalado en tu proyecto Laravel 9 crea un componente llamado ContactComponent, para ello en la terminal de comandos ejecuta la siguiente instrucción:

php artisan make:livewire ContactComponent

Se crearon dos archivos, el archivo app/Http/Livewire/ContactComponent.php es en donde se escribe toda la lógica del componente y el archivo resources/views/livewire/contact-component.blade.php es la vista en donde se mostrará el formulario de contacto.

3. Crear vista del formulario de contacto

Para este tutorial no utilizaré un layout, solamente estaré trabajando con la vista del formulario. Crea el archivo resources/views/contact.blade.php y agrega el siguiente código del formulario de contacto:

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
    <title>Formulario de contacto en Laravel 9 y Livewire | Diario del programador</title>
    <meta charset="utf-8">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <link href='https://fonts.googleapis.com/css?family=Roboto:400,100,300,700' rel='stylesheet' type='text/css'>

    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">

    <link rel="stylesheet" href="{{ asset('assets/css/style.css') }}">

    <livewire:styles />

</head>

<body>

    @livewire("contact-component")

    <script src="{{ asset('assets/js/jquery.min.js') }}"></script>
    <script src="{{ asset('assets/js/popper.js') }}"></script>
    <script src="{{ asset('assets/js/bootstrap.min.js') }}"></script>
    <script src="{{ asset('assets/js/jquery.validate.min.js') }}"></script>
    <script src="{{ asset('assets/js/main.js') }}"></script>

    <livewire:scripts />

</body>

</html>

Abre el archivo resources/views/livewire/contact-component.blade.php, en este archivo se agrega la parte de la vista que será reactiva, el siguiente código ya está conectado a Livewire, puedes analizar su estructura y las directivas que se agregaron en los inputs del formulario:

<div>
    <section class="ftco-section img bg-hero" style="background-image: url({{ asset('assets/images/bg_1.jpg') }});">
        <div class="container">
            <div class="row justify-content-center">
                <div class="col-md-6 text-center mb-5">
                    <h2 class="heading-section">Diario del Programador</h2>
                </div>
            </div>
            <div class="row justify-content-center">
                <div class="col-lg-11">
                    <div class="wrapper">
                        <div class="row no-gutters justify-content-between">
                            <div class="col-lg-6 d-flex align-items-stretch">
                                <div class="info-wrap w-100 p-5">
                                    <h3 class="mb-4">Contact us</h3>
                                    <div class="dbox w-100 d-flex align-items-start">
                                        <div class="icon d-flex align-items-center justify-content-center">
                                            <span class="fa fa-map-marker"></span>
                                        </div>
                                        <div class="text pl-4">
                                            <p><span>Address:</span> Ciudad Juarez, Chihuahua, Mexico
                                            </p>
                                        </div>
                                    </div>
                                    <div class="dbox w-100 d-flex align-items-start">
                                        <div class="icon d-flex align-items-center justify-content-center">
                                            <span class="fa fa-phone"></span>
                                        </div>
                                        <div class="text pl-4">
                                            <p><span>Phone:</span> <a href="tel://1234567920">+ 1235 2355 98</a></p>
                                        </div>
                                    </div>
                                    <div class="dbox w-100 d-flex align-items-start">
                                        <div class="icon d-flex align-items-center justify-content-center">
                                            <span class="fa fa-paper-plane"></span>
                                        </div>
                                        <div class="text pl-4">
                                            <p><span>Email:</span> <a
                                                    href="mailto:[email protected]">[email protected]</a>
                                            </p>
                                        </div>
                                    </div>
                                    <div class="dbox w-100 d-flex align-items-start">
                                        <div class="icon d-flex align-items-center justify-content-center">
                                            <span class="fa fa-globe"></span>
                                        </div>
                                        <div class="text pl-4">
                                            <p><span>Website</span> <a href="#">diarioprogramador.com</a></p>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="col-lg-6">
                                <div class="contact-wrap w-100 p-md-5 p-4">
                                    <h3 class="mb-4">Get in touch</h3>
                                    <div id="form-message-warning" class="mb-4"></div>

                                    {{-- Muestra mensaje de envio exitoso --}}
                                    @if ($success)
                                        <div class="alert alert-success alert-dismissible fade show" role="alert">
                                            {{ $success }}
                                            <button type="button" class="close" data-dismiss="alert"
                                                aria-label="Cerrar">
                                                <span aria-hidden="true">&times;</span>
                                            </button>
                                        </div>
                                    @endif

                                    <form wire:submit.prevent="submit" method="POST">
                                        @csrf
                                        <div class="row">
                                            <div class="col-md-12">
                                                <div class="form-group">
                                                    <input wire:model="name" type="text" class="form-control"
                                                        name="name" id="name" placeholder="Name">

                                                    @error('name')
                                                        <span class="invalid-feedback d-block" role="alert">
                                                            <strong>{{ $message }}</strong>
                                                        </span>
                                                    @enderror
                                                </div>
                                            </div>
                                            <div class="col-md-12">
                                                <div class="form-group">
                                                    <input wire:model="email" type="email" class="form-control"
                                                        name="email" id="email" placeholder="Email">
                                                    @error('email')
                                                        <span class="invalid-feedback d-block" role="alert">
                                                            <strong>{{ $message }}</strong>
                                                        </span>
                                                    @enderror
                                                </div>
                                            </div>
                                            <div class="col-md-12">
                                                <div class="form-group">
                                                    <input wire:model="phone" type="text" class="form-control"
                                                        name="phone" id="phone" placeholder="Phone">
                                                    @error('phone')
                                                        <span class="invalid-feedback d-block" role="alert">
                                                            <strong>{{ $message }}</strong>
                                                        </span>
                                                    @enderror
                                                </div>
                                            </div>
                                            <div class="col-md-12">
                                                <div class="form-group">
                                                    <input wire:model="subject" type="text"
                                                        class="form-control" name="subject" id="subject"
                                                        placeholder="Subject">
                                                    @error('subject')
                                                        <span class="invalid-feedback d-block" role="alert">
                                                            <strong>{{ $message }}</strong>
                                                        </span>
                                                    @enderror
                                                </div>
                                            </div>
                                            <div class="col-md-12">
                                                <div class="form-group">
                                                    <textarea wire:model="message" name="message" class="form-control" id="message" cols="30" rows="5"
                                                        placeholder="Message"></textarea>
                                                    @error('message')
                                                        <span class="invalid-feedback d-block" role="alert">
                                                            <strong>{{ $message }}</strong>
                                                        </span>
                                                    @enderror
                                                </div>
                                            </div>
                                            <div class="col-md-12">
                                                <div class="form-group">
                                                    <button class="btn btn-primary">Send
                                                        Message</button>
                                                </div>
                                            </div>
                                        </div>
                                    </form>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </section>
</div>

NOTA: Los assets del código los encontrás en un link al final del tutorial en donde podrás descargar la plantilla que uso para este ejemplo.

4. Configurar ruta

Abre el archivo routes/web.php y modifica la ruta que está por default por la siguiente:

Route::get('/', function () {
    return view('contact');
});

Enciende el servidor de desarrollo que viene integrado en Laravel ejecutando el comando:

php artisan serve

En el navegador web ve a la dirección: http://127.0.0.1:8000/. Podrás ver el formulario de contacto, pero aún no hace nada, en los siguientes pasos le darás reactividad.

5. Configurar archivo de lógica

Abre el archivo app/Http/Livewire en este archivo se conecta con los inputs del formulario de contacto, se agregan las reglas de validación y se valida en tiempo real, después de validar se envía un correo electrónico con todos los datos:

<?php

namespace App\Http\Livewire;

use Livewire\Component;
use App\Mail\ContactForm;
use Illuminate\Support\Facades\Mail;

class ContactComponent extends Component
{
    public $name, $email, $phone, $subject, $message;
    public $success;

    //Validacion en tiempo real
    protected $rules = [
        'name' => 'required',
        'email' => 'required',
        'phone' => 'required',
        'subject' => 'required',
        'message' => 'required'
    ];

    public function updated($propertyName)
    {
        $this->validateOnly($propertyName);
    }

    public function submit()
    {
        //Se valida las
        $rules = $this->validate();

        $data['name'] = $this->name;
        $data['email'] = $this->email;
        $data['phone'] = $this->phone;
        $data['subject'] = $this->subject;
        $data['message'] = $this->message;

        //Se instancia ContactForm y se envian los datos del formulario
        Mail::to('[email protected]')->send(new ContactForm($data));

        //Se llama a la funcion resetForm()
        $this->resetForm();

        //se envia mensaje de exito a la vista
        $this->success = 'Mensaje enviado con éxito';
    }

    //metodo limpia los campos del formulario
    private function resetForm()
    {
        $this->name = '';
        $this->email = '';
        $this->phone = '';
        $this->subject = '';
        $this->message = '';
    }

    public function render()
    {
        return view('livewire.contact-component');
    }
}

6. Crear y configurar Mailable

Para enviar el email con la información del formulario de contacto usarás un Mailable, para crearlo ejecuta la siguiente línea de comando:

php artisan make:mail ContactForm

Abre el archivo app/Mail/ContactForm.php, en este archivo las dos partes principales es el método construct() y el método build(). En el método construct() vas a pasar la variable con la información que quieres que se visualice en la vista del email; en el método build() se pueden pasar varios parámetros hacía la vista del email. Agrega el siguiente código al archivo:

<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class ContactForm extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct($data)
    {
        $this->data = $data;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->from('[email protected]', 'Sistema Automático de Notificaciones')->subject('Un usuario envió un mensaje desde el formulario de contacto')->view('email.contact-form', ['data' => $this->data]);
    }
}

7. Configurar vista del email

Para mostrar el email es necesario que diseñes una vista. Crea la carpeta resources/views/email dentro de ella crea el archivo contact-form.blade y agrega el siguiente código, como verás mostrará las variables que vienen del formulario de contacto:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Mensaje desde formulario de contacto</title>
</head>

<body>
    <div class="card">
        <div class="card-header">
            Has recibido un mensaje desde el formulario de contacto
        </div>
        <div class="card-body">
          <h3 class="card-title">Datos del mensaje</h3>
          <p class="card-text"><b>Name:</b> {{ $data['name'] }}</p>
          <p class="card-text"><b>Telephone:</b> {{ $data['phone'] }}</p>
          <p class="card-text"><b>Email:</b> {{ $data['email'] }}.</p>
          <p class="card-text"><b>Subject:</b> {{ $data['subject'] }}.</p>
          <p class="card-text"><b>Message:</b> {{ $data['message'] }}.</p>

        </div>
      </div>
</body>
</html>

8. Configurar archivo .env

Para mandar emails desde Laravel 9 es necesario que en tu archivo .env tengas configurando algún cliente SMTP, cuando estás en producción puedes usar tu cuenta de Gmail, Yahoo, Outlook o si tienes un nombre de dominio puedes crear una cuenta especial de email para ello, la configuración la agregas en el archivo .env. Pero en este caso estoy trabajando en localhost por lo que usará el servicio de mailtrap.io.

Desde tu navegador abre el sitio web de mailtrap.io sino tienes cuenta crea una e ingresa a ella.

Ingresa a tu cuenta Mailtrap

Ingresa al menú My Inbox y en Integration busca PHP y Laravel 7+:

Formulario de contacto Laravel 9 y Livewire

Los datos que te muestra cópialos y guárdalos porque en los vas a necesitar:

Copia los datos de la API de Mailtrap

Abre el archivo .env que está en la raíz de tu proyecto localiza la sección en donde se colocan las variable de entorno referentes al envío de SMTP y actualiza la información con las variables que copiaste anteriormente en Mailtrap:

Formulario de contacto Laravel 9 y Livewire

9. Probar formulario de contacto

Para probar el funcionamiento del formulario de contacto enciende el servidor integrado de Laravel ejecutando el comando:

php artisan serve

En el navegador web ve a la dirección http://127.0.0.1:8000/ llena la información que pide el formulario y envíalo, verás el mensaje que se ha enviado el mensaje y si revisas tu cuenta de Mailtrap tendrás en la bandeja de entrada un mensaje con los datos del formulario. ¡Está funcionando!

Formulario de contacto Laravel 9 y Livewire

Conclusión

En este tutorial aprendiste paso a paso a cómo crear un formulario de contacto en Laravel 9 y Livewire el cual que podrás implementar en futuros proyectos. Si este tutorial fue de ayuda te invito a compartirlo en tus redes sociales para llegar a más personas y si tienes dudas o comentario déjalos en la caja de comentarios, estaré al pendiente de ellos. Saludos!

Formulario de contacto plantilla.
Repositorio GitHub del tutorial.
Livewire documentación.

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.