Laravel Blueprint Macro

Laravel Blueprint Macro

DRY untuk kolom-kolom tabelmu!

Bismillahirrahmanirrahim

Apakah kamu pernah merancang desain struktur database dan menemukan bahwa ada beberapa kolom yang hampir selalu ada di setiap tabelnya? Lebih memukau lagi bahwa kamu selalu menulis ulang di setiap file migration-nya? Apakah ada cara agar kamu tidak menulis ulang kolom-kolom tersebut di hampir setiap file migration yang ada?


Studi Kasus

Misalnya saya selalu ingin memasukkan beberapa kolom ini:

  • created_by

  • updated_by

  • deleted_by

  • created_at

  • updated_at

  • deleted_at

Maka di setiap file migration harus selalu ada baris ini:

$table->string('created_by', 150)->nullable()->default('Sistem');
$table->string('updated_by', 150)->nullable()->default('Sistem');
$table->string('deleted_by', 150)->nullable();
$table->timestamps();
$table->softDeletes();

Sudah terbayang bagaimana repotnya untuk melakukan copy-paste setiap menambah file migration baru?


Solusi

Ada 2 cara yang saya tau untuk menangani masalah perulangan di atas, antara lain:

  1. Lewat file AppServiceProvider.php yang terdapat di folder app/Providers.

  2. Menggunakan Trait.

Keduanya tetap memanfaatkan fitur Macro pada Blueprint. Pada artikel ini saya mengesampingkan teori dan lebih mengedepankan prakteknya.

Mari kita mulai ngoding!

Lewat AppServiceProvider

Dalam function boot, tambahkan kode berikut:

// Blueprint Macro
Blueprint::macro('opsFields', function () {
    $this->string('created_by', 150)->nullable()->default('Sistem');
    $this->string('updated_by', 150)->nullable()->default('Sistem');
    $this->string('deleted_by', 150)->nullable();
    $this->timestamps();
    $this->softDeletes();
});

Maka jika kamu butuh kolom-kolom tersebut dalam file migration, maka cukup tambahkan saja $table->opsFields() di dalamnya. Contohnya jadi seperti ini:

Schema::create('categories', function (Blueprint $table) {
    $table->id();
    $table->string('code', 7)->unique();
    $table->string('name', 150);
    $table->opsFields();
});

Menggunakan Trait

Buat sebuah class baru dengan perintah php artisan make:trait OpsFields dan tuliskan isinya sebagai berikut:

public function opsFields(Blueprint $table): void
{
    $table->string('created_by', 150)->nullable()->default('Sistem');
    $table->string('updated_by', 150)->nullable()->default('Sistem');
    $table->string('deleted_by', 150)->nullable();
    $table->timestamps();
    $table->softDeletes();
}

File trait selengkapnya jadi seperti ini:

<?php

namespace App\Traits;

use Illuminate\Database\Schema\Blueprint;

trait OpsFields
{
    public function opsFields(Blueprint $table): void
    {
        $table->string('created_by', 150)->nullable()->default('Sistem');
        $table->string('updated_by', 150)->nullable()->default('Sistem');
        $table->string('deleted_by', 150)->nullable();
        $table->timestamps();
        $table->softDeletes();
    }
}

Maka jika kamu butuh kolom-kolom tersebut dalam file migration, maka cukup tambahkan saja $table->opsFields() di dalamnya. Contohnya jadi seperti ini:

Schema::create('categories', function (Blueprint $table) {
    $table->id();
    $table->string('code', 7)->unique();
    $table->string('name', 150);
    $this->opsFields($table);
});

Jangan lupa tambahkan namespace pada bagian atas file migration-nya:

use App\Traits\OpsFields;

Selengkapnya jadi seperti ini file migration-nya

<?php

use App\Traits\OpsFields;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    use OpsFields;
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('categories', function (Blueprint $table) {
            $table->id();
            $table->string('code', 7)->unique();
            $table->string('name', 150);
            $this->opsFields($table);
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('categories');
    }
};

Hasil

Jika kamu coba jalankan perintah di terminal sebagai berikut php artisan migrate --pretend, maka akan menghasilkan query sebagai berikut:

create table `categories` (
   `id` bigint unsigned not null auto_increment primary key, 
   `code` varchar(7) not null, 
   `name` varchar(150) not null, 
   `created_by` varchar(150) null default 'Sistem', 
   `updated_by` varchar(150) null default 'Sistem', 
   `deleted_by` varchar(150) null, 
   `created_at` timestamp null, 
   `updated_at` timestamp null, 
   `deleted_at` timestamp null
) default character set utf8mb4 collate 'utf8mb4_unicode_ci';

alter table `categories` add unique `categories_code_unique`(`code`);

Nah, silahkan kamu pilih mau pakai metode yang mana. Apakah lewat service provider atau trait. Pilihan saya? Trait. Mengapa?

Jika menggunakan Trait, maka ia akan hadir jika dipanggil saja. Adapun jika service provider, sejatinya ia akan selalu dipanggil di setiap request, tentang migration atau lainnya.