MAXBY SSD 512GB/1TB M.2 NVMe PCIe Gen4x4 SSD NVMe Gen3/1TB PCIe 4.0 Garansi Resmi 5 Tahun Original

Laravel Artisan Command: Cara Membuat Custom Command untuk Task Otomatis

Apa Itu Laravel Artisan Command?

Laravel Artisan Command adalah perintah CLI yang disediakan Laravel untuk menjalankan berbagai pekerjaan dari terminal.

Selain command bawaan seperti:

php artisan migrate

atau:

php artisan cache:clear

Laravel juga memungkinkan kita membuat Custom Artisan Command sendiri.

Contohnya:

php artisan cleanup:temporary-data

atau:

php artisan report:daily

Command custom dapat digunakan untuk:

  • Membersihkan data lama
  • Import data
  • Export data
  • Sinkronisasi API
  • Generate laporan
  • Memproses database
  • Maintenance aplikasi
  • Menjalankan task otomatis
  • Menjadi bagian dari Laravel Scheduler

Konsep sederhananya:

Terminal / Cron / Scheduler
          ↓
    Artisan Command
          ↓
     Application
          ↓
 Database / API / File

Kenapa Membuat Custom Artisan Command?

Tanpa Artisan Command, developer mungkin menjalankan script PHP secara terpisah:

php script-cleanup.php

Masalahnya, script tersebut berada di luar struktur Laravel dan harus mengatur sendiri:

  • Database connection
  • Configuration
  • Environment
  • Dependency
  • Logging
  • Service aplikasi

Dengan Artisan Command, kita dapat menggunakan ekosistem Laravel secara langsung.

Misalnya:

DB::table('users')->count();

atau:

Log::info('Cleanup selesai');

atau:

User::where(...)->get();

Semua dapat digunakan di dalam Command.

Membuat Artisan Command

Gunakan:

php artisan make:command CleanupTemporaryData

Laravel akan membuat file Command.

Pada struktur Laravel yang umum, file tersebut berada di:

app/Console/Commands/CleanupTemporaryData.php

Command kemudian dapat dipanggil dengan:

php artisan cleanup:temporary-data

Struktur Custom Command

Contoh sederhana:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class CleanupTemporaryData extends Command
{
    protected $signature = 'cleanup:temporary-data';

    protected $description = 'Membersihkan data sementara';

    public function handle()
    {
        $this->info('Cleanup selesai.');

        return self::SUCCESS;
    }
}

Ada beberapa bagian penting:

$signature
$description
handle()

Apa Itu $signature?

Property:

protected $signature = 'cleanup:temporary-data';

menentukan nama command.

Jadi command tersebut dipanggil dengan:

php artisan cleanup:temporary-data

Format yang umum digunakan adalah:

kategori:aksi

Contohnya:

user:cleanup
report:generate
order:sync
invoice:send
product:import

Gunakan nama yang jelas agar mudah dipahami ketika command semakin banyak.

Apa Itu $description?

Property:

protected $description = 'Membersihkan data sementara';

digunakan untuk menjelaskan fungsi command.

Jika menjalankan:

php artisan list

description tersebut akan membantu developer mengetahui fungsi command.

Apa Fungsi handle()?

Method:

public function handle()
{
    //
}

merupakan tempat utama logic command dijalankan.

Contoh:

public function handle()
{
    $this->info('Memulai cleanup...');

    // proses cleanup

    $this->info('Cleanup selesai.');

    return self::SUCCESS;
}

Ketika command dijalankan:

php artisan cleanup:temporary-data

Laravel akan mengeksekusi:

handle()

Menampilkan Informasi di Terminal

Artisan menyediakan beberapa helper untuk memberikan output.

Contoh:

$this->info('Proses berhasil.');

Output:

INFO  Proses berhasil.

Untuk pesan error:

$this->error('Proses gagal.');

Untuk warning:

$this->warn('Data tidak ditemukan.');

Untuk pesan biasa:

$this->line('Memproses data...');

Output terminal menjadi lebih informatif.

Contoh Command dengan Database

Misalnya kita ingin membuat Command untuk menghitung jumlah user.

<?php

namespace App\Console\Commands;

use App\Models\User;
use Illuminate\Console\Command;

