Laravel 8 - #9 - Database Seeder
Pada pembahasan kali ini kita akan membahas sesuatu feature yang tidak kalah keren pada Laravel yaitu Seeder
Arman Dwi Pangestu
26 Desember 2023•1 menit baca
Pendahuluan
Seperti yang kita tau, dari beberapa pembahasan sebelumnya jika kita ingin menambahkan data pada aplikasi kita, kita menggunakan sebuah fitur yang namanya tinker. Nah, sebetulnya hal tersebut tidak ada masalah untuk menambahkan beberapa data kedalam aplikasi kita melalui terminal karena kita belum masuk kedalam materi CRUD melalui form input, hal tersebut ketika ingin menambahkan 2, 3, 4 atau 5 data masih oke. Namun, bayangkan jika ingin menambahkan 20 atau 30 data post, mungkin hal tersebut akan cukup merepotkan jika melalui tulis secara manual melalui tinker.
Atau dalam kasus kita kali ini adalah masih dalam tahap pengembangan atau development, tahap tersebut pastinya kita sering mengubah-ubah skema dari tabel kita seperti menambah field baru atau menghapus field yang sudah ada didalam database atau ingin menambahkan relasi. Pastinya tabel tersebut masih sering kita ubah dan kita harus melakukan yang namanya migration
yang artinya database kita akan kembali kosong lagi dan memulai nya kembali dari awal sehingga jika ingin menambahkan data lagi kita perlu membuka tinker dan mengisikan data nya kembali satu per-satu. Hal tersebut lah baru terasa sangat merepotkan, lantas bagaimana cara mengatasinya?
Untuk mengatasinya tenang, karena pada Laravel terdapat fitur untuk mempermudah hal tersebut, nama fitur tersebut adalah Seeder
dan juga Factory
. Feature tersebut nantinya akan mempermudah kita mempopulasi (istilah nya) atau mengisikan data secara otomatis ketika kita melakukan migration
, sehingga ketika kita melakukan migration, maka di tabel nya akan otomatis terdapat isi nya dan tidak perlu lagi repot-repot melakukan insert data satu per-satu secara manual.
Untuk pendahuluan sebelum masuk kedalam seeder, disini kita benarkan dan tambahkan beberapa UI pada tampilan blog kita seperti menghilangkan garis underline pada anchor link, kemudian menambahkan detail category dan sebagai nya. Kita mulai dari file view posts.blade.php
, berikut adalah kode view nya
@extends('layouts.main')
@section('container')
<h1 class="mb-5">Halaman Blog Posts</h1>
@foreach ($posts as $post)
<article class="mb-5 border-bottom pb-4">
<h2>
<a href="/posts/{{ $post->slug }}" class="text-decoration-none">{{ $post->title }}</a>
</h2>
<h5>By: {{ $post->author }} in <a href="/categories/{{ $post->category->slug }}" class="text-decoration-none">{{ $post->category->name }}</a></h5>
<p>{{ $post->excerpt }}</p>
<a href="/posts/{{ $post->slug }}" class="text-decoration-none">Read more..</a>
</article>
@endforeach
@endsection
Kemudian file view post.blade.php
@extends('layouts.main')
@section('container')
<article>
<h2>{{ $post->title }}</h2>
<h5>By: {{ $post->author }} in <a href="/categories/{{ $post->category->slug }}" class="text-decoration-none">{{ $post->category->name }}</a></h5>
{!! $post->body !!}
</article>
<a href="/posts">Back to Posts</a>
@endsection
File view categories.blade.php
@extends('layouts.main')
@section('container')
<h1 class="mb-5">Post Categories</h1>
@foreach ($categories as $category)
<ul>
<li>
<h2>
<a href="/categories/{{ $category->slug }}" class="text-decoration-none">{{ $category->name }}</a>
</h2>
</li>
</ul>
@endforeach
@endsection
dan yang terakhir file category.blade.php
@extends('layouts.main')
@section('container')
<h1 class="mb-5">Post Category : {{ $category }}</h1>
@foreach ($posts as $post)
<article class="mb-5">
<h2>
<a href="/posts/{{ $post->slug }}" class="text-decoration-none">{{ $post->title }}</a>
</h2>
<h5>By: {{ $post->author }}</h5>
<p>{{ $post->excerpt }}</p>
</article>
@endforeach
@endsection
Fitur selanjutnya kita akan buat juga agar tulisan author nya bisa di klik seperti tulisan category nya, sehingga kita perlu membuat relasi antar model Post dan juga model User. Oleh karena itu kita tambahkan pada skema model post nya agar menyimpan atau memuat foreign key user_id
dari tabel User di file migration nya
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('category_id');
$table->foreignId('user_id');
$table->string('title');
$table->string('slug')->unique();
$table->string('author');
$table->text('excerpt');
$table->text('body');
$table->timestamp('publish_at')->nullable();
$table->timestamps();
});
}
Sekarang problem nya adalah kita harus melakukan migration lagi, dengan melakukan hal tersebut lagi-lagi akan mengosongkan tabel kita. Sekarang apakah kalian sudah merasa kesal? karena dari pembahasan sebelumnya kita sudah melakukan hapus tabel, buat lagi dan seterusnya bukan? Nah, karena memang kita masih dalam proses development, maka sangat wajar bukan banyaknya perubahan yang terjadi? Nah, pada tahap inilah kita butuh yang namanya Seeder
. Sekarang kita lakukan migaration nya terlebih dahulu
php artisan migrate:fresh
Apa itu Seeder?
Seeding ini jika saya terjemahkan itu seperti kita menyemai benih, karena seed
ini benih atau biji. Jadi ceritanya kita bisa mengisi otomatis tabel kita ketika kita buat, sehingga seperti kita memanen tabel nya.
Jika dikutip dari dokumentasi resmi Laravel nya "Laravel memiliki kemampuan untuk melakukan seed didalam database kita dengan data testing
dengan cara menggunakan class Seed
. Sehingga tiap model itu kita bisa bikin class seed nya dan nantinya disimpan kedalam folder database/seeders
. Secara default, kita sudah diberikan sebuah seeder yang namanya DatabaseSeeder
, yang nantinya kita bisa gunakan untuk menjalankan proses seeding nya dari class-class atau model-model yang lain."
Cara Membuat atau Menulis Seeder
Untuk men-generate sebuah seeder, kalian bisa jalankan perintah artisan make:seeder
. Semua seeder yang di-generate oleh framework akan disimpan di folder database/seeders
php artisan make:seeder NamaSeeder
Berikut adalah contoh isi dari class bawaan DatabaseSeeder
yang sudah ada pada framework Laravel dan menambahkan sebuah statement database insert pada method run
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeders.
*
* @return void
*/
public function run()
{
DB::table('users')->insert([
'name' => Str::random(10),
'email' => Str::random(10).'@gmail.com',
'password' => Hash::make('password'),
]);
}
}
Menggunakan Model Factories
Kita juga bisa membuat seeder dengan Factories
, sehingga seakan-akan kita membuat pabrik pembuat data untuk melakukan seeding nya secara otomatis. Misalkan, membuat 50 user yang masing-masing nya memiliki satu buah postingan terkait
use App\Models\User;
/**
* Run the database seeders.
*
* @return void
*/
public function run()
{
User::factory()
->count(50)
->hasPosts(1)
->create();
}
Atau jika kita ingin membuat seeding nya satu-persatu, misalkan User membuat seeding sendiri, Post membuat seeding sendiri dan seterusnya
/**
* Run the database seeders.
*
* @return void
*/
public function run()
{
$this->call([
UserSeeder::class,
PostSeeder::class,
CommentSeeder::class,
]);
}
Menjalankan Seeder
Setelah menyiapkan skema seeding nya, selanjutnya kita perlu eksekusi agar data nya tersimpan pada database menggunakan perintah artisan
Catatan:
Secara default perintah
db:seed
akan menjalankan classDatabase\Seeders\DatabaseSeeder
, yang pada gilirannya dimana dapat memanggil class seed lainnya
php artisan db:seed
Jika kalian hanya ingin men-spesifikan class seeder mana yang ingin dieksekusi atau secara individual, kalian bisa menggunakan option --class
php artisan db:seed --class=UserSeeder
Mencoba Seeder
Kita bisa mencoba database seeder dengan simpel, kalian bisa buka file DatabaseSeeder.php
kemudian uncomment agar isian dari method run
nya bisa dieksekusi
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
\App\Models\User::factory(10)->create();
}
}
Sekarang kita bisa jalankan seeder nya dengan perintah artisan
php artisan db:seed
Maka akan muncul output tulisan
Database seeding completed successfully.
Dan jika kita lihat menggunakan tinker data di tabel user, maka sekarang akan muncul 10 data random
User::all();
[!] Aliasing 'User' to 'App\Models\User' for this Tinker session.
= Illuminate\Database\Eloquent\Collection {#7096
all: [
App\Models\User {#7097
id: 1,
name: "Prof. Nels Buckridge",
email: "reinger.terrell@example.com",
email_verified_at: "2023-12-26 01:50:54",
#password: "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi",
#remember_token: "HlsdfsMUsv",
created_at: "2023-12-26 01:50:55",
updated_at: "2023-12-26 01:50:55",
},
App\Models\User {#7098
id: 2,
...
},
App\Models\User {#7099
id: 3,
...
},
App\Models\User {#7100
id: 4,
...
},
App\Models\User {#7101
id: 5,
...
},
App\Models\User {#7102
id: 6,
...
},
App\Models\User {#7103
id: 7,
...
},
App\Models\User {#7104
id: 8,
...
},
App\Models\User {#7105
id: 9,
...
},
App\Models\User {#7106
id: 10,
...
},
],
}
Hal tersebut kita sudah melakukan seeding dengan bantuan factory, yang dimana terdapat sebuah feature untuk mengenerate 10 data palsu untuk dimasukan kedalam tabel kita. Keren banget bukan? tapi sekarang kita akan coba terlebih dahulu secara manual, maka kita hapus kembali data nya dengan cara migrate ulang
php artisan migrate:fresh
Kemudian kasih komentar kembali isian dari method run
di file DatabaseSeeder.php
nya
public function run()
{
// \App\Models\User::factory(10)->create();
}
Implementasi Seeding
Nah sekarang kita akan melakukan seeding secara manual, cara kita tulis apa yang kita ketikan didalam tinker di pembahasan sebelumnya seperti
Post::create([])
Nah hal tersebut yang dilakukan didalam tinker, kita lakukan didalam seeding sekarang
public function run()
{
// \App\Models\User::factory(10)->create();
User::create([
'name' => 'Arman Dwi Pangestu',
'email' => 'armandwi.pangestu7@gmail.com',
'password' => bcrypt('12345')
]);
Category::create([
'name' => 'Web Programming',
'slug' => 'web-programming'
]);
Category::create([
'name' => 'Personal',
'slug' => 'personal'
]);
Post::create([
'title' => 'Judul Pertama',
'slug' => 'judul-pertama',
'excerpt' => 'Lorem ipsum dolor sit amet consectetur adipisicing elit.',
'body' => 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus sed quis, perferendis adipisci placeat, quidem rem mollitia quam voluptate, excepturi voluptas soluta quos. Officiis similique nihil unde quibusdam, iste quae cupiditate iure maxime! Fugiat doloremque dignissimos adipisci omnis saepe rem possimus tenetur! Voluptates omnis eaque facere architecto asperiores a odio illo nemo quam alias repellat praesentium aspernatur, soluta voluptate sapiente doloremque minus quisquam dolores. Voluptate sit blanditiis odio quos. Ipsa error nam distinctio! Illo voluptatibus, quia tempore eos fuga vero consequatur libero fugiat enim consectetur facilis sint corporis delectus illum, eius nemo tempora dolor iusto eligendi rem eum veritatis. Voluptatibus?',
'category_id' => 1,
'user_id' => 1
]);
Post::create([
'title' => 'Judul Kedua',
'slug' => 'judul-kedua',
'excerpt' => 'Lorem ipsum dolor sit amet consectetur adipisicing elit.',
'body' => 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus sed quis, perferendis adipisci placeat, quidem rem mollitia quam voluptate, excepturi voluptas soluta quos. Officiis similique nihil unde quibusdam, iste quae cupiditate iure maxime! Fugiat doloremque dignissimos adipisci omnis saepe rem possimus tenetur! Voluptates omnis eaque facere architecto asperiores a odio illo nemo quam alias repellat praesentium aspernatur, soluta voluptate sapiente doloremque minus quisquam dolores. Voluptate sit blanditiis odio quos. Ipsa error nam distinctio! Illo voluptatibus, quia tempore eos fuga vero consequatur libero fugiat enim consectetur facilis sint corporis delectus illum, eius nemo tempora dolor iusto eligendi rem eum veritatis. Voluptatibus?',
'category_id' => 1,
'user_id' => 1
]);
Post::create([
'title' => 'Judul Ketiga',
'slug' => 'judul-ketiga',
'excerpt' => 'Lorem ipsum dolor sit amet consectetur adipisicing elit.',
'body' => 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus sed quis, perferendis adipisci placeat, quidem rem mollitia quam voluptate, excepturi voluptas soluta quos. Officiis similique nihil unde quibusdam, iste quae cupiditate iure maxime! Fugiat doloremque dignissimos adipisci omnis saepe rem possimus tenetur! Voluptates omnis eaque facere architecto asperiores a odio illo nemo quam alias repellat praesentium aspernatur, soluta voluptate sapiente doloremque minus quisquam dolores. Voluptate sit blanditiis odio quos. Ipsa error nam distinctio! Illo voluptatibus, quia tempore eos fuga vero consequatur libero fugiat enim consectetur facilis sint corporis delectus illum, eius nemo tempora dolor iusto eligendi rem eum veritatis. Voluptatibus?',
'category_id' => 2,
'user_id' => 1
]);
}
Nah sekarang kita sudah membuat seed nya secara manual semuanya, tapi meskipun manual ini sudah tersimpan didalam DatabaseSeeder
, sehinnga jika kita butuhin kita tinggal jalankan saja perintah artisan db:seed
nya.
php artisan db:seed
Maka sekarang data user, post dan category nya sudah masuk kedalam database setelah migration (tidak perlu lagi isi melalui tinker).
Perlu di-ingat, jika kita menjalankan kembali perintah diatas db:seed
maka akan muncul error, karena seed ini akan menambahkan data nya kembali sedangkan pada file migration kita terdapat sebuah field yang uniqe
seperti field email
pada model user dan field slug
pada model post. Lantas bagaimana jika terdapat perubahan pada file seeder nya tapi tetap ingin menjalankan perintah db:seed
nya? Kalian bisa jalankan perintah berikut ini untuk melakukan migrate:fresh
sekaligus seeding
.
php artisan migrate:fresh --seed
Fitur Tulisan Author Post
Nah, sekarang jika kalian ingin menjalankan fitur tulisan author post agar seperti category, kita bisa mulai ubah dari file view posts.blade.php
<h5>By: <a href="#">{{ $post->user->name }}</a> ... </h5>
Namun, jika kita mencoba menjalankan nya akan muncul error bahwa property name
tersebut tidak ada.
Hal tersebut terjadi karena didalam instance $post
nya belum ada user nya, jika kalian ingat kita hanya baru saja menghubungkan model antara postingan kita dengan category sedangkan kita belum mempunyai hubungan antara model postingan dengan model user nya. Jika kalian membuka file model Post.php
nya maka bisa kalian lihat hanya terdapat method category
public function category()
{
return $this->belongsTo(Category::class);
}
Nah jika ingin menghubungkan nya juga dengan model User, kita bikin juga method user
public function user()
{
return $this->belongsTo(User::class);
}
Setelah itu, kita sekarang buat relasi di model User.php
nya
public function posts()
{
return $this->hasMany(Post::class);
}
Maka sekarang akan view posts
nya akan berjalan
Nah sekarang kita perbaiki pada view single post nya di file post.blade.php
<h5>By: <a href="#" class="text-decoration-none">{{ $post->user->name }}</a> ... </h5>