Para crear confianza en tu comunidad en línea o blog, un elemento crucial que querrás tener es un sistema de comentarios en tiempo real de Laravel bien diseñado.

Sin embargo, no es fácil hacerlo bien a la primera, a menos que confíes en sistemas de comentarios autoalojados como Disqus o Commento, cada uno de los cuales viene con su propio conjunto de desventajas. Son dueños de tus datos, ofrecen diseños y personalizaciones limitadas y, lo más importante, no son gratuitos.

Con estas limitaciones, si tienes la idea de construir tu sistema de comentarios en tiempo real – con las ventajas de controlar tus datos, diseñar y personalizar el aspecto para que encaje en tu blog – te atrae, sigue leyendo.

Este artículo te enseñará a desarrollar un sistema de comentarios en tiempo real bien diseñado y con diferentes funcionalidades de comentarios. Siguiendo los principios de la construcción de una aplicación de chat en tiempo real con Vue.js y Socket.io, utilizaremos Laravel, Pusher y React para desarrollar el sistema de comentarios en tiempo real.

Vamos a sumergirnos.

Qué vamos a construir

Construiremos un sistema de comentarios en tiempo real que pueda integrarse en cualquier sitio web o blog para generar confianza en la comunidad.

Visión general de los bloques de construcción: Laravel, Pusher y Vue

Antes de sumergirnos en el desarrollo, vamos a hablar de las tecnologías que utilizaremos para desarrollar nuestro sistema de comentarios en tiempo real.

Laravel

Laravel es un framework PHP orientado a MVC de código abierto. Se utiliza para construir aplicaciones web PHP simples a complejas conocidas por su elegante sintaxis. Aprender qué es Laravel es esencial para construir este sistema de comentarios.

Pusher

Pusher permite a los desarrolladores crear funciones en tiempo real a escala. Este artículo combinará Laravel Echo para crear un evento de difusión en tiempo real al servidor Pusher y mostrar el contenido en el frontend con Vue.js.

Vue.js

Vue.js es nuestro marco de trabajo de frontend de elección. Vue.js es un marco de trabajo progresivo de JavaScript conocido por su enfoque sencillo y fácil de aprender para el desarrollo de frontend. Utilizaremos Vue.js para desarrollar nuestro sistema de comentarios en tiempo real.

Construir el sistema de comentarios

Si el sistema de comentarios que hemos esbozado anteriormente se parece a lo que quieres, pasemos a construirlo.

1. Instalar y configurar Laravel, Pusher y Echo

La instalación y configuración de Laravel, Echo y Pusher es sencilla, ya que Laravel ha realizado todas las tareas de fondo configurando Laravel Echo para que funcione perfectamente con Pusher.

En primer lugar, vamos a empezar por instalar y configurar Laravel, nuestro framework PHP backend. Puedes obtener una nueva instancia de Laravel con este comando, siempre que hayas instalado la CLI de Laravel de forma global:

laravel new commenter

Tu nueva instancia de Laravel se instalará en una carpeta llamada commenter. Abremos la carpeta en nuestro VSCode y naveguemos hasta ella en nuestro terminal:

cd commenter

code .

Antes de iniciar nuestro servidor de desarrollo, vamos a instalar y configurar algunos paquetes necesarios que se utilizarán para el proyecto.

Ejecute este comando para instalar el SDK PHP de Pusher:

composer require pusher/pusher-php-server

Ejecuta este comando para instalar los paquetes NPM necesarios para el frontend de Vue.js:

npm install --save laravel-echo pusher-js

A continuación, configuraremos Laravel Echo y Pusher. Abre tu archivo resources/js/bootstrap.js y pega los siguientes scripts:

window._ = require("lodash");
window.axios = require("axios");
window.moment = require("moment");
window.axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
window.axios.defaults.headers.post["Content-Type"] =
    "application/x-www-form-urlencoded";
window.axios.defaults.headers.common.crossDomain = true;
window.axios.defaults.baseURL = "/api";
let token = document.head.querySelector('meta[name="csrf-token"]');
if (token) {
    window.axios.defaults.headers.common["X-CSRF-TOKEN"] = token.content;
} else {
    console.error("CSRF token not found");
}


/**
 * Echo exposes an expressive API for subscribing to channels and listening
 * for events that Laravel broadcasts. Echo and event broadcasting
 * allows your team to build robust real-time web applications quickly.
 */
