Tutorial Portal Berita - Level 4: Manajemen Topik di Panel Admin π
Selamat datang di Level 4! Kali ini kita akan fokus pada Manajemen Topik di Panel Admin menggunakan Laravolt. Di level ini, kita akan menyaksikan kecepatan dalam membangun fungsionalitas CRUD (Create, Read, Update, Delete) dengan memanfaatkan code generator andalan, Thunderclap.
Kita akan membuat modul untuk Topik Berita secara otomatis, lalu mengintegrasikannya dengan sistem otorisasi yang telah kita siapkan di Level 3. Tujuannya adalah memastikan hanya pengguna yang berhak (Admin) yang dapat mengelola topik.
π― Tujuan Level 4:
- Menggunakan perintah
laravolt:clap
untuk membuat modul CRUD secara otomatis. - Mendaftarkan modul yang baru dibuat ke dalam aplikasi Laravel.
- Mengintegrasikan otorisasi (Policies) ke dalam controller yang dihasilkan.
- Menambahkan menu baru ke sidebar Laravolt.
- Memverifikasi fungsionalitas CRUD dan keamanannya.
1. Persiapan: Model Topic
dan Otorisasi
Sebelum menggunakan generator, pastikan model App\Models\Topic
dan permissions terkait sudah siap dari level-level sebelumnya.
- Model
App\Models\Topic
: Sudah dibuat di Level 2 dengan fillable attributes, traits (HasUlids
,SoftDeletes
,HasFactory
), dan relasi yang diperlukan. - Permissions di
App\Enums\Permission
: Dari Level 3, kita sudah punyaTOPIC_VIEW
,TOPIC_CREATE
,TOPIC_EDIT
, danTOPIC_DELETE
. - Role Admin: Sudah memiliki semua permissions di atas.
2. Membuat TopicPolicy
Langkah ini sangat krusial untuk otorisasi. Jika belum dibuat di Level 3, sekarang saatnya. Pastikan juga sudah terdaftar di AuthServiceProvider
.
1. Buat Policy
php artisan make:policy TopicPolicy --model=Topic
2. Isi app/Policies/TopicPolicy.php
<?php
namespace App\Policies;
use App\Enums\Permission;
use App\Models\Topic;
use App\Models\User;
class TopicPolicy
{
public function before(User $user, string $ability): bool|null
{
if ($user->hasRole('admin')) {
return true;
}
return null;
}
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return $user->can(Permission::TOPIC_VIEW);
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, Topic $topic): bool
{
return $user->can(Permission::TOPIC_VIEW);
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return $user->can(Permission::TOPIC_CREATE);
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, Topic $topic): bool
{
return $user->can(Permission::TOPIC_EDIT);
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, Topic $topic): bool
{
return $user->can(Permission::TOPIC_DELETE);
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, Topic $topic): bool
{
// Atau gunakan permission terpisah jika perlu
return $user->can(Permission::TOPIC_EDIT);
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, Topic $topic): bool
{
// Biasanya hanya super admin (sudah di-handle oleh 'before')
return false;
}
}
3. Daftarkan di app/Providers/AuthServiceProvider.php
protected $policies = [
// ... policies lain
\App\Models\Topic::class => \App\Policies\TopicPolicy::class,
];
3. Implementasi AutoCRUD dengan Thunderclap (laravolt:clap
) β‘
Saatnya menggunakan sihir dari Thunderclap untuk membuat seluruh modul manajemen topik.
1. Jalankan Perintah Interaktif
Buka terminal dan jalankan perintah laravolt:clap
:
php artisan laravolt:clap
2. Ikuti Proses Interaktif
- Thunderclap akan meminta Anda memilih tabel dari database. Pilih
topics
. - Ikuti instruksi selanjutnya, dan generator akan membuat seluruh file yang dibutuhkan di dalam direktori
modules/
.
Struktur direktori baru yang akan terbentuk:
modules/
βββ Topic/
βββ Http/
β βββ Controllers/
β βββ Requests/
β βββ Tables/
βββ Providers/
βββ Models/ (Bisa dihapus nanti)
βββ resources/
β βββ lang/
β βββ views/
βββ routes/
Catatan: File yang dihasilkan mungkin berekstensi
.stub
. Laravolt biasanya akan otomatis mengubahnya menjadi.php
.
4. Registrasi Modul Baru
Agar modul baru ini dikenali oleh aplikasi, kita perlu mendaftarkannya.
1. Perbarui composer.json
Tambahkan direktori modules/
ke dalam konfigurasi autoloading PSR-4.
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/",
"Modules\\": "modules/"
}
},
2. Daftarkan Service Provider
Tambahkan Service Provider dari modul baru ke dalam bootstrap/providers.php
.
<?php
return [
// ... service provider lain
\Modules\Topic\Providers\TopicServiceProvider::class,
];
3. Update Autoloader
Jalankan perintah berikut di terminal untuk memperbarui autoloader Composer.
composer dump-autoload
5. Kustomisasi dan Integrasi Otorisasi
Kode yang dihasilkan Thunderclap adalah fondasi. Sekarang, kita perlu menyesuaikannya.
1. Sesuaikan Controller
Buka modules/Topic/Http/Controllers/TopicController.php
dan terapkan TopicPolicy
.
- Gunakan Model yang Benar: Pastikan controller menggunakan
\App\Models\Topic
. - Terapkan Otorisasi: Gunakan
$this->authorize()
di setiap action.
<?php
namespace Modules\Topic\Controllers;
use App\Models\Topic;
use Illuminate\Routing\Controller;
use Modules\Topic\Requests\Store;
use Modules\Topic\Requests\Update;
use Modules\Topic\Tables\TopicTableView;
class TopicController extends Controller
{
public function index()
{
$this->authorize('viewAny', Topic::class);
return TopicTableView::make()->view('topic::index');
}
public function create()
{
$this->authorize('create', Topic::class);
return view('topic::create');
}
public function store(Store $request)
{
Topic::create($request->validated());
return to_route('modules::topic.index')->withSuccess('Topic saved');
}
public function edit(Topic $topic)
{
$this->authorize('update', $topic);
return view('topic::edit', compact('topic'));
}
public function update(Update $request, Topic $topic)
{
$topic->update($request->validated());
return to_route('modules::topic.index')->withSuccess('Topic saved');
}
public function destroy(Topic $topic)
{
$this->authorize('delete', $topic);
$topic->delete();
return to_route('modules::topic.index')->withSuccess('Topic deleted');
}
}
2. Hapus Model Duplikat
Karena kita sudah menggunakan App\Models\Topic
, model di modules/Topic/Models/Topic.php
bisa dihapus untuk menghindari kebingungan. Jangan lupa sesuaikan traits
atau properties
yang diperlukan di model utama jika ada yang belum ditambahkan.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Concerns\HasUlids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Laravolt\Suitable\AutoFilter;
use Laravolt\Suitable\AutoSearch;
use Laravolt\Suitable\AutoSort;
class Topic extends Model
{
// baris lainnya tetap sama
use AutoFilter, AutoSearch, AutoSort;
protected $searchableColumns = ['name', 'slug', 'description'];
// baris lainnya tetap sama
}
3. Sesuaikan TableView
Sama seperti Controller, kelas yang menampilkan data dalam bentuk tabel juga harus diarahkan untuk menggunakan model utama \App\Models\Topic
.
Buka file TableView
yang digenerate (misalnya modules/Topic/Tables/TopicTableView.php
):
<?php
namespace Modules\Topic\Tables;
use App\Models\Topic;
use Laravolt\Suitable\Columns\Numbering;
use Laravolt\Suitable\Columns\RestfulButton;
use Laravolt\Suitable\Columns\Text;
use Laravolt\Suitable\TableView;
class TopicTableView extends TableView
{
public function source()
{
return Topic::autoSort()->latest()->autoSearch(request('search'))->paginate();
}
protected function columns()
{
return [
Numbering::make('No'),
Text::make('name')->sortable(),
Text::make('slug')->sortable(),
Text::make('description')->sortable(),
RestfulButton::make('modules::topic'),
];
}
}
4. Sesuaikan Form Request
Pastikan form request (misal: Store.php
dan Update.php
) menggunakan permission yang benar.
Contoh modules/Topic/Requests/Store.php
:
<?php
namespace Modules\Topic\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Str;
class Store extends FormRequest
{
public function authorize()
{
return $this->user()->can('create', \App\Models\Topic::class);
}
protected function prepareForValidation()
{
if ($this->has('name') && !$this->has('slug')) {
$this->merge(['slug' => Str::slug($this->input('name'))]);
}
}
public function rules()
{
return [
'name' => ['required', 'string', 'max:255'],
'slug' => ['required', 'string', 'max:255', 'unique:topics,slug'],
'description' => ['nullable', 'string', 'max:1000'],
];
}
}
Contoh modules/Topic/Requests/Update.php
:
<?php
namespace Modules\Topic\Requests;
class Update extends Store
{
public function authorize()
{
// Model di-resolve oleh route model binding
return $this->user()->can('update', $this->route('topic'));
}
public function rules()
{
$topicId = $this->route('topic')->id;
return [
'name' => ['required', 'string', 'max:255'],
'slug' => ['required', 'string', 'max:255', 'unique:topics,slug,'.$topicId],
'description' => ['nullable', 'string', 'max:1000'],
];
}
}
5. Sesuaikan Route
Jika tidak memerlukan route show
, kita bisa mengecualikannya di modules/Topic/routes/web.php
.
Route::resource('topic', TopicController::class)->except('show');
6. Verifikasi Fungsionalitas dan Otorisasi β
- Jalankan Aplikasi dan login sebagai Admin (
[email protected]
). - Verifikasi Menu: Menu "Manajemen Topik" seharusnya muncul di sidebar.
- Test CRUD:
- Klik menu tersebut dan Anda akan masuk ke halaman daftar topik.
- Coba buat, edit, dan hapus topik. Pastikan semua berjalan lancar.
- Test Otorisasi:
- Login sebagai Writer (
[email protected]
). - Pastikan menu "Manajemen Topik" tidak muncul.
- Coba akses URL
/admin/topics
secara manual. Anda harus mendapatkan error 403 Forbidden. - Lakukan tes yang sama untuk role Member.
- Login sebagai Writer (
Selamat! π
Anda telah berhasil menyelesaikan Level 4. Kini Anda mampu menggunakan Laravolt Thunderclap untuk membuat modul CRUD secara instan, mendaftarkannya, dan mengamankannya dengan sistem otorisasi berbasis policy.
Di Level 5, kita akan melangkah lebih jauh dengan Manajemen Post, yang melibatkan rich text editor dan unggah gambar. Sampai jumpa di level berikutnya!