Laravel: Envío de mails con Formulario (parte 21)

Archivos:

  • resources/views/layouts/header.blade.php

Agregaremos al menú de navegación un link «contáctanos». Al pulsarlo, nos redirigirá a una vista que mostrará un formulario donde poner el nombre, el mail y un mensaje. Esa información nos será enviada en un correo electrónico.

Enlace en el menú

Abrimos la platilla de headers dentro de la carpeta partials, para añadir un link «contactanos» en nuestro menú de navegación.

            <ul>
                <li><a href="{{route('home')}}" class="{{request()->routeIs('home') ? 'active' : '' }}">Home</a>
                    {{-- @dump(request()->routeIs('home')) --}}
                </li>
                <li><a href="{{route('cursos.index')}}" class="{{request()->routeIs('cursos.*') ? 'active' : '' }}">Cursos</a>
                    {{-- @dump(request()->routeIs('cursos.index')) --}}
                </li>
                <li><a href="{{route('nosotros')}}" class="{{request()->routeIs('nosotros') ? 'active' : '' }}">Nosotros</a>
                    {{-- @dump(request()->routeIs('nosotros')) --}}
                </li>
                <li><a href="">Contactanos</a>
                </li>
</ul>

Ruta para almacenar mail

Abrimos web.php. Le damos a la ruta get que hemos creado para enviar mails el nombre «contactanos.index».

Route::get('contactanos', function() {
    $correo = new ContactanosMailable;
    Mail::to('weblikonet@gmail.com')->send($correo);
    return "mensaje enviado";
})->name('contactanos.index');

Ruta para mostrar el formulario

Hacemos que el nuevo enlace de contacto apunte a esa ruta.


<li><a href="{{route('contactanos.index')}}">Contactanos</a></li>

Controlador para la ruta y métodos

Creamos un controlador para que administre la ruta.

php make:controller ContactanosController 

Creamos dos métodos para este controlador: index() para mostrar el formulario y store() para procesarlo y enviar el mail.

class ContactanosController extends Controller
{
    //
    public function index(){
        
    }

    public function store(){
    
    }

}

Modificamos el controlador

Habíamos escrito esta función en la ruta:

        $correo = new ContactanosMailable;
        Mail::to('weblikonet@gmail.com')->send($correo);
        return "mensaje enviado";    

Lo ponemos esta vez dentro del método store().

class ContactanosController extends Controller
{
    //
    public function index(){
        
    }

    public function store(){
        $correo = new ContactanosMailable;
        Mail::to('weblikonet@gmail.com')->send($correo);
        return "mensaje enviado";    
    }

}

Como estamos creando aquí el objeto y haciendo uso de la clase, debemos importar las clases en el controlador:

use App\Mail\ContactanosMailable;
use Illuminate\Support\Facades\Mail;

Modificamos la ruta para el controlador

Modificamos la ruta para que llame al método index() del controlador ContactanosController:

Route::get('contactanos', [ContactanosController::class, 'index'])->name('contactanos.index');

Vista para el formulario

Hacemos que el método index() del controlador devuelva una vista llamada «contactanos.index»:

    public function index(){
        return view('contactanos.index');
    }

Creamos una carpeta dentro de views llamada «contactanos» y, dentro, la vista index.blade.php. Su contenido puede estar copiado de la vista home, y modificamos a nuestro antojo el title y el h1:

@extends('layouts.plantilla')

@section('title', 'Contactanos')

@section('content')
    <h1>Déjanos un mensaje</h1>
@endsection

Añadimos la clase para que el enlace quede activo cuando se visite:

<a href="{{route('contactanos.index')}}" class="{{request()->routeIs('contactanos.index') ? 'active' : '' }}">Contactanos</a>

Formulario de contacto

Creamos el formulario dentro de la vista:

<form action="">
    <label>
        Nombre:
        <br>
        <input type="text" name="name">
    </label>
    <br>


    <label>
        Correo:
        <br>
        <input type="mail" name="email">
    </label>
    <br>

    <label>
        Mensaje:
        <br>
        <textarea name="mensaje" rows="4"></textarea>    
        </label>
    <br>

    <button type="submit">Enviar mensaje</button>

</form>

Ruta post para el formulario

Creamos una ruta que procese la información del formulario. Va a ser de tipo post y llevará la url «contactanos». Le asignamos el método store() del controlador ContactanosController. Le damos el nombre «contactanos.store»:

Route::post('contactanos',[ContactanosController::class, 'store'])->name('contactanos.store');