import Echo from "laravel-echo";
window.Pusher = require("pusher-js");
window.Echo = new Echo({
    broadcaster: "pusher",
    key: process.env.MIX_PUSHER_APP_KEY,
    cluster: process.env.MIX_PUSHER_APP_CLUSTER,
    forceTLS: true
});

Notarás en el script anterior que solo estamos configurando la instancia de Axios con nuestras configuraciones por defecto. A continuación, configuraremos Laravel Echo para usar Pusher y sus configuraciones.

2. Configuración y migración de la base de datos

A continuación, vamos a crear y configurar nuestra base de datos para almacenar los comentarios para su conservación. Usaremos SQLite, aunque puedes usar cualquier cliente de base de datos de tu elección.

Crea un archivo database.sqlite dentro de la carpeta de la base de datos y actualiza tu archivo .env como sigue:

DB_CONNECTION=sqlite
DB_DATABASE=/Users/all/paths/to/project/commenter_be/database/database.sqlite
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=

A continuación, ejecute este comando para crear la migración de comentarios y actualizarla con los siguientes scripts:

php artisan make:migration create_comments_table

Abre el archivo database/migrations/xxxx_create_comments_table_xxxx.php y pega este código:

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateCommentsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('comments', function (Blueprint $table) {
            $table->id();
            $table->string('content');
            $table->string('author');
            $table->timestamps();
        });
    }
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('comments');
    }
}

Esto creará una nueva tabla de base de datos de comentarios y añadirá columnas de contenido y autor.

Por último, para crear la migración, ejecuta este comando:

php artisan migrate

3. Creación de modelos

En Laravel, los modelos son significativos – son la forma más segura de comunicarnos con nuestra base de datos y manejar la gestión de datos.

Para crear un modelo en Laravel, ejecutaremos el siguiente comando:

php artisan make:model Comment

A continuación, abre el archivo app/models/Comment.php y pega el siguiente código:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
    use HasFactory;
    protected $fillable = ['content', 'author'];
}

The $fillable array allows us to create and update the model in mass.

4. Creación de controladores

Los controladores son cruciales porque albergan toda la lógica, de negocio y demás, de nuestras aplicaciones, así que vamos a crear uno para manejar la lógica de los comentarios:

php artisan make:controller CommentController

A continuación, abre el archivo app/Http/Controllers/CommentController.php y pega el siguiente código:

<?php
namespace App\Http\Controllers;
use App\Models\Comment;
use App\Events\CommentEvent;
use Illuminate\Http\Request;

class CommentController extends Controller
{
    //
    public function index()
    {
        return view('comments');
    }
    public function fetchComments()
    {
        $comments = Comment::all();
        return response()->json($comments);
    }
    public function store(Request $request)
    {
        $comment = Comment::create($request->all());
        event(new CommentEvent($comment));
        return $comment;
    }
}

El controlador tiene tres métodos diferentes: devolver una vista de comentarios, obtener todos los comentarios y almacenar un nuevo comentario, respectivamente. Lo más importante es que disparamos un evento cada vez que almacenamos un nuevo comentario, que el frontend escuchará para actualizar la página correspondiente con el nuevo comentario en tiempo real utilizando Pusher y Laravel Echo.

5. Creación de rutas

Para configurar nuestras rutas correctamente, tendremos que actualizar muchos archivos, así que vamos a empezar.

En primer lugar, vamos a actualizar el archivo api.php en la carpeta de rutas. Abre el archivo y añade el siguiente código:

use App\Http\Controllers\CommentController;
//...

Route::get('/', [CommentController::class, 'index']);
Route::get('/comments', [CommentController::class, 'fetchComments']);
Route::post('/comments', [CommentController::class, 'store']);

A continuación, abre el archivo channels.php en la misma carpeta y añade el siguiente código para autorizar el evento que hemos disparado antes:

Broadcast::channel('comment', function ($user) {
    return true;
});

A continuación, abre el archivo web.php en la misma carpeta y añade el siguiente código para redirigir nuestra petición a la página de inicio, donde Vue.js la recogerá:

use App\Http\Controllers\CommentController;
//...

Route::get('/', [CommentController::class, 'index']);

Por último, crearemos un nuevo archivo blade en la carpeta resources/views llamado comments.blade.php y añadiremos el siguiente código:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>Commenter</title>
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css" />
    <style>
        .container {
            margin: 0 auto;
            position: relative;
            width: unset;
        }
        #app {
            width: 60%;
            margin: 4rem auto;
        }
        .question-wrapper {
            text-align: center;
        }
    </style>
