Para construir confiança na sua comunidade on-line ou blog, um elemento crucial que você vai querer é um sistema de comentários em tempo real bem desenhado no Laravel.

No entanto, não é fácil acertar na primeira tentativa, a menos que você confie em sistemas de comentários auto-hospedados, como Disqus ou Commento, cada um deles com seu próprio conjunto de desvantagens. Eles possuem seus dados, oferecem desenhos e customizações limitadas e, o mais importante, não são gratuitos.

Com estas limitações, se a idéia de construir seu sistema de comentários em tempo real – com os benefícios de controlar seus dados, projetar e personalizar o visual para caber em seu blog – lhe atrai, continue lendo.

Este artigo irá ensiná-lo a desenvolver um sistema de comentários bem concebido e em tempo real com diferentes funcionalidades de comentário. Seguindo os princípios de construir um aplicativo de chat em tempo real com Vue.js e Socket.io, vamos usar Laravel, Pusher e React para desenvolver o sistema de comentários em tempo real.

Vamos nessa!

O que vamos construir

Construiremos um sistema de comentários em tempo real que pode ser integrado em qualquer site ou blog para criar credibilidade na comunidade.

Visão geral dos blocos de construção: Laravel, Pusher, e Vue

Antes de mergulharmos no desenvolvimento, vamos discutir as tecnologias que vamos usar para desenvolver o nosso sistema de comentários em tempo real.

Laravel

Laravel é uma framework PHP de código aberto orientada para MVC. É usado para construir aplicativos web PHP simples ou complexas, conhecidas pela sua elegante sintaxe. Conhecer Laravel é importante para desenvolver este sistema de comentários.

Pusher

O Pusher permite aos desenvolvedores criar recursos em tempo real em escala. Este artigo irá combinar o Laravel Echo para criar um evento de transmissão em tempo real para o servidor Pusher e exibir o conteúdo no front-end com o Vue.js.

Vue.js

O Vue.js é a nossa framework front-end base. O Vue.js é uma framework front-end de JavaScript progressiva conhecida por sua abordagem fácil de aprender e direta para o desenvolvimento de front-end. Vamos utilizar o Vue.js para desenvolver o nosso sistema de comentários em tempo real.

Construindo o sistema de comentários

Se o sistema de comentários que delineamos acima soa como o que você quer, vamos prosseguir com a construção do sistema.

1. Instalanção e configuração do Laravel, Pusher e Echo

A instalação e configuração de Laravel, Echo e Pusher é simples, pois Laravel fez todas as tarefas de fundo ao configurar o Laravel Echo para trabalhar perfeitamente com Pusher.

Em primeiro lugar, vamos começar por instalar e configurar o Laravel, a nossa framework back-end PHP. Você pode pegar uma nova instância de Laravel com este comando, desde que você tenha instalado o Laravel CLI globalmente:

laravel new commenter

Sua nova instância Laravel será instalada em uma pasta chamada commenter. Vamos abrir a pasta no nosso VSCode e navegar até ela no nosso terminal:

cd commenter

code .

Antes de iniciarmos nosso servidor de desenvolvimento, vamos instalar e configurar alguns pacotes necessários que serão utilizados para o projeto.

Execute este comando para instalar o Pusher PHP SDK:

composer require pusher/pusher-php-server

Execute este comando para instalar os pacotes NPM necessários para o front-end do Vue.js:

npm install --save laravel-echo pusher-js

A seguir, vamos configurar o Laravel Echo e o Pusher. Abra seu arquivo resources/js/bootstrap.js e cole nos seguintes 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
});

Você vai notar pelo script acima que estamos apenas configurando a instância Axios com nossas configurações padrão. A seguir, vamos configurar o Laravel Echo para usar o Pusher e suas configurações.

2. Configuração e migração da base de dados

A seguir, vamos criar e configurar a nossa base de dados para armazenar os comentários para a persistência. Vamos usar o SQLite, embora você possa usar qualquer cliente de banco de dados de sua escolha.

Crie um arquivo database.sqlite dentro da pasta da base de dados e atualize o seu arquivo .env da seguinte forma:

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 seguir, execute este comando para criar a migração de Comentários e atualize-a com os seguintes scripts:

php artisan make:migration create_comments_table

Abra o arquivo database/migrations/xxxx_create_comments_table_xxxx.php e cole neste 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');
    }
}

Isto irá criar uma nova tabela de banco de dados de comentários e adicionar colunas de conteúdo e autor.

Finalmente, para criar a migração, execute este comando:

php artisan migrate

3. Criação de modelos

Em Laravel, os modelos são significativos – são a forma mais segura de comunicar com a nossa base de dados e lidar com a gestão de dados.

Para criar um modelo no Laravel, vamos executar o seguinte comando:

php artisan make:model Comment

Em seguida, abra o arquivo app/models/Comment.php e cole o seguinte 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. Criando controladores

Os controladores (Controllers) são cruciais porque abrigam toda a lógica, negócios e outros aspectos dos nossos aplicativos, então vamos criar um para lidar com a lógica dos comentários:

php artisan make:controller CommentController

Em seguida, abra o arquivo app/Http/Controllers/CommentController.php e cole o seguinte 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;
    }
}

O controlador tem três métodos diferentes: devolver uma vista de comentários, ir buscar todos os comentários e armazenar um novo comentário, respectivamente. Mais importante ainda, nós acendemos um evento cada vez que armazenamos um novo comentário, que o front-end irá ouvir para atualizar a página relevante com o novo comentário em tempo real, usando Pusher e Laravel Echo.

5. Criando rotas

Para configurar nossas rotas corretamente, vamos precisar atualizar muitos arquivos, então vamos começar.

Primeiro, vamos atualizar o arquivo api.php na pasta routes. Abra o arquivo e adicione o seguinte código:

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

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

Em seguida, abra o arquivo channels.php na mesma pasta e adicione o seguinte código para autorizar o evento que disparamos anteriormente:

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

Em seguida, abra o arquivo web.php na mesma pasta e adicione o seguinte código para redirecionar nosso pedido para a página inicial, onde o Vue.js irá pegá-lo:

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

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

Finalmente, vamos criar um novo arquivo blade na pasta resources/views chamado comments.blade.php e adicionar o seguinte 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>

O script adiciona um título de postagem e um componente Vue para exibir e adicionar novos comentários ao título de postagem criado acima.

Execute os seguintes comandos para testar se você obtém tudo corretamente:

npm run watch

php artisan serve

Se lhe for apresentada esta página, você está pronto para passar ao próximo passo neste artigo.

Sistema de comentários ao vivo em Laravel
Sistema de comentários em tempo real no Laravel

6. Configuração do Vue (Front-end)

Vamos criar e configurar a nossa instância Vue para criar e exibir todos os comentários feitos neste artigo.

Vamos começar com a montagem da nossa loja Vuex. Crie os seguintes arquivos na pasta resource/js/store.

Criando estado de comentário

Crie actions.js e adicione o seguinte 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;

O arquivo Action faz uma chamada para o ponto final do comentário no back-end.

Em seguida, crie um arquivo getters.js e adicione o seguinte código:

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

O arquivo Getter é usado para recuperar todos os comentários no estado.

Crie o arquivo mutations.js e cole o seguinte código:

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

Em seguida, crie um arquivo state.js e cole o seguinte código:

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

Finalmente, vamos adicionar tudo ao arquivo index.js exportado para a instância Vue, crie um arquivo index.js e adicione o seguinte:

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
});

Criando componentes

Finalmente, vamos criar os nossos componentes de comentário para exibir e adicionar novos comentários. Vamos começar por criar o componente de comentário único.

Crie uma pasta resource/js na pasta chamada components, adicione o comment.vue e adicione o seguinte 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>

Em seguida, crie o seguinte arquivo chamado comments.vue na mesma pasta e adicione o seguinte 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>

Finalmente, crie um arquivo chamado NewComment.vue e adicione o seguinte 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>

Agora, abra o arquivo app.js e adicione o seguinte código para registrar os componentes Vue que você criou 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
});

Resumo

E é isso! Você acabou de aprender como construir um sistema de comentários em tempo real para o seu site usando Laravel.

Discutimos os benefícios de criar e gerenciar um sistema de comentários em sua busca para construir confiança em sua comunidade ou blog. Também exploramos como desenvolver um sistema de comentários bem desenhado e em tempo real desde o início, utilizando diferentes funcionalidades de comentários.

Você pode clonar o código fonte deste projeto nesta Github repo.

O que você acha do sistema de comentários em tempo real no Laravel que construímos juntos? Informe-nos nos comentários!

 

Solomon Eseme

Sou um Engenheiro de Software e Criador de Conteúdo voltado para a construção de produtos de alta performance e inovadores, seguindo as melhores práticas e padrões da indústria. Também adoro escrever sobre isso no Masteringbackend.com. Siga-me no X, LinkedIn e About Me.