class CountUsers extends Command
{
    protected $signature = 'user:count';

    protected $description = 'Menampilkan jumlah user';

    public function handle()
    {
        $total = User::count();

        $this->info("Total user: {$total}");

        return self::SUCCESS;
    }
}

Jalankan:

php artisan user:count

Misalnya hasilnya:

Total user: 1250

Menggunakan Query Builder

Tidak harus menggunakan Eloquent.

Kita juga dapat menggunakan Query Builder:

use Illuminate\Support\Facades\DB;

$total = DB::table('users')->count();

$this->info("Total user: {$total}");

Artisan Command memiliki akses ke database Laravel seperti bagian aplikasi lainnya.

Membuat Command untuk Cleanup Data

Misalnya terdapat tabel:

temporary_data

dan kita ingin menghapus data yang lebih lama dari 7 hari.

use App\Models\TemporaryData;

public function handle()
{
    $deleted = TemporaryData::where(
        'created_at',
        '<',
        now()->subDays(7)
    )->delete();

    $this->info("{$deleted} data berhasil dihapus.");

    return self::SUCCESS;
}

Jalankan:

php artisan cleanup:temporary-data

Output:

125 data berhasil dihapus.

Command seperti ini sangat cocok dikombinasikan dengan Scheduler.

Menghubungkan Artisan Command dengan Scheduler

Setelah Command dapat dijalankan:

php artisan cleanup:temporary-data

kita dapat menjadwalkannya.

Contoh:

use Illuminate\Support\Facades\Schedule;

Schedule::command('cleanup:temporary-data')
    ->dailyAt('02:00');

Alurnya:

Cron
 ↓
Laravel Scheduler
 ↓
cleanup:temporary-data
 ↓
Database Cleanup

Dengan begitu cleanup dapat berjalan otomatis setiap hari.

Artisan Command Bisa Dijalankan Manual dan Otomatis

Ini salah satu keuntungan utama.

Command:

php artisan cleanup:temporary-data

dapat dijalankan manual ketika diperlukan.

Tetapi juga dapat dijalankan otomatis:

Scheduler
 ↓
cleanup:temporary-data

Jadi satu logic dapat digunakan untuk dua kebutuhan.

Menggunakan Argument

Terkadang Command membutuhkan input dari user.

Misalnya:

php artisan user:find 100

Untuk membuat argument:

protected $signature = 'user:find {id}';

Kemudian:

public function handle()
{
    $id = $this->argument('id');

    $this->info("Mencari user dengan ID: {$id}");

    return self::SUCCESS;
}

Jalankan:

php artisan user:find 100

Output:

Mencari user dengan ID: 100

Argument Wajib

Dengan:

protected $signature = 'user:find {id}';

id merupakan argument wajib.

Jika menjalankan:

php artisan user:find

Laravel akan meminta argument tersebut.

Argument Opsional

Gunakan:

protected $signature = 'user:find {id?}';

Sekarang argument boleh tidak diberikan.

Contoh:

php artisan user:find

Dalam code:

$id = $this->argument('id');

if (!$id) {
    $this->warn('ID belum diberikan.');

    return self::FAILURE;
}

Memberikan Default Value

Argument juga dapat memiliki default value.

protected $signature = 'report:generate {date?}';

Kemudian:

$date = $this->argument('date') ?? now()->toDateString();

Jika menjalankan:

php artisan report:generate

command menggunakan tanggal hari ini.

Jika:

php artisan report:generate 2026-08-24

command menggunakan tanggal yang diberikan.

Menggunakan Option

Selain argument, Artisan juga mendukung option.

Misalnya:

php artisan report:generate --format=csv

Signature:

protected $signature = 'report:generate {--format=pdf}';

Ambil option:

$format = $this->option('format');

Jika tidak diberikan:

pdf

Jika diberikan:

php artisan report:generate --format=csv

hasil:

csv

Option Boolean

Option juga bisa berupa flag.

Misalnya:

protected $signature = 'user:cleanup {--force}';

Kemudian:

if ($this->option('force')) {
    // jalankan mode force
}

Command:

php artisan user:cleanup --force

Option seperti --force berguna untuk tindakan yang berisiko.

Meminta Konfirmasi Sebelum Menjalankan Task

Untuk operasi berbahaya, kita dapat meminta konfirmasi.