</head>
<body>


    <div id="app">
        <div class="container">
            <div class="question-wrapper">
                <h5 class="is-size-2" style="color: #220052;">
                    What do you think about <span style="color: #47b784;">Dogs</span>?</h5>
                <br>
                <a href="#Form" class="button is-medium has-shadow has-text-white" style="background-color: #47b784">Comment</a>
            </div>
            <br><br>
            <comments></comments>
            <new-comment></new-comment>
        </div>
    </div>
    <script async src="{{mix('js/app.js')}}"></script>
</body>
</html>

El script añade un título de entrada y un componente Vue para mostrar y añadir nuevos comentarios al título de entrada creado anteriormente.

Ejecuta los siguientes comandos para comprobar si todo está bien:

npm run watch

php artisan serve

Si aparece esta página, estás listo para pasar al siguiente paso de este artículo.

Sistema de comentarios en vivo en Laravel
Sistema de comentarios en tiempo real de Laravel

6. Configuración de Vue (Frontend)

Crearemos y configuraremos nuestra instancia Vue para crear y mostrar todos los comentarios realizados en este post.

Comenzaremos con la configuración de nuestra tienda Vuex. Crea los siguientes archivos en la carpeta resource/js/store.

Crear estado de comentarios

Crea actions.js y añade el siguiente código:

let actions = {
    ADD_COMMENT({ commit }, comment) {
        return new Promise((resolve, reject) => {
            axios
                .post(`/comments`, comment)
                .then(response => {
                    resolve(response);
                })
                .catch(err => {
                    reject(err);
                });
        });
    },
    GET_COMMENTS({ commit }) {
        axios
            .get("/comments")
            .then(res => {
                {
                    commit("GET_COMMENTS", res.data);
                }
            })
            .catch(err => {
                console.log(err);
            });
    }
};
export default actions;

El archivo de acción hace una llamada al punto final de comentarios en el backend.

A continuación, crea un archivo getters.js y añade el siguiente código:

let getters = {
    comments: state => {
        return state.comments;
    }
};
export default getters;

El archivo Getter se utiliza para recuperar todos los comentarios del estado.

Crea el archivo mutations.js y pégalo en el siguiente código:

let mutations = {
    GET_COMMENTS(state, comments) {
        state.comments = comments;
    },
    ADD_COMMENT(state, comment) {
        state.comments = [...state.comments, comment];
    }
};
export default mutations;

A continuación, crea un archivo state.js y pégalo en el siguiente código:

let state = {
    comments: []
};
export default state;

Por último, añadiremos todo al archivo index.js exportado a la instancia de Vue, crearemos un archivo index.js y añadiremos lo siguiente:

import Vue from "vue";
import Vuex from "vuex";
import actions from "./actions";
import mutations from "./mutations";
import getters from "./getters";
import state from "./state";
Vue.use(Vuex);
export default new Vuex.Store({
    state,
    mutations,
    getters,
    actions
});

Crear componentes

Por último, vamos a crear nuestros componentes de comentarios para mostrar y añadir nuevos comentarios. Empecemos por crear el componente de comentario único.

Crea una carpeta en la carpeta resource/js llamada components, añade el comment.vue y añade el siguiente código:

<template>
  <li class="comment-wrapper animate slideInLeft">
    <div class="profile">
    </div>
    <div class="msg has-shadow">
      <div class="msg-body">
        <p class="name">
          {{ comment.author }} <span class="date">{{ posted_at }}</span>
        </p>
        <p class="content">{{ comment.content }}</p>
      </div>
    </div>
  </li>
</template>
    
    <script>
export default {
  name: "Comment",
  props: ["comment"],
  computed: {
    posted_at() {
      return moment(this.comment.created_at).format("MMMM Do YYYY");
    },

  },
};
</script>
    
    <style lang="scss" scoped>
.comment-wrapper {
  list-style: none;
  text-align: left;
  overflow: hidden;
  margin-bottom: 2em;
  padding: 0.4em;
  .profile {
    width: 80px;
    float: left;
  }
  .msg-body {
    padding: 0.8em;
    color: #666;
    line-height: 1.5;
  }
  .msg {
    width: 86%;
    float: left;
    background-color: #fff;
    border-radius: 0 5px 5px 5px;
    position: relative;
    &::after {
      content: " ";
      position: absolute;
      left: -13px;
      top: 0;
      border: 14px solid transparent;
      border-top-color: #fff;
    }
  }
  .date {
    float: right;
  }
  .name {
    margin: 0;
    color: #999;
    font-weight: 700;
    font-size: 0.8em;
  }
  p:last-child {
    margin-top: 0.6em;
    margin-bottom: 0;
  }
}
</style>

