Laravel Multiple Database MySql & MongoDB

Laravel Multiple Database MySql & MongoDB

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.

laravel multiple database

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.

Category:
Share:

Comments