if (!$this->confirm('Apakah Anda yakin ingin menghapus data?')) {
    $this->warn('Proses dibatalkan.');

    return self::SUCCESS;
}

Ketika command dijalankan:

Apakah Anda yakin ingin menghapus data? (yes/no)

Ini berguna ketika Command dijalankan secara manual.

Namun hati-hati jika Command juga digunakan oleh Scheduler.

Scheduler tidak dapat menjawab prompt interaktif seperti developer di terminal.

Untuk command otomatis, sebaiknya hindari interaksi yang membutuhkan input manual.

Gunakan --force untuk Automation

Misalnya:

protected $signature = 'data:cleanup {--force}';

Kemudian:

if (!$this->option('force')) {
    if (!$this->confirm('Lanjutkan proses?')) {
        return self::SUCCESS;
    }
}

Saat manual:

php artisan data:cleanup

akan meminta konfirmasi.

Sedangkan Scheduler dapat menggunakan:

Schedule::command('data:cleanup --force')
    ->dailyAt('02:00');

Dengan begitu task otomatis tidak menunggu input.

Membuat Progress Bar

Untuk Command yang memproses banyak data, progress bar dapat membantu.

Contoh:

$users = User::query()->get();

$bar = $this->output->createProgressBar($users->count());

$bar->start();

foreach ($users as $user) {
    // proses user

    $bar->advance();
}

$bar->finish();

Output:

100/100 [============================] 100%

Ini sangat berguna ketika Command dijalankan secara manual.

Menggunakan Table Output

Jika ingin menampilkan data dalam bentuk tabel:

$this->table(
    ['ID', 'Name'],
    [
        [1, 'Budi'],
        [2, 'Andi'],
    ]
);

Output menjadi lebih mudah dibaca:

+----+------+
| ID | Name |
+----+------+
| 1  | Budi |
| 2  | Andi |
+----+------+

Menangani Data dalam Jumlah Besar

Hindari:

$users = User::all();

foreach ($users as $user) {
    // ...
}

jika tabel memiliki jutaan data.

Karena semua data dapat dimuat ke memory.

Lebih baik gunakan:

User::chunkById(500, function ($users) {
    foreach ($users as $user) {
        // proses
    }
});

Atau gunakan lazyById() sesuai kebutuhan.

Konsepnya:

Database
 ↓
500 rows
 ↓
Process
 ↓
500 rows
 ↓
Process
 ↓
...

Memory lebih terkontrol.

Contoh Command dengan chunkById()

public function handle()
{
    $processed = 0;

    User::chunkById(500, function ($users) use (&$processed) {
        foreach ($users as $user) {
            // proses user

            $processed++;
        }
    });

    $this->info("{$processed} user berhasil diproses.");

    return self::SUCCESS;
}

Ini lebih aman untuk data besar dibandingkan mengambil seluruh data sekaligus.

Gunakan Service untuk Logic yang Kompleks

Hindari membuat handle() menjadi terlalu panjang.

Contoh buruk:

public function handle()
{
    // 300 baris logic
}

Lebih baik:

Command
   ↓
Service
   ↓
Repository / Model
   ↓
Database

Misalnya:

public function handle(ReportService $service)
{
    $service->generateDailyReport();

    $this->info('Report selesai.');

    return self::SUCCESS;
}

Dengan demikian Command hanya bertugas sebagai entry point.

Artisan Command Sebaiknya Menjadi Entry Point

Idealnya:

Artisan Command
      ↓
Service
      ↓
Business Logic

Bukan:

Artisan Command
      ↓
Ratusan baris business logic

Keuntungannya, logic dapat digunakan kembali dari:

  • Controller
  • Queue Job
  • Scheduler
  • Command
  • Test

Menggunakan Dependency Injection

Laravel memungkinkan dependency injection pada handle().

Misalnya:

public function handle(ReportService $service)
{
    $service->generate();

    return self::SUCCESS;
}

Laravel akan melakukan resolve dependency tersebut melalui service container.

Ini membuat Command lebih mudah diuji dan dipelihara.

Menangani Exception

Command dapat menangani error dengan try/catch.

public function handle()
{
    try {
        // proses

        $this->info('Proses berhasil.');

        return self::SUCCESS;
    } catch (\Throwable $e) {
        $this->error($e->getMessage());

        return self::FAILURE;
    }
}