Ponemos esta ruta en el action del formulario. Tenemos que especificar también el método del formulario, y el token csrf:

(...)
<form action="{{route('contactanos.store')}}" method="post">
    @csrf
(...)

Ejercicio

Hagamos este pequeño ejercicio antes de continuar. Si añadimos una propiedad a la clase del mailable que hemos creado para enviar el correo, como esta:

(...)
class ContactanosMailable extends Mailable
{
    use Queueable, SerializesModels;

    public $subject="Asunto del mail de contacto";

    public $propiedad="Esta es una propiedad del mailable"; 
(...)

Podemos rescatar esta propiedad dentro de la vista del mail de la siguiente forma:

<!DOCTYPE html>
(...)
<body>
    <h1>Correo Electrónico</h1>
    <p>Primer mail que mando por Laravel</p>
    {{$propiedad}}
</body>
</html>

Y comprobar que se envía correctamente

Recuperar la información del formulario

Al método store del controlador le pasamos el objeto request.

    public function store(Request $request){
        $correo = new ContactanosMailable;
        Mail::to('weblikonet@gmail.com')->send($correo);
        return "mensaje enviado";    
    }

Donde estoy creando la instancia de la clase ContactanosMailable le pasamos la información de request al constructor:

    public function store(Request $request){
        $correo = new ContactanosMailable($request->all());
        Mail::to('weblikonet@gmail.com')->send($correo);
        return "mensaje enviado";    
    }

Y recibimos la información en el constructor de la clase de la siguiente forma:

public $contacto;

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

Ahora podemos modificar la vista para imprimir la información así:

(...)
<body>
    <h1>Correo Electrónico</h1>
    <p>Primer mail que mando por Laravel</p>
    {{$propiedad}}

    <p><strong>Nombre:</strong> {{$contacto['nombre']}}</p>
    <p><strong>Nombre:</strong> {{$contacto['email']}}</p>
    <p><strong>Nombre:</strong> {{$contacto['mensaje']}}</p>
</body>
</html>

Validación

Completamos el método store() para validar el formulario. Todos los campos serán requeridos y el email debe ser un email:

 public function store(Request $request){

        $request->validate([
            'name'=>'required',
            'name'=>'required|email',
            'mensaje'=>'required',
        ]);

        $correo = new ContactanosMailable($request->all());
        Mail::to('weblikonet@gmail.com')->send($correo);
        return "mensaje enviado";    
    }

En el formulario ponemos los mensajes de error en cada campo. Abrimos la directiva error con el parámetro el nombre del campo que queramos validar, y en la directiva un párrafo con el posible error almacenado en la variable $message. Lo hacemos en cada campo:

 <form action="{{route('contactanos.store')}}" method="POST">
    @csrf
    <label>
        Nombre:
        <br>
        <input type="text" name="name">
    </label>
    <br>

    @error('name')
        <p><strong>{{$message}}</strong></p>
    @enderror

    <label>
        Correo:
        <br>
        <input type="mail" name="email">
    </label>
    <br>


    @error('email')
        <p><strong>{{$message}}</strong></p>
    @enderror

    <label>
        Mensaje:
        <br>
        <textarea name="mensaje" rows="4"></textarea>    
        </label>
    <br>
    
    @error('mensaje')
        <p><strong>{{$message}}</strong></p>
    @enderror

    <button type="submit">Enviar mensaje</button>
</form>

Redirección

Con esta redirección no mostraremos el mensaje «mensaje enviado», sino que volveremos a la vista en la que estábamos mostrando un mensaje. Le mandamos a la ruta un mensaje de sesión con el método with con dos parámetros, el nombre de la variable y su contenido.

    public function store(Request $request){

        $request->validate([
            'name'=>'required',
            'email'=>'required|email',
            'mensaje'=>'required',
        ]);

        $correo = new ContactanosMailable($request->all());
        Mail::to('weblikonet@gmail.com')->send($correo);

        return redirect()->route('contactanos.index')->with('info','mensaje enviado');    
    }

Usamos un condicional en la vista para ver si mostramos o no la variable de sesión en una alerta, en la vista del formulario.

(...)
    <button type="submit">Enviar mensaje</button>

</form>

@if (session('info'))
    <script>
        alert("{{session('info')}}")
    </script>
@endif
(...)

Recursos:

Enlace de Youtube: https://www.youtube.com/watch?v=Ei3RVhdcE0A&list=PLZ2ovOgdI-kWWS9aq8mfUDkJRfYib-SvF&index=29