Home Paket Belajar Bootcamp Instruktur

Kuasai Eloquent ORM #7 - Mengenal Query Scopes, Accessors & Best Practices

Pelajari Eloquent ORM Laravel dari dasar hingga mahir. Pahami berbagai jenis relasi seperti hasOne, hasMany, belongsTo, belongsToMany, hasManyThrough, hingga polymorphic relationship. Kuasai teknik query yang efisien menggunakan eager loading, constraint query, aggregate, subquery, serta cara menghindari N+1 Query agar aplikasi Laravel lebih cepat dan scalable. Materi disertai studi kasus dan best practice yang sering digunakan di proyek nyata.

✅ Telah dilihat 14 kali

Rating: 5.00 ⭐

... 08 June 2026, 19:34

Local Query Scope

Scope memungkinkan kamu enkapsulasi logika query yang sering dipakai.

class Post extends Model
{
    // Scope: hanya post yang sudah dipublish
    public function scopePublished(Builder $query): void
    {
        $query->whereNotNull('published_at')
              ->where('published_at', '<=', now());
    }

    // Scope: post unggulan
    public function scopeFeatured(Builder $query): void
    {
        $query->where('is_featured', true);
    }

    // Scope dengan parameter
    public function scopeByUser(Builder $query, int $userId): void
    {
        $query->where('user_id', $userId);
    }
}

Penggunaan:

// Pakai scope
$posts = Post::published()->get();
$posts = Post::featured()->get();
$posts = Post::byUser(1)->get();

// Chain scope
$posts = Post::published()->featured()->latest()->paginate(10);

Global Scope

Diterapkan otomatis ke semua query model.

// Buat global scope
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;

class PublishedScope implements Scope
{
    public function apply(Builder $builder, Model $model): void
    {
        $builder->whereNotNull('published_at');
    }
}

// Daftarkan di model
class Post extends Model
{
    protected static function booted(): void
    {
        static::addGlobalScope(new PublishedScope);
    }
}

// Mengabaikan global scope
$allPosts = Post::withoutGlobalScope(PublishedScope::class)->get();

Accessor & Mutator

Accessor = ubah data saat dibacaMutator = ubah data saat ditulis.

use Illuminate\Database\Eloquent\Casts\Attribute;

class User extends Model
{
    // Accessor: nama selalu Title Case
    protected function name(): Attribute
    {
        return Attribute::make(
            get: fn (string $value) => ucwords($value),
        );
    }

    // Accessor + Mutator: password di-hash saat disimpan
    protected function password(): Attribute
    {
        return Attribute::make(
            get: fn (string $value) => $value,
            set: fn (string $value) => bcrypt($value),
        );
    }

    // Computed accessor (tidak ada di DB)
    protected function fullName(): Attribute
    {
        return Attribute::make(
            get: fn () => "{$this->first_name} {$this->last_name}",
        );
    }
}

Penggunaan:

$user = User::find(1);
echo $user->name;      // otomatis Title Case
echo $user->full_name; // computed attribute

$user->password = 'secret'; // otomatis di-hash
$user->save();

Best Practices Eloquent

1. Selalu gunakan $fillable atau $guarded

// ✅ Eksplisit kolom yang bisa diisi
protected $fillable = ['title', 'body', 'user_id'];

// Atau: tandai yang TIDAK boleh diisi massal
protected $guarded = ['id', 'admin_override'];

2. Gunakan $casts untuk tipe data

protected $casts = [
    'published_at' => 'datetime',
    'settings'     => 'array',      // JSON otomatis decode
    'price'        => 'decimal:2',
    'is_active'    => 'boolean',
];

3. Manfaatkan select() untuk efisiensi

// ❌ Ambil semua kolom padahal hanya perlu 2
$users = User::with('posts')->get();

// ✅ Ambil kolom yang dibutuhkan saja
$users = User::select('id', 'name', 'email')
             ->with(['posts' => fn($q) => $q->select('id', 'user_id', 'title')])
             ->get();

4. Pagination daripada all()

// ❌ Ambil semua data sekaligus (berbahaya jika data besar)
$posts = Post::all();

// ✅ Gunakan pagination
$posts = Post::latest()->paginate(15);
$posts = Post::latest()->simplePaginate(15);  // lebih efisien
$posts = Post::latest()->cursorPaginate(15);  // paling efisien

5. Gunakan chunk() untuk data besar

//  Proses data besar tanpa memory overflow
Post::chunk(200, function ($posts) {
    foreach ($posts as $post) {
        // proses setiap batch
    }
});

// Atau chunkById (lebih aman jika ada update)
Post::chunkById(200, function ($posts) {
    // ...
});

6. Manfaatkan firstOrCreate dan updateOrCreate

// Cari atau buat baru
$user = User::firstOrCreate(
    ['email' => '[email protected]'],            // kondisi pencarian
    ['name' => 'User Baru', 'password' => '...'] // data jika dibuat baru
);

// Update atau buat baru
$post = Post::updateOrCreate(
    ['slug' => 'belajar-laravel'],  // kondisi pencarian
    ['title' => 'Belajar Laravel', 'body' => '...'] // data
);

Langkah selanjutnya: coba implementasi di project nyata, dan eksplorasi Laravel Scout untuk full-text search, serta Eloquent API Resources untuk transformasi data di API.


Dibuat dengan ❤️ untuk komunitas developer Laravel Indonesia

Daftar eBook