Pendahuluan
Ada beragam kasus dimana sebuah aplikasi menggunakan lebih dari satu database secara bersamaan, misalnya saja pada aplikasi yang sedang saya kerjakan saat ini, dimana aplikasi yang baru (Aplikasi A) membutuhkan data dari aplikasi lama (Aplikasi B), akan tetapi pada aplikasi B tidak memungkinkan untuk membuat API karena satu dan lain hal.
Multiple database akan sangat membantu karena kita bisa mengambil data secara langsung dari database aplikasi B tanpa harus merepotkan pihak lain untuk menyediakan API service. Artikel kali ini akan membahas bagaimana berinteraksi dengan lebih dari satu database & contoh kasus yang lebih sederhana.
Case yang akan kita angkat adalah membuat CRUD untuk data produk menggunakan MySQL dan CRUD untuk data kategori menggunakan MongoDB.
Instalasi & Persiapan
Sebelum melanjutkan ke tahap persiapan, saya asumsikan teman-teman sudah meng-install web server, mysql dan mongodb, pastikan juga php module untuk mysql & mongodb sudah diaktifkan. Adapun materi tentang instalasinya akan dibahas pada artikel yang berbeda.
Laravel yang akan digunakan adalah Laravel 6, dari command line, jalankan perintah
composer create-project --prefer-dist laravel/laravel laravel-multidb "6.*"
Package yang akan digunakan untuk mengelola koneksi ke Mongo adalah Laravel-MongoDB, masuk ke dalam project dan install package berikut
cd laravel-multidb
composer require jenssegers/mongodb
Buka file config/database.php
dan tambahkan code berikut di dalam connections
//[.. CODE SEBELUMNYA ..]
'mongodb' => [
'driver' => 'mongodb',
'host' => env('MONGO_DB_HOST', 'localhost'),
'port' => env('MONGO_DB_PORT', 27017),
'database' => env('MONGO_DB_DATABASE'),
'username' => env('MONGO_DB_USERNAME'),
'password' => env('MONGO_DB_PASSWORD'),
'options' => []
],
Buka file .env
dan modifikasi konfigurasi mysql pada line berikut
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=multidb-mysql
DB_USERNAME=root
DB_PASSWORD=
Note: Pastikan kamu sudah membuat database bernama multidb-mysql
.
Masih dengan file yang sama, tambahkan konfigurasi untuk MongoDB
MONGO_DB_HOST=127.0.0.1
MONGO_DB_PORT=27017
MONGO_DB_DATABASE=laravel-multidb
MONGO_DB_USERNAME=
MONGO_DB_PASSWORD=
Note: Pastikan kamu sudah membuat database Mongo bernama laravel-multidb
.
Saatnya kita membuat migration untuk table products
yang akan di-handle oleh MySql, dari command line, jalankan
php artisan make:model Product -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 CreateProductsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('title');
$table->integer('price');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('products');
}
}
MongoDBnya bagaimana? Karena Mongo ini berorientasi dokumen, maka kita tidak membutuhkan table sebagaimana yang dilakukan sebelumnya. Eksekusi migration diatas dengan command
php artisan migrate
CRUD MySQL & MongoDB
Pengelolaan data dari kedua database ini akan kita kerjakan secara bersamaan, dimana frame browser akan dibagi menjadi dua bagian, yakni untuk menampilkan data products dan categories. Generate controller baru dengan command
php artisan make:controller ProductController
Buka file ProductController.php
dan tambahkan method berikut
public function index()
{
$product = Product::orderBy('created_at', 'DESC')->paginate(10); //GET DATA DARI TABLE PRODUCT
$category = Category::orderBy('created_at', 'DESC')->paginate(10); //GET DATA DARI COLLECTION MONGODB
return view('welcome', compact('product', 'category'));
}
Masih dengan file yang sama, tambahkan use statement
use App\Product;
use App\Category;
Lalu bagaimana cara kedua Eloquent diatas untuk membedakan tujuan database-nya? Secara default, Laravel akan menggunakan config default dari database.php
, dalam hal ini adalah mysql
. Sehingga tugas kita hanyalah mendefinisikan model untuk ke mongodb-nya. Generate model Category dengan command
php artisan make:model Category
Buka file app/Category.php
dan modifikasi menjadi
<?php
namespace App;
// use Illuminate\Database\Eloquent\Model;
use Jenssegers\Mongodb\Eloquent\Model as Eloquent;
class Category extends Eloquent
{
protected $connection = 'mongodb';
protected $guarded = [];
}
Penjelasan: mongodb
adalah nama connections yang ada di config/database.php
.
Kemudian kita akan mengelola tampilan dari data kedua database, buka file resources/views/welcome.blade.php
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>Laravel MultiDB</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">
<div class="row">
<div class="col-md-6 mt-3">
<div class="card">
<div class="card-header">
<h3 class="card-title">DB1: MySQL</h3>
</div>
<div class="card-body">
<form action="{{ url('/mysql') }}" method="post">
@csrf
<div class="form-group">
<label for="">Title</label>
<input type="text" name="title" class="form-control">
</div>
<div class="form-group">
<label for="">Price</label>
<input type="text" name="price" class="form-control">
</div>
<button class="btn btn-primary btn-sm">Simpan</button>
</form>
<table class="table table-hover table-bordered mt-3">
<thead>
<tr>
<th>No</th>
<th>Title</th>
<th>Price</th>
<th>Action</th>
</tr>
</thead>
<tbody>
@forelse ($product as $key => $row)
<tr>
<td>{{ $key+1 }}</td>
<td>{{ $row->title }}</td>
<td>{{ number_format($row->price) }}</td>
<td>
<form action="{{ url('/mysql/' . $row->id) }}" method="post">
@csrf
<input type="hidden" value="DELETE" name="_method">
<a href="{{ url('/edit/' . $row->id . '/mysql') }}" class="btn btn-warning btn-sm">Edit</a>
<button class="btn btn-danger btn-sm">Hapus</button>
</form>
</td>
</tr>
@empty
<tr>
<td colspan="4" class="text-center">Tidak ada data</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
<div class="col-md-6 mt-3">
<div class="card">
<div class="card-header">
<h3 class="card-title">DB2: MongoDB</h3>
</div>
<div class="card-body">
<form action="{{ url('/mongo') }}" method="post">
@csrf
<div class="form-group">
<label for="">Kategori</label>
<input type="text" name="name" class="form-control">
</div>
<button class="btn btn-primary btn-sm">Simpan</button>
</form>
<table class="table table-hover table-bordered mt-3">
<thead>
<tr>
<th>No</th>
<th>Category</th>
<th>Action</th>
</tr>
</thead>
<tbody>
@forelse ($category as $key => $row)
<tr>
<td>{{ $key+1 }}</td>
<td>{{ $row->name }}</td>
<td>
<form action="{{ url('mongo/' . $row->id) }}" method="post">
@csrf
<input type="hidden" value="DELETE" name="_method">
<a href="{{ url('/edit/' . $row->id . '/mongo') }}" class="btn btn-warning btn-sm">Edit</a>
<button class="btn btn-danger btn-sm">Hapus</button>
</form>
</td>
</tr>
@empty
<tr>
<td colspan="3" class="text-center">Tidak ada data</td>
</tr>
@endforelse
</tbody>
</table>
</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>
</body>
</html>
Penjelasan: Perhatikan form untuk kedua input-an di atas, route untuk input-an data mysql ke /mysql
dan untuk input-an ke mongo ke /mongo
, dimana keduanya menggunakan method POST.
Untuk meng-handle masing-masing input-an di atas, buka file ProductController.php
dan tambahkan kedua method berikut
public function insertToMySQL(Request $request)
{
$this->validate($request, [
'title' => 'required|string',
'price' => 'required|integer'
]);
Product::create([
'title' => $request->title,
'price' => $request->price
]);
return redirect()->back();
}
public function insertToMongo(Request $request)
{
$this->validate($request, [
'name' => 'required|string'
]);
Category::create(['name' => $request->name]);
return redirect()->back();
}
Definisikan route untuk ketiga method yang sudah kita buat, buka file routes/web.php
dan tambahkan code
Route::get('/', 'ProductController@index');
Route::post('/mysql', 'ProductController@insertToMySQL');
Route::post('/mongo', 'ProductController@insertToMongo');
Untuk mengizinkan mass assignment ke products
, buka file Product.php
dan modifikasi menjadi
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $guarded = [];
}
Dua langkah terakhir adalah membuat fitur hapus dan update data. Buka kembali file ProductController.php
dan tambahkan method
public function deleteMySQL($id)
{
$product = Product::find($id);
$product->delete();
return redirect()->back();
}
public function deleteMongo($id)
{
$category = Category::find($id);
$category->delete();
return redirect()->back();
}
Kemudian definisikan routing untuk menghapus data, buka file routes/web.php
dan tambahkan code
Route::delete('/mongo/{id}', 'ProductController@deleteMongo');
Route::delete('/mysql/{id}', 'ProductController@deleteMySQL');
Adapun form untuk edit akan kita satukan & hanya dibedakan oleh type, buka file ProductController.php
dan tambahkan method
public function formEdit($id, $type)
{
if ($type == 'mysql') {
$product = Product::find($id);
return view('edit', compact('product', 'type'));
}
$category = Category::find($id);
return view('edit', compact('category', 'type'));
}
public function update(Request $request, $id, $type)
{
if ($type == 'mysql') {
$product = Product::find($id);
$product->update([
'title' => $request->title,
'price' => $request->price
]);
return redirect('/');
}
$category = Category::find($id);
$category->update(['name' => $request->name]);
return redirect('/');
}
Handle form edit-nya dengan membuat file edit.blade.php
di dalam folder resources/views
dan 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>Laravel MultiDB</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">
<div class="row">
@if ($type == 'mysql')
<div class="col-md-6 mt-3">
<div class="card">
<div class="card-header">
<h3 class="card-title">DB1: MySQL</h3>
</div>
<div class="card-body">
<form action="{{ url('/edit/' . $product->id . '/mysql') }}" method="post">
@csrf
<input type="hidden" name="_method" value="PUT">
<div class="form-group">
<label for="">Title</label>
<input type="text" name="title" class="form-control" value="{{ $product->title }}">
</div>
<div class="form-group">
<label for="">Price</label>
<input type="text" name="price" class="form-control" value="{{ $product->price }}">
</div>
<button class="btn btn-primary btn-sm">Simpan</button>
<a href="{{ url('/') }}" class="btn btn-secondary btn-sm">Kembali</a>
</form>
</div>
</div>
</div>
@else
<div class="col-md-6 mt-3">
<div class="card">
<div class="card-header">
<h3 class="card-title">DB2: MongoDB</h3>
</div>
<div class="card-body">
<form action="{{ url('/edit/' . $category->id . '/mongo') }}" method="post">
@csrf
<input type="hidden" name="_method" value="PUT">
<div class="form-group">
<label for="">Kategori</label>
<input type="text" name="name" class="form-control" value="{{ $category->name }}">
</div>
<button class="btn btn-primary btn-sm">Simpan</button>
<a href="{{ url('/') }}" class="btn btn-secondary btn-sm">Kembali</a>
</form>
</div>
</div>
</div>
@endif
</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>
</body>
</html>
Langkah terakhir adalah mendefinisikan route untuk form edit dan update data, buka file routes/web.php
Route::get('/edit/{id}/{type}', 'ProductController@formEdit');
Route::put('/edit/{id}/{type}', 'ProductController@update');
Kesimpulan
Berinteraksi dengan multiple database di Laravel sangatlah mudah karena didukung oleh fitur yang sudah disediakan oleh Laravel, sehingga kita hanya perlu melakukan konfigurasi untuk koneksi database, dan selanjutnya sudah di-handle oleh Eloquent layaknya ketika kita menggunakan single database.
Adapun dokumentasi code dari artikel ini bisa dilihat di Github.
Comments