03. Membuat Chirp
Anda sekarang siap untuk mulai membangun aplikasi baru Anda! Mari kita izinkan pengguna untuk mengirim pesan singkat yang disebut Chirps.
Model, migrasi, dan controller
Untuk memungkinkan pengguna mengirim Chirp, kita perlu membuat model, migrasi, dan controller. Mari kita pelajari masing-masing konsep ini lebih dalam:
- Model menyediakan antarmuka yang andal dan menyenangkan bagi Anda untuk berinteraksi dengan tabel-tabel di database Anda.
- Migrasi memungkinkan Anda untuk membuat dan mengubah tabel di database dengan mudah. Migrasi memastikan bahwa struktur database yang sama ada di mana pun aplikasi Anda dijalankan.
- Controller bertanggung jawab untuk memproses permintaan (request) yang dibuat ke aplikasi Anda dan mengembalikan respons.
Hampir setiap fitur yang Anda bangun akan melibatkan semua bagian ini yang bekerja bersama secara harmonis, sehingga perintah artisan make:model dapat membuat semuanya sekaligus untuk Anda.
Mari kita buat model, migrasi, dan controller untuk Chirp kita dengan perintah berikut:
php artisan make:model -mc Chirp
Anda dapat melihat semua opsi yang tersedia dengan menjalankan perintah php artisan make:model --help.
Perintah ini akan membuat tiga file untuk Anda:
-
app/Models/Chirp.php- Model Eloquent. -
database/migrations/<timestamp>_create_chirps_table.php- Migrasi database yang akan membuat tabel database Anda. -
app/Http/Controllers/ChirpController.php- Controller HTTP yang akan menerima permintaan masuk dan mengembalikan respons.
Perutean (Routing)
Kita juga perlu membuat URL untuk controller kita. Kita dapat melakukannya dengan menambahkan "routes", yang dikelola di direktori routes proyek Anda.
Karena kita menggunakan Livewire, kita hanya perlu mendefinisikan satu rute Route::get untuk menampilkan formulir pembuatan Chirp dan daftar Chirp yang sudah ada. Selain itu, kita akan menempatkan rute ini di balik dua middleware:
- Middleware
authmemastikan bahwa hanya pengguna yang sudah login yang dapat mengakses rute tersebut. - Middleware
verifiedakan digunakan jika Anda memutuskan untuk mengaktifkan verifikasi email.
<?php +use App\Http\Controllers\ChirpController; use Illuminate\Support\Facades\Route; Route::view('/', 'welcome');+ +Route::get('chirps', [ChirpController::class, 'index'])+ ->middleware(['auth', 'verified'])+ ->name('chirps'); Route::view('dashboard', 'dashboard') ->middleware(['auth', 'verified']) ->name('dashboard'); Route::view('profile', 'profile') ->middleware(['auth']) ->name('profile'); require __DIR__.'/auth.php';
Anda dapat melihat semua rute untuk aplikasi Anda dengan menjalankan perintah php artisan route:list.
Mari kita uji rute dan controller kita dengan mengembalikan pesan uji dari metode index di kelas ChirpController yang baru:
<?php namespace App\Http\Controllers; -use Illuminate\Http\Request; +use Illuminate\Http\Response; class ChirpController extends Controller {+ /**+ * Menampilkan daftar resource. + */+ public function index(): Response+ {+ return response('Halo, Dunia!');+ } }
Jika Anda masih dalam keadaan login dari langkah sebelumnya, Anda seharusnya melihat pesan tersebut saat membuka http://localhost:8000/chirps, atau http://localhost/chirps jika Anda menggunakan Sail!
Livewire
Belum terkesan? Mari perbarui metode index di kelas ChirpController kita untuk me-render tampilan (view) Blade:
<?php namespace App\Http\Controllers; -use Illuminate\Http\Response;+use Illuminate\View\View; class ChirpController extends Controller { /** * Menampilkan daftar resource. */- public function index(): Response+ public function index(): View {- return response('Halo, Dunia!');+ return view('chirps', [+ //+ ]); } }
Kita kemudian dapat membuat template Blade dan menyertakan komponen Livewire yang akan me-render formulir kita untuk membuat Chirp baru:
<x-app-layout> <div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8"> <livewire:chirps.create /> </div></x-app-layout>
Selanjutnya, mari kita buat komponen Livewire untuk me-render formulir tersebut. Untuk itu, Anda dapat menggunakan perintah Artisan make:volt.
Perhatikan bahwa potongan kode di bawah ini menawarkan dua cara berbeda untuk membuat komponen: satu menggunakan API Class dan yang lainnya menggunakan API Functional. Anda akan melihat kedua API tersebut di sepanjang tutorial ini, dan Anda dapat memilih gaya pengembangan Livewire yang Anda sukai:
php artisan make:volt chirps/create --class
php artisan make:volt chirps/create
Perintah ini akan membuat komponen Livewire baru di resources/views/livewire/chirps/create.blade.php.
Mari kita perbarui komponen Livewire tersebut untuk menampilkan formulir:
<?php use Livewire\Volt\Component; new class extends Component {+ public string $message = ''; }; ?> <div>- // + <form wire:submit="store"> + <textarea+ wire:model="message"+ placeholder="{{ __('What\'s on your mind?') }}"+ class="block w-full border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm"+ ></textarea>+ + <x-input-error :messages="$errors->get('message')" class="mt-2" />+ <x-primary-button class="mt-4">{{ __('Chirp') }}</x-primary-button>+ </form> </div>
<?php use function Livewire\Volt\{state}; +state(['message' => '']); ?> <div>- // + <form wire:submit="store"> + <textarea+ wire:model="message"+ placeholder="{{ __('What\'s on your mind?') }}"+ class="block w-full border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm"+ ></textarea>+ + <x-input-error :messages="$errors->get('message')" class="mt-2" />+ <x-primary-button class="mt-4">{{ __('Chirp') }}</x-primary-button>+ </form> </div>
Selesai! Segarkan halaman di peramban Anda untuk melihat formulir baru Anda yang di-render dalam tata letak (layout) default yang disediakan oleh Breeze!
Jika tangkapan layar Anda tidak terlihat persis seperti di atas, Anda mungkin perlu menghentikan dan menjalankan kembali server pengembangan Vite agar Tailwind dapat mendeteksi kelas CSS di berkas baru yang baru saja kita buat.
Mulai saat ini, setiap perubahan yang kita buat pada template Blade akan secara otomatis disegarkan di peramban kapan pun server pengembangan Vite berjalan melalui npm run dev.
Menu navigasi
Mari kita luangkan waktu sejenak untuk menambahkan tautan ke menu navigasi yang disediakan oleh Breeze.
Perbarui komponen navigation.blade.php yang disediakan oleh Breeze untuk menambahkan item menu untuk layar desktop:
<div class="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex"> <x-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')" wire:navigate> {{ __('Dashboard') }} </x-nav-link>+ <x-nav-link :href="route('chirps')" :active="request()->routeIs('chirps')" wire:navigate>+ {{ __('Chirps') }}+ </x-nav-link> </div>
Dan juga untuk layar mobile:
<div class="pt-2 pb-3 space-y-1"> <x-responsive-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')" wire:navigate> {{ __('Dashboard') }} </x-responsive-nav-link>+ <x-responsive-nav-link :href="route('chirps')" :active="request()->routeIs('chirps')" wire:navigate>+ {{ __('Chirps') }}+ </x-responsive-nav-link> </div>
Menyimpan Chirp
Formulir kita telah dikonfigurasi untuk memanggil aksi store saat tombol Chirp diklik. Mari tambahkan aksi store ke komponen chirps.create kita untuk memvalidasi data dan membuat Chirp baru.
<?php +use Livewire\Attributes\Validate; use Livewire\Volt\Component; new class extends Component {+ #[Validate('required|string|max:255')] public string $message = '';+ + public function store(): void+ {+ $validated = $this->validate();+ + auth()->user()->chirps()->create($validated);+ + $this->message = '';+ } }; ?> <div> <form wire:submit="store"> <textarea wire:model="message" placeholder="{{ __('What\'s on your mind?') }}" class="block w-full border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm" ></textarea> <x-input-error :messages="$errors->get('message')" class="mt-2" /> <x-primary-button class="mt-4">{{ __('Chirp') }}</x-primary-button> </form> </div>
<?php -use function Livewire\Volt\{state};+use function Livewire\Volt\{rules, state}; state(['message' => '']);+ +rules(['message' => 'required|string|max:255']);+ +$store = function () {+ $validated = $this->validate();+ + auth()->user()->chirps()->create($validated);+ + $this->message = '';+}; ?> <div> <form wire:submit="store"> <textarea wire:model="message" placeholder="{{ __('What\'s on your mind?') }}" class="block w-full border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm" ></textarea> <x-input-error :messages="$errors->get('message')" class="mt-2" /> <x-primary-button class="mt-4">{{ __('Chirp') }}</x-primary-button> </form> </div>
Dengan menggunakan atribut Validate milik Livewire, kita memanfaatkan fitur validasi Laravel yang kuat untuk memastikan pengguna memberikan pesan yang tidak melebihi batas 255 karakter dari kolom database yang akan kita buat.
Kita kemudian membuat catatan yang akan dimiliki oleh pengguna yang sedang login dengan memanfaatkan relasi chirps. Kita akan mendefinisikan relasi tersebut segera.
Terakhir, kita juga mengosongkan nilai kolom formulir message.
Membuat relasi
Anda mungkin telah memperhatikan pada langkah sebelumnya bahwa kita memanggil metode chirps pada objek auth()->user(). Kita perlu membuat metode ini pada model User kita untuk mendefinisikan relasi "has many":
<?php
namespace App\Models; // use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Factories\HasFactory;+use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Laravel\Sanctum\HasApiTokens; class User extends Authenticatable {
use HasApiTokens, HasFactory, Notifiable; /** * Atribut-atribut yang dapat di-assign secara massal. * * @var array<int, string> */ protected $fillable = [ 'name', 'email', 'password', ]; /** * Atribut-atribut yang harus disembunyikan untuk serialisasi. * * @var array<int, string> */ protected $hidden = [ 'password', 'remember_token', ]; /** * Atribut-atribut yang perlu diubah tipenya (casting). * * @return array<string, string> */ protected function casts(): array { return [ 'email_verified_at' => 'datetime', 'password' => 'hashed', ]; } + public function chirps(): HasMany+ {+ return $this->hasMany(Chirp::class);+ } }
Laravel menawarkan banyak jenis relasi model yang berbeda yang dapat Anda baca lebih lanjut di dokumentasi relasi Eloquent.
Perlindungan mass assignment
Melewatkan/mengoper semua data dari sebuah permintaan (request) ke model Anda bisa berisiko. Bayangkan Anda memiliki halaman di mana pengguna dapat mengedit profil mereka. Jika Anda mengoper seluruh request ke model, maka pengguna bisa mengedit kolom apa pun yang mereka suka, seperti kolom is_admin. Ini disebut kerentanan mass assignment.
Laravel melindungi Anda agar tidak sengaja melakukan hal ini dengan memblokir mass assignment secara default. Walau begitu, mass assignment tetap nyaman, karena mencegah Anda menetapkan setiap atribut satu per satu. Kita dapat mengaktifkan mass assignment untuk atribut yang aman dengan menandainya sebagai "fillable".
Mari tambahkan properti $fillable ke model Chirp kita untuk mengaktifkan mass-assignment untuk atribut message:
<?php
namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Chirp extends Model {
use HasFactory; + protected $fillable = [+ 'message',+ ]; }
Anda dapat mempelajari lebih lanjut tentang perlindungan mass assignment milik Laravel di dokumentasi.
Memperbarui migrasi
Selama pembuatan aplikasi, Laravel sudah menerapkan migrasi default yang disertakan dalam direktori database/migrations. Anda dapat memeriksa struktur database saat ini menggunakan perintah php artisan db:show dan php artisan db:table:
php artisan db:showphp artisan db:table users
Jadi, satu-satunya hal yang kurang adalah kolom tambahan di database kita untuk menyimpan relasi antara Chirp dan User-nya serta pesan itu sendiri. Ingat migrasi database yang kita buat tadi? Saatnya membuka berkas tersebut untuk menambahkan beberapa kolom tambahan:
<?php
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { /** * Menjalankan migrasi. */ public function up(): void { Schema::create('chirps', function (Blueprint $table) { $table->id();+ $table->foreignId('user_id')->constrained()->cascadeOnDelete();+ $table->string('message'); $table->timestamps(); }); }
/** * Mengembalikan migrasi. */ public function down(): void { Schema::dropIfExists('chirps'); } };
Kita belum melakukan migrasi database sejak menambahkan migrasi ini, jadi mari kita lakukan sekarang:
php artisan migrate
Setiap migrasi database hanya akan dijalankan sekali. Untuk melakukan perubahan tambahan pada tabel, Anda perlu membuat migrasi lain. Selama pengembangan, Anda mungkin ingin memperbarui migrasi yang belum di-deploy dan membangun ulang database Anda dari awal menggunakan perintah php artisan migrate:fresh.
Coba sekarang
Kita sekarang siap untuk mengirim Chirp menggunakan formulir yang baru saja kita buat! Kita belum bisa melihat hasilnya karena kita belum menampilkan Chirp yang ada di halaman.
Jika Anda mengosongkan kolom pesan, atau memasukkan lebih dari 255 karakter, Anda akan melihat validasi bekerja.
Artisan Tinker
Ini adalah saat yang tepat untuk mempelajari Artisan Tinker, sebuah REPL (Read-eval-print loop) di mana Anda dapat mengeksekusi kode PHP apa pun di aplikasi Laravel Anda.
Di konsol Anda, mulai sesi tinker baru:
php artisan tinker
Selanjutnya, jalankan kode berikut untuk menampilkan Chirp yang ada di database Anda:
App\Models\Chirp::all();
=> Illuminate\Database\Eloquent\Collection {#4512 all: [ App\Models\Chirp {#4514 id: 1, user_id: 1, message: "Aku membangun Chirper dengan Laravel!", created_at: "2022-08-24 13:37:00", updated_at: "2022-08-24 13:37:00", }, ], }
Anda dapat keluar dari Tinker dengan menggunakan perintah exit, atau dengan menekan Ctrl + c.