03. Membuat Chirp
Anda sekarang siap untuk mulai membangun aplikasi baru Anda! Mari kita izinkan pengguna kita untuk mem-posting pesan singkat yang disebut Chirp.
Model, migrasi, dan controller
Untuk memungkinkan pengguna mem-posting Chirp, kita perlu membuat model, migrasi, dan controller. Mari kita jelajahi masing-masing konsep ini sedikit lebih dalam:
- Model menyediakan antarmuka yang handal dan menyenangkan bagi Anda untuk berinteraksi dengan tabel-tabel di database Anda.
- Migrasi memungkinkan Anda untuk membuat dan memodifikasi tabel di database dengan mudah. Migrasi memastikan struktur database yang sama ada di mana pun aplikasi Anda dijalankan.
- Controller bertanggung jawab untuk memproses permintaan yang masuk ke aplikasi Anda dan mengembalikan respons.
Hampir setiap fitur yang Anda bangun akan melibatkan semua bagian ini bekerja sama secara harmonis, sehingga perintah artisan make:model dapat membuat semuanya sekaligus untuk Anda.
Mari kita buat model, migrasi, dan resource controller untuk Chirp kita dengan perintah berikut:
php artisan make:model -mrc 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 milik 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 bisa melakukan ini dengan menambahkan "route", yang dikelola di direktori routes pada proyek Anda. Karena kita menggunakan resource controller, kita dapat menggunakan satu pernyataan Route::resource() untuk mendefinisikan semua rute mengikuti struktur URL konvensional.
Untuk memulai, kita akan mengaktifkan dua rute:
- Rute
indexakan menampilkan formulir dan daftar Chirp. - Rute
storeakan digunakan untuk menyimpan Chirp baru.
Kita juga akan menempatkan rute-rute ini di belakang 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 App\Http\Controllers\ProfileController; use Illuminate\Support\Facades\Route; Route::get('/', function () { return view('welcome'); }); Route::get('/dashboard', function () { return view('dashboard'); })->middleware(['auth', 'verified'])->name('dashboard'); Route::middleware('auth')->group(function () { Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit'); Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update'); Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy'); }); +Route::resource('chirps', ChirpController::class)+ ->only(['index', 'store'])+ ->middleware(['auth', 'verified']); require __DIR__.'/auth.php';
Ini akan membuat rute-rute berikut:
| Verb | URI | Action | Route Name |
|---|---|---|---|
| GET | /chirps |
index | chirps.index |
| POST | /chirps |
store | chirps.store |
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 App\Models\Chirp; use Illuminate\Http\Request; +use Illuminate\Http\Response; class ChirpController extends Controller { /** * Menampilkan daftar resource. */- public function index()+ public function index(): Response {- //+ return response('Halo, Dunia!'); }
/** * Menampilkan formulir untuk membuat resource baru. */ public function create() { // } /** * Menyimpan resource yang baru dibuat ke dalam penyimpanan. */ public function store(Request $request) { // } /** * Menampilkan resource yang dipilih/spesifik. */ public function show(Chirp $chirp) { // } /** * Menampilkan formulir untuk mengedit resource yang dipilih/spesifik. */ public function edit(Chirp $chirp) { // } /** * Memperbarui resource yang dipilih/spesifik di dalam penyimpanan. */ public function update(Request $request, Chirp $chirp) { // } /** * Menghapus resource yang dipilih/spesifik dari penyimpanan. */ public function destroy(Chirp $chirp) { // } }
Jika Anda masih dalam kondisi login, Anda seharusnya melihat pesan tersebut saat mengunjungi http://localhost:8000/chirps, atau http://localhost/chirps jika Anda menggunakan Sail!
Blade
Belum terkesan? Mari kita perbarui metode index pada kelas ChirpController kita untuk me-render view (sebutan untuk layer tampilan) Blade:
<?php
namespace App\Http\Controllers; use App\Models\Chirp; use Illuminate\Http\Request; 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.index'); }
/** * Menampilkan formulir untuk membuat resource baru. */ public function create() { // } /** * Menyimpan resource yang baru dibuat ke dalam penyimpanan. */ public function store(Request $request) { // } /** * Menampilkan resource yang dipilih/spesifik. */ public function show(Chirp $chirp) { // } /** * Menampilkan formulir untuk mengedit resource yang dipilih/spesifik. */ public function edit(Chirp $chirp) { // } /** * Memperbarui resource yang dipilih/spesifik di dalam penyimpanan. */ public function update(Request $request, Chirp $chirp) { // } /** * Menghapus resource yang dipilih/spesifik dari penyimpanan. */ public function destroy(Chirp $chirp) { // } }
Kita kemudian dapat membuat templat view Blade dengan formulir untuk membuat Chirp baru:
<x-app-layout> <div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8"> <form method="POST" action="{{ route('chirps.store') }}"> @csrf <textarea name="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" >{{ old('message') }}</textarea> <x-input-error :messages="$errors->get('message')" class="mt-2" /> <x-primary-button class="mt-4">{{ __('Chirp') }}</x-primary-button> </form> </div></x-app-layout>
Selesai! Segarkan halaman di peramban Anda untuk melihat formulir baru Anda di-render dalam 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 pada file yang baru saja kita buat.
Mulai dari titik ini, setiap perubahan yang kita buat pada templat Blade akan disegarkan secara otomatis di peramban setiap kali server pengembangan Vite berjalan melalui npm run dev.
Menu navigasi
Mari 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')"> {{ __('Dashboard') }} </x-nav-link>+ <x-nav-link :href="route('chirps.index')" :active="request()->routeIs('chirps.index')">+ {{ __('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')"> {{ __('Dashboard') }} </x-responsive-nav-link>+ <x-responsive-nav-link :href="route('chirps.index')" :active="request()->routeIs('chirps.index')">+ {{ __('Chirps') }}+ </x-responsive-nav-link> </div>
Menyimpan Chirp
Formulir kita telah dikonfigurasi untuk mem-posting pesan ke rute chirps.store yang kita buat tadi. Mari kita perbarui metode store pada kelas ChirpController kita untuk memvalidasi data dan membuat Chirp baru:
<?php
namespace App\Http\Controllers; use App\Models\Chirp;+use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Http\Response; use Illuminate\View\View; class ChirpController extends Controller {
/** * Menampilkan daftar resource. */ public function index(): View { return view('chirps.index'); } /** * Menampilkan formulir untuk membuat resource baru. */ public function create() { // } /** * Menyimpan resource yang baru dibuat ke dalam penyimpanan. */- public function store(Request $request)+ public function store(Request $request): RedirectResponse {- //+ $validated = $request->validate([+ 'message' => 'required|string|max:255',+ ]);+ + $request->user()->chirps()->create($validated);+ + return redirect(route('chirps.index')); }
/** * Menampilkan resource yang dipilih/spesifik. */ public function show(Chirp $chirp) { // } /** * Menampilkan formulir untuk mengedit resource yang dipilih/spesifik. */ public function edit(Chirp $chirp) { // } /** * Memperbarui resource yang dipilih/spesifik di dalam penyimpanan. */ public function update(Request $request, Chirp $chirp) { // } /** * Menghapus resource yang dipilih/spesifik dari penyimpanan. */ public function destroy(Chirp $chirp) { // } }
Kita menggunakan fitur validasi Laravel yang andal untuk memastikan bahwa pengguna memberikan pesan dan pesan tersebut 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 mengembalikan respons redirect untuk mengirim pengguna kembali ke rute chirps.index.
Membuat relasi
Anda mungkin memperhatikan pada langkah sebelumnya bahwa kita memanggil metode chirps pada objek $request->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 dapat Anda baca lebih lanjut di dokumentasi Eloquent Relationships.
Perlindungan mass assignment
Melewatkan/mengoper semua data dari 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 dapat mengedit kolom apa pun yang mereka suka, seperti kolom is_admin. Ini disebut kerentanan mass assignment.
Laravel melindungi Anda dari ketidaksengajaan 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 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 dengan menggunakan perintah php artisan db:show dan php artisan db:table:
php artisan db:showphp artisan db:table users
Jadi, satu-satunya yang kurang adalah kolom tambahan di database kita untuk menyimpan hubungan antara Chirp dan User-nya serta pesan itu sendiri. Ingat migrasi database yang kita buat sebelumnya? Saatnya membuka file 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 memigrasi database sejak kita menambahkan migrasi ini, jadi mari kita lakukan sekarang:
php artisan migrate
Setiap migrasi database hanya akan dijalankan satu kali. Untuk membuat 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 hasilnya
Kita sekarang siap untuk mengirim Chirp menggunakan formulir yang baru saja kita buat! Kita belum akan bisa melihat hasilnya karena kita belum menampilkan Chirp yang ada di halaman tersebut.
Jika Anda mengosongkan kolom pesan, atau memasukkan lebih dari 255 karakter, maka Anda akan melihat validasi bekerja.
Artisan Tinker
Ini adalah waktu yang tepat untuk mempelajari tentang 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, eksekusi kode berikut untuk menampilkan Chirps 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.