A continuación, crea el siguiente archivo llamado comments.vue en la misma carpeta y añade el siguiente código:

<template>
  <div class="container">
    <ul class="comment-list">
      <Comment
        :key="comment.id"
        v-for="comment in comments"
        :comment="comment"
      ></Comment>
    </ul>
  </div>
</template>
    
    <script>
import { mapGetters } from "vuex";
import Comment from "./Comment";
export default {
  name: "Comments",
  components: { Comment },
  mounted() {
    this.$store.dispatch("GET_COMMENTS");
    this.listen();
  },
  methods: {
    listen() {
      Echo.channel("comment").listen("comment", (e) => {
        console.log(e);
        this.$store.commit("ADD_COMMENT", e);
      });
    },
  },
  computed: {
    ...mapGetters(["comments"]),
  },
};
</script>
    
    <style scoped>
.comment-list {
  padding: 1em 0;
  margin-bottom: 15px;
}
</style>

Por último, crea un archivo llamado NewComment.vue y añade el siguiente código:

<template>
  <div id="commentForm" class="box has-shadow has-background-white">
    <form @keyup.enter="postComment">
      <div class="field has-margin-top">
        <div class="field has-margin-top">
          <label class="label">Your name</label>
          <div class="control">
            <input
              type="text"
              placeholder="Your name"
              class="input is-medium"
              v-model="comment.author"
            />
          </div>
        </div>
        <div class="field has-margin-top">
          <label class="label">Your comment</label>
          <div class="control">
            <textarea
              style="height: 100px"
              name="comment"
              class="input is-medium"
              autocomplete="true"
              v-model="comment.content"
              placeholder="lorem ipsum"
            ></textarea>
          </div>
        </div>
        <div class="control has-margin-top">
          <button
            style="background-color: #47b784"
            :class="{ 'is-loading': submit }"
            class="button has-shadow is-medium has-text-white"
            :disabled="!isValid"
            @click.prevent="postComment"
            type="submit"
          >
            Submit
          </button>
        </div>
      </div>
    </form>
    <br />
  </div>
</template>
    
    <script>
export default {
  name: "NewComment",
  data() {
    return {
      submit: false,
      comment: {
        content: "",
        author: "",
      },
    };
  },
  methods: {
    postComment() {
      this.submit = true;
      this.$store
        .dispatch("ADD_COMMENT", this.comment)
        .then((response) => {
          this.submit = false;
          if (response.data) console.log("success");
        })
        .catch((err) => {
          console.log(err);
          this.submit = false;
        });
    },
  },
  computed: {
    isValid() {
      return this.comment.content !== "" && this.comment.author !== "";
    },
  },
};
</script>
    
    <style scoped>
.has-margin-top {
  margin-top: 15px;
}
</style>

Ahora, abre el archivo app.js y añade el siguiente código para registrar los componentes Vue que creaste anteriormente:

// resource/js/app.js

require("./bootstrap");
window.Vue = require("vue");
import store from "./store/index";

Vue.component("comment", require("./components/Comment"));
Vue.component("comments", require("./components/Comments"));
Vue.component("new-comment", require("./components/NewComment"));

const app = new Vue({
    el: "#app",
    store
});

Resumen

Y ya está. Acabas de aprender cómo construir un sistema de comentarios en tiempo real para tu sitio usando Laravel.

Hemos hablado de las ventajas de crear y gestionar un sistema de comentarios en tu búsqueda de la confianza en tu comunidad o blog. También hemos explorado cómo desarrollar un sistema de comentarios bien diseñado y en tiempo real desde el principio, utilizando diferentes funcionalidades de comentarios.

Puedes clonar el código fuente de este proyecto en este repositorio de Github.

¿Qué te parece el sistema de comentarios en vivo de Laravel que hemos construido juntos? ¡Háznoslo saber en los comentarios!

 

Solomon Eseme

I am a Software Engineer and Content Creator who is geared toward building high-performing and innovative products following best practices and industry standards. I also love writing about it at Masteringbackend.com. Follow me on Twitter, LinkedIn, and About Me