Untuk production, jangan hanya menampilkan error.

Sebaiknya juga gunakan logging:

use Illuminate\Support\Facades\Log;

Log::error('Command gagal', [
    'exception' => $e,
]);

Gunakan Exit Code yang Benar

Artisan menyediakan:

return self::SUCCESS;

untuk proses berhasil.

Sedangkan:

return self::FAILURE;

untuk proses gagal.

Ini penting karena command dapat dijalankan oleh:

  • Cron
  • Supervisor
  • CI/CD
  • Script deployment
  • Monitoring

Sistem tersebut dapat mengetahui apakah command berhasil berdasarkan exit code.

Contoh Command yang Baik

public function handle(ReportService $service)
{
    $this->info('Memulai generate report...');

    try {
        $service->generateDailyReport();

        $this->info('Report berhasil dibuat.');

        return self::SUCCESS;
    } catch (\Throwable $e) {
        report($e);

        $this->error('Generate report gagal.');

        return self::FAILURE;
    }
}

Command tetap sederhana, sedangkan logic berada di service.

Artisan Command untuk Import Data

Contoh signature:

protected $signature = 'product:import {file}';

Kemudian:

$file = $this->argument('file');

if (!file_exists($file)) {
    $this->error('File tidak ditemukan.');

    return self::FAILURE;
}

Jalankan:

php artisan product:import products.csv

Alurnya:

CSV
 ↓
Artisan Command
 ↓
Validate
 ↓
Process
 ↓
Database

Untuk file besar, sebaiknya proses dilakukan secara bertahap agar memory tidak berlebihan.

Artisan Command untuk Sinkronisasi API

Contoh:

protected $signature = 'product:sync';

Kemudian:

public function handle(ProductSyncService $service)
{
    $this->info('Memulai sinkronisasi...');

    $service->sync();

    $this->info('Sinkronisasi selesai.');

    return self::SUCCESS;
}

Command:

php artisan product:sync

Kemudian dapat dijadwalkan:

Schedule::command('product:sync')
    ->everyTenMinutes();

Alurnya:

Cron
 ↓
Scheduler
 ↓
product:sync
 ↓
External API
 ↓
Database

Artisan Command untuk Maintenance

Contoh command:

cache:cleanup
file:cleanup
session:cleanup
report:generate
data:sync
notification:send

Semua dapat dibuat sebagai Command terpisah.

Ini membuat maintenance server dan aplikasi lebih terstruktur.

Artisan Command vs Queue Job

Keduanya sering terlihat mirip, tetapi memiliki fungsi berbeda.

Artisan Command:

Cara menjalankan pekerjaan

Queue Job:

Cara memproses pekerjaan di background

Misalnya:

Artisan Command
 ↓
Dispatch Job
 ↓
Redis
 ↓
Queue Worker

Contoh:

public function handle()
{
    GenerateReport::dispatch();

    $this->info('Report Job masuk queue.');

    return self::SUCCESS;
}

Kapan Menggunakan Command?

Gunakan Artisan Command ketika pekerjaan:

  • Perlu dijalankan dari terminal
  • Perlu dijadwalkan
  • Merupakan proses maintenance
  • Membutuhkan input CLI
  • Digunakan untuk import/export
  • Digunakan untuk sinkronisasi
  • Digunakan sebagai entry point automation

Kapan Menggunakan Queue Job?

Gunakan Queue Job ketika pekerjaan:

  • Membutuhkan waktu lama
  • Tidak perlu membuat user menunggu
  • Dapat diproses di background
  • Membutuhkan retry
  • Membutuhkan delay
  • Memiliki banyak item untuk diproses

Contohnya:

Command
 ↓
Dispatch Job
 ↓
Redis
 ↓
Worker

Command + Scheduler + Queue

Ketiga fitur dapat digunakan bersama.

Misalnya setiap hari pukul 02:00 kita ingin memproses 1 juta data.

Arsitektur yang baik:

Cron
 ↓
Scheduler
 ↓
Artisan Command
 ↓
Dispatch Jobs
 ↓
Redis
 ↓
Queue Worker
 ↓
Process Data

Command tidak perlu memproses 1 juta data secara langsung.

Command cukup membagi pekerjaan menjadi Job.

Contoh Command untuk Dispatch Job

public function handle()
{
    User::query()
        ->select('id')
        ->chunkById(500, function ($users) {
            foreach ($users as $user) {
                ProcessUser::dispatch($user->id);
            }
        });

    $this->info('Semua job berhasil dikirim ke queue.');

    return self::SUCCESS;
}

Kemudian Scheduler:

Schedule::command('user:process')
    ->dailyAt('02:00');

Worker:

php artisan queue:work redis

Jika menggunakan Supervisor, Worker dapat dijaga agar tetap berjalan.

Jangan Membuat Command Menjadi Terlalu Berat

Misalnya:

public function handle()
{
    // ambil jutaan data
    // request API jutaan kali
    // generate file besar
    // kirim ribuan email
}

Ini berpotensi menyebabkan:

  • Memory tinggi
  • Timeout
  • Proses lama
  • Sulit retry
  • Server terbebani

Lebih baik:

Command
 ↓
Dispatch Jobs
 ↓
Queue
 ↓
Worker

Logging pada Artisan Command

Gunakan Laravel Log untuk mencatat proses penting:

use Illuminate\Support\Facades\Log;

Log::info('Cleanup dimulai');

Log::info('Cleanup selesai', [
    'deleted' => $deleted,
]);

Kemudian log dapat diperiksa:

tail -f storage/logs/laravel.log

Ini sangat berguna ketika Command dijalankan melalui Scheduler karena tidak ada developer yang melihat output terminal secara langsung.

Command yang Dipanggil Scheduler Tidak Boleh Bergantung pada Terminal

Hindari logic seperti:

$this->ask('Masukkan nama:');

jika Command tersebut akan dijalankan otomatis.

Scheduler tidak memiliki manusia yang menjawab pertanyaan tersebut.

Untuk automation, gunakan:

Argument
Option
Configuration
Database
Environment

Contoh:

php artisan report:generate --format=pdf

lebih cocok untuk automation dibandingkan meminta input interaktif.

Gunakan Environment Variable untuk Konfigurasi

Misalnya:

REPORT_FORMAT=pdf

Kemudian:

$format = config('report.format');

atau melalui konfigurasi aplikasi.

Dengan begitu Command tidak perlu memiliki nilai yang hardcoded.

Artisan Command di Production

Sebelum menjalankan Command di production:

php artisan report:daily

pastikan:

  • Command sudah dites
  • Database benar
  • Environment benar
  • Permission benar
  • Logic memiliki error handling
  • Tidak ada operasi berbahaya tanpa proteksi
  • Logging tersedia

Untuk operasi destructive, gunakan option seperti:

php artisan data:cleanup --force

sehingga mode otomatis dapat dibedakan dari mode manual.

Testing Artisan Command

Laravel juga memungkinkan Command diuji melalui automated test.

Contoh:

$this->artisan('user:count')
    ->assertExitCode(0);

Untuk Command dengan output:

$this->artisan('user:count')
    ->expectsOutput('Total user: 10')
    ->assertExitCode(0);

Testing seperti ini membantu memastikan perubahan kode tidak merusak automation.

Struktur Command yang Disarankan

Untuk project yang semakin besar:

app/
├── Console/
│   └── Commands/
│       ├── CleanupTemporaryData.php
│       ├── GenerateDailyReport.php
│       └── SyncProducts.php
│
├── Jobs/
│   ├── ProcessUser.php
│   └── GenerateReport.php
│
└── Services/
    ├── ReportService.php
    └── ProductSyncService.php

Alurnya:

Command
   ↓
Service
   ↓
Job
   ↓
Database/API

Tidak semua Command membutuhkan Service atau Job, tetapi struktur ini berguna ketika logic semakin kompleks.

Contoh Custom Command Lengkap

Berikut contoh yang lebih realistis:

<?php

namespace App\Console\Commands;

use App\Services\ReportService;
use Illuminate\Console\Command;
use Throwable;

class GenerateDailyReport extends Command
{
    protected $signature = 'report:daily {--force}';

    protected $description = 'Generate laporan harian';

    public function handle(ReportService $service)
    {
        $this->info('Memulai generate laporan...');

        try {
            $service->generateDailyReport();

            $this->info('Laporan berhasil dibuat.');

            return self::SUCCESS;
        } catch (Throwable $e) {
            report($e);

            $this->error('Generate laporan gagal.');

            return self::FAILURE;
        }
    }
}

Command tersebut dapat dijalankan:

php artisan report:daily

dan kemudian dijadwalkan:

Schedule::command('report:daily')
    ->dailyAt('08:00')
    ->withoutOverlapping();

Alur Automation Lengkap

Dengan konfigurasi tersebut:

Ubuntu Cron
     ↓
schedule:run
     ↓
Laravel Scheduler
     ↓
report:daily
     ↓
ReportService
     ↓
Database / API

Jika report membutuhkan proses berat:

Ubuntu Cron
     ↓
Scheduler
     ↓
report:daily
     ↓
Dispatch Job
     ↓
Redis
     ↓
Queue Worker
     ↓
Generate Report

Troubleshooting Artisan Command

Jika Command tidak dapat dijalankan, mulai dari:

php artisan list

Pastikan Command muncul.

Kemudian:

php artisan report:daily

Jika gagal, periksa error.

Jika dijalankan melalui Scheduler:

php artisan schedule:list

Kemudian:

php artisan schedule:run

Jika manual berhasil tetapi Scheduler gagal, periksa konfigurasi Scheduler dan Cron.

Command Tidak Muncul di php artisan list

Periksa:

php artisan optimize:clear

Kemudian:

php artisan list

Jika tetap tidak muncul, periksa:

  • Namespace
  • Nama class
  • File Command
  • Signature
  • Struktur project
  • Konfigurasi Console Laravel

Pastikan class Command memiliki namespace yang sesuai dengan lokasi file.

Command Berhasil Manual tetapi Gagal di Cron

Ini sering terjadi karena environment berbeda.

Periksa:

which php

dan:

php -v

Kemudian gunakan absolute path pada Cron:

* * * * * /usr/bin/php /var/www/myapp/artisan schedule:run

Periksa juga .env, permission, working directory, dan user yang menjalankan Cron.

Best Practice Membuat Artisan Command

Beberapa prinsip yang sebaiknya digunakan:

  1. Gunakan nama command yang jelas
report:daily
product:sync
user:cleanup
  1. Buat handle() tetap sederhana

Pindahkan business logic kompleks ke Service.

  1. Gunakan argument dan option

Jangan hardcode semua nilai.

  1. Gunakan exit code
return self::SUCCESS;

atau:

return self::FAILURE;
  1. Tambahkan logging

Terutama untuk Command otomatis.

  1. Pertimbangkan Queue

Untuk pekerjaan yang berat.

  1. Hindari prompt interaktif

Jika Command digunakan oleh Scheduler.

  1. Gunakan chunking

Untuk data dalam jumlah besar.

  1. Gunakan withoutOverlapping()

Jika task tidak boleh berjalan bersamaan.

  1. Tes Command secara manual sebelum memasukkannya ke Scheduler

Ini menghemat banyak waktu saat troubleshooting.

Kesimpulan

Laravel Artisan Command merupakan cara yang praktis untuk membuat task custom yang dapat dijalankan melalui terminal maupun automation.

Command sederhana dapat dibuat dengan:

php artisan make:command CleanupTemporaryData

Kemudian tentukan signature:

protected $signature = 'cleanup:temporary-data';

dan logic:

public function handle()
{
    // proses

    return self::SUCCESS;
}

Command kemudian dapat dijalankan manual:

php artisan cleanup:temporary-data

atau dijadwalkan:

Schedule::command('cleanup:temporary-data')
    ->dailyAt('02:00');

Untuk proses yang berat, gunakan kombinasi:

Cron
 ↓
Laravel Scheduler
 ↓
Artisan Command
 ↓
Queue Job
 ↓
Redis
 ↓
Queue Worker

Dengan pendekatan ini, Artisan Command menjadi entry point untuk automation, Scheduler menentukan kapan pekerjaan dijalankan, dan Queue menangani pekerjaan berat di background.

Struktur tersebut sangat cocok untuk aplikasi Laravel production yang membutuhkan proses otomatis seperti cleanup data, sinkronisasi API, generate laporan, import data, dan maintenance rutin.