Pendahuluan
Membangun sebuah aplikasi yang membutuhkan feedback dari penggunanya, seperti blog, e-commerce dan lain sebagainya membutuhkan sistem komentar untuk saling interaksi antara pemilik dan pengguna atau antara pengguna dengan pengguna lainnya. Artikel ini juga sebagai tanggapan atas permintaan dari pembaca Daengweb.id untuk menjelaskan bagaimana cara membuat sistem komentar dengan PHP atau Laravel 7.
Schema yang akan digunakan sebagai sampel adalah aplikasi blog dimana kita akan membuat data dummy postingan dan masing-masing postingan memiliki komentar dari pengguna. Setiap komentar bisa di-reply sebanyak mungkin tapi cakupannya hanya dalam 1 tingkatan.
Baca Juga: Cara Upload File ke Amazon S3 Menggunakan Laravel 7
Instalasi & Kerangka Aplikasi
Buka command line dan jalankan perintah berikut untuk meng-install Laravel 7
composer create-project --prefer-dist laravel/laravel komentar
Kemudian buat database, dan sesuaikan informasi database yang kamu miliki. Buka file .env
dan modifikasi code berikut
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel-comment
DB_USERNAME=root
DB_PASSWORD=
Hapus semua file migration bawaan Laravel, dan generate migration baru dengan command
php artisan make:model Post -m
Buka file migration yang baru saja di-generate dan modifikasi menjadi
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePostsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('slug')->unique();
$table->text('content');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('posts');
}
}
Eksekusi migration yang baru saja dibuat dengan command php artisan migrate
. Adapun fungsi yang akan meng-handle data dummy dari postingan adalah dengan memanfaatkan model factory. Dari command line, jalankan perintah
php artisan make:factory PostFactory
Buka file PostFactory.php
yang berada di dalam folder database/factories
dan modifikasi menjadi
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use App\Post;
use Faker\Generator as Faker;
use Illuminate\Support\Str;
$factory->define(Post::class, function (Faker $faker) {
$title = $faker->paragraph($nbSentences = 3, $variableNbSentences = true);
return [
'title' => $title,
'slug' => Str::slug($title),
'content' => $faker->text($maxNbChars = 200)
];
});
Tugas selanjutnya adalah membuat seeder menjalankan model factory diatas, buat seeder baru dengan command
php artisan make:seeder PostTableSeeder
Dari file PostTableSeeder.php
yang baru saja di-generate, modifikasi menjadi
<?php
use Illuminate\Database\Seeder;
class PostTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
factory(App\Post::class, 50)->create();
}
}
Sebelum meng-eksekusi seeder yang ada, buka file Post.php
dan tambahkan guarded di dalamnya.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $guarded = [];
}
Kemudian eksekusi seeder di atas dengan command php artisan db:seed --class=PostTableSeeder
. Secara otomatis, 50 data dummy sudah tersedia dan bisa digunakan sebagai list artikel yang nantinya akan dikaitkan dengan sistem komentar.
Membuat Fitur Komentar
Table selanjutnya yang akan dikerjakan adalah table comments
untuk menampung semua komentar pengguna. Karena kita tidak membuat fitur authentication, maka setiap kali pengguna akan melakukan komentar, maka wajib meng-input username-nya.
Generate sebuah migration baru dengan command
php artisan make:model Comment -m
Melirik ke folder database/migrations
, terdapat migration baru, buka file tersebut dan modifikasi menjadi
<?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->unsignedBigInteger('post_id');
$table->unsignedBigInteger('parent_id')->nullable();
$table->string('username');
$table->text('comment');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('comments');
}
}
Penjelasan: Perhatikan pada bagian parent_id
, dimana field ini akan berisi id dari table comments atau dengan kata lain, dia akan berelasi dengan dirinya sendiri. parent_id
hanya akan terisi, jika pengguna melakukan komentar pada komentar yang sudah ada.
Eksekusi migration di atas dengan command php artisan migrate
. Dari sisi database sudah tersedia, saatnya kita untuk menyediakan fiturnya secara sistem. Generate controller baru dengan command
php artisan make:controller PostController
Buka file PostController.php
dan tambahkan method berikut
public function index()
{
$posts = Post::orderBy('created_at', 'DESC')->paginate(10);
return view('welcome', compact('posts'));
}
Jangan lupa untuk menambahkan use statement di dalam file yang sama
use App\Post;
Kemudian buka file welcome.blade.php
untuk menampilkan seluruh postingan yang ada di database berdasarkan hasil query di atas dan modifikasi menjadi.
<!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>Komentar Sistem</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<div class="card mt-3">
<div class="card-body">
<div class="row">
@foreach ($posts as $row)
<div class="col-md-6 mb-4">
<div class="card">
<div class="card-body">
<h5><a href="{{ url('/' . $row->slug) }}" style="text-decoration: none">{{ \Str::limit($row->title, 100) }}</a></h5>
<p>{!! $row->content !!}</p>
</div>
</div>
</div>
@endforeach
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
Definisikan routing-nya dengan cara memodifikasi file routes/web.php
menjadi
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', 'PostController@index');
Ketika salah satu artikel diklik, maka akan mengarah ke halaman baru untuk menampilkan detail artikel. Tambahkan method berikut ke dalam file PostController.php
public function show($slug)
{
$post = Post::with(['comments', 'comments.child'])->where('slug', $slug)->first();
return view('show', compact('post'));
}
Sebelum membuat file baru, perhatikan pada eager loading with()
dimana kita me-load relationships ke comments dan child yang berada di model Comment. Buka file Post.php
dan tambahkan code berikut
public function comments()
{
return $this->hasMany(Comment::class)->whereNull('parent_id');
}
Penjelasan: Membuat relasi ke table comments
dengan kondisi hanya data yang parent_id
-nya sama dengan NULL.
Relasi selanjutnya adalah child yang akan berelasi dengan dirinya sendiri, buka file Comment.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
protected $guarded = [];
public function child()
{
return $this->hasMany(Comment::class, 'parent_id');
}
}
Penjelasan: child
berelasi dengan Comment atau dirinya sendiri dengan parent_id
sebagai foreign key-nya.
Saatnya untuk membuat file show.blade.php
untuk meng-handle tampilan komentar dan form komentar. Tambahkan code berikut
<!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>{{ \Str::limit($post->title, 50) }}</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<style>
blockquote {
background: #f9f9f9;
border-left: 10px solid #ccc;
margin: 1.5em 10px;
padding: 0.5em 10px;
quotes: "\201C""\201D""\2018""\2019";
}
blockquote:before {
color: #ccc;
content: open-quote;
font-size: 4em;
line-height: 0.1em;
margin-right: 0.25em;
vertical-align: -0.4em;
}
blockquote p {
display: inline;
font-style: italic;
}
blockquote h6 {
font-weight: 700;
padding: 0;
margin: 0 0 .25rem;
}
.child-comment {
padding-left: 50px;
}
</style>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<div class="card mt-3">
<div class="card-body">
<h3>{{ $post->title }}</h3>
<p>{{ $post->content }}</p>
<hr>
<h5>Komentar</h5>
<div class="row">
<div class="col-md-6">
<form action="{{ url('/comment') }}" method="post">
@csrf
<input type="hidden" name="id" value="{{ $post->id }}" class="form-control">
<input type="hidden" name="parent_id" id="parent_id" class="form-control">
<div class="form-group">
<label for="">Username</label>
<input type="text" class="form-control" name="username">
<p class="text-danger">{{ $errors->first('username') }}</p>
</div>
<div class="form-group" style="display: none" id="formReplyComment">
<label for="">Balas Komentar</label>
<input type="text" id="replyComment" class="form-control" readonly>
</div>
<div class="form-group">
<label for="">Komentar</label>
<textarea name="comment" cols="30" rows="10" class="form-control"></textarea>
</div>
<button class="btn btn-primary btn-sm">Kirim</button>
</form>
</div>
<div class="col-md-6">
@foreach ($post->comments as $row)
<blockquote>
<h6>{{ $row->username }}</h6>
<hr>
<p>{{ $row->comment }}</p><br>
<a href="javascript:void(0)" onclick="balasKomentar({{ $row->id }}, '{{ $row->comment }}')">Balas</a>
</blockquote>
@foreach ($row->child as $val)
<div class="child-comment">
<blockquote>
<h6>{{ $val->username }}</h6>
<hr>
<p>{{ $val->comment }}</p><br>
</blockquote>
</div>
@endforeach
@endforeach
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<script>
function balasKomentar(id, title) {
$('#formReplyComment').show();
$('#parent_id').val(id)
$('#replyComment').val(title)
}
</script>
</body>
</html>
Penjelasan: Kita memanfaatkan Javascript untuk mengisi input-an dengan name parent_id
, jadi setiap kali tombol balas ditekan, maka secara otomatis akan mengisi data parent_id.
Lalu kita buat fungsi untuk meng-handle data komentar untuk disimpan ke database, buka file PostController.php
dan tambahkan code
public function comment(Request $request)
{
//VALIDASI DATA YANG DITERIMA
$this->validate($request, [
'username' => 'required',
'comment' => 'required'
]);
Comment::create([
'post_id' => $request->id,
//JIKA PARENT ID TIDAK KOSONG, MAKA AKAN DISIMPAN IDNYA, SELAIN ITU NULL
'parent_id' => $request->parent_id != '' ? $request->parent_id:NULL,
'username' => $request->username,
'comment' => $request->comment
]);
return redirect()->back()->with(['success' => 'Komentar Ditambahkan']);
}
Pastikan untuk menambahkan use statement di dalam file yang sama
use App\Comment;
Bagian terakhir adalah mendefinisikan routing-nya, buka file routes/web.php
dan tambahkan code
Route::get('/{slug}', 'PostController@show');
Route::post('/comment', 'PostController@comment');
Baca Juga: Membuat Aplikasi Ekspedisi Lumen 6 #5: Manage Category
Kesimpulan
Membuat fitur sistem komentar menggunakan Laravel 7 atau PHP hanya memanfaatkan relasi data agar bisa menampilkan komentar yang saling terkait. Sehingga bagian yang perlu diperhatikan adalah struktur database agar kita bisa mengelola data komentar yang ada.
Dokumentasi code dari artikel ini bisa dilihat di Github.
Comments