Seri 11 Belajar Laravel 10 dari Nol || Merefaktor/memperbaiki List Produk

 

Refaktor List Produk

Banyak hal yang dapat diperbaiki dalam kode sebelumnya. Sebagai contoh, kita akan melakukan refaktor pada model Produk, ProductController, dan View produk. Perubahan ini akan membuat kode kita lebih mudah dikelola, dimengerti, dan bersih. Sekali lagi, banyak dari perubahan ini berlaku tidak hanya untuk proyek Laravel tetapi juga merupakan tips umum yang dapat diadopsi dalam sebagian besar kerangka kerja MVC.


Atribut Model

Buka file model Produk dan coba tebak hanya dengan melihat file tersebut, atribut model Produk apa saja yang ada. Kita memiliki masalah di sini. Kita tidak bisa mengetahui atribut model Produk secara langsung. Kita harus melihat di dalam migrasi "create products table" atau membuka phpMyAdmin dan pergi ke tabel produk hanya untuk menemukan jawabannya. Menurut pendapat kami, cara desain model Produk memengaruhi keberpahaman proyek. Banyak kerangka kerja MVC lain, seperti Django (Python) atau Spring (Java), dengan jelas menentukan atribut produk mereka, tetapi hal itu tidak terjadi pada Laravel.

Masalah yang Diakibatkan:

  • Sulit memahami model: Developer perlu mencari informasi di tempat lain, seperti migrasi database atau phpMyAdmin, untuk mengetahui atribut model.
  • Kurang fleksibel: Model menjadi kurang fleksibel karena informasi penting tentang atributnya tidak terpusat.
  • Kurang self-documenting: Model tidak mendokumentasikan dirinya dengan baik, membuat kode menjadi lebih sulit dibaca dan dipahami.


Mari kita refaktor model Produk kita. Di app/Models/Product.php, lakukan perubahan berikut :



[code hl="1, 4, 7"] attributes['id'] - int - contains the product primary key (id) * $this->attributes['name'] - string - contains the product name * $this->attributes['description'] - string - contains the product description * $this->attributes['image'] - string - contains the product image * $this->attributes['price'] - int - contains the product price * $this->attributes['created_at'] - timestamp - contains the product creation date * $this->attributes['updated_at'] - timestamp - contains the product update date */ public function getId() { return $this->attributes['id']; } public function setId($id) { $this->attributes['id'] = $id; } public function getName() { return $this->attributes['name']; } public function setName($name) { $this->attributes['name'] = $name; } public function getDescription() { return $this->attributes['description']; } public function setDescription($description) { $this->attributes['description'] = $description; } public function getImage() { return $this->attributes['image']; } public function setImage($image) { $this->attributes['image'] = $image; } public function getPrice() { return $this->attributes['price']; } public function setPrice($price) { $this->attributes['price'] = $price; } public function getCreatedAt() { return $this->attributes['created_at']; } public function setCreatedAt($createdAt) { $this->attributes['created_at'] = $createdAt; } public function getUpdatedAt() { return $this->attributes['updated_at']; } public function setUpdatedAt($updatedAt) { $this->attributes['updated_at'] = $updatedAt; } } [/code]


Kita menghapus penggunaan trait HasFactory (yang berperan sebagai jembatan yang menghubungkan model Eloquent Anda dengan model factory yang sesuai). Model factories berguna untuk mengotomatiskan pembuatan catatan model palsu di database. Misalnya, ingatkah ketika kami mengeksekusi beberapa kueri SQL untuk memasukkan beberapa produk ke dalam database? Model factories dapat mengotomatiskan proses ini untuk kami. Namun, model factories berada di luar cakupan buku ini. Anda dapat menemukan informasi lebih lanjut tentang model factories di https://laravel.com/docs/9.x/database-testing#defining-model-factories

Terakhir, kita menyertakan blok komentar PHP yang menentukan atribut yang tersedia untuk model Produk. Seorang programmer yang membuka model Produk dapat dengan mudah menemukan atribut yang tersedia.

Kita telah mendeklarasikan atribut model dalam bentuk $this->attributes['id']. Hal ini karena Laravel Eloquent menyimpan atribut model dalam atribut array kelas yang disebut $attributes.


Periksa kode berikut untuk memahami bagaimana cara kerja atribut model Laravel Eloquent.


Dapatkan produk = Product::findOrFail(1);

echo $product->name; # mencetak nama produk

echo $product["name"]; # mencetak nama produk

Laravel Eloquent menyediakan dua cara untuk mengakses atribut model. Bentuk atribut objek ($product->name) dan bentuk array asosiatif ($product["name"]). Kedua pilihan ini secara internal mengakses model Produk dan mencari data $this->attributes['name']. Jika atribut tersebut tidak ada, maka akan mengembalikan null. Jika tidak, maka akan mengembalikan nilai yang disimpan dalam atribut array kelas ($attributes). Ssst, kami tidak akan menggunakan salah satu dari bentuk ini untuk mengakses atribut model. Kita akan menggunakan yang lebih baik, tetapi pertama-tama, mari kita lihat mengapa kami memerlukan cara yang lebih baik untuk mengakses atribut model.


Proyek Tanpa Getter dan Setter

Mari kita analisis kode saat ini. Ini adalah cuplikan dari file ProductController.php.



public function show($id)

{

$viewData = [];

$product = Product::findOrFail($id);

$viewData["title"] = $product["name"]." - Toko Online";

$viewData["subtitle"] = $product["name"]." - Informasi Produk";

$viewData["product"] = $product;

return view('product.show')->with("viewData", $viewData); }

Kita mengakses nama produk melalui bentuk array asosiatif ($product["name"]). Sekarang, mari kita analisis tampilan product/show.blade.php.


<div class="card-body">

<h5 class="card-title">

{{ $viewData["product"]["name"] }} (${{ $viewData["product"]["price"] }}) </h5>

<p class="card-text">{{ $viewData["product"]["description"] }}</p> <p class="card-text"><small class="text-muted">Tambahkan ke Keranjang</small></p>

</div>

Sekali lagi, kami mengakses nama produk melalui bentuk array asosiatif ($viewData["product"]["name"]). Apa masalahnya dengan mengakses data entitas ini dengan cara ini? Bayangkan bahwa bos Anda mengatakan, "Kita perlu menampilkan semua nama produk dalam huruf besar di seluruh aplikasi". Itu adalah masalah besar karena kami mengekstrak nama produk di berbagai tampilan dan controller yang berbeda. Persyaratan sederhana ini akan membuat kami harus memodifikasi beberapa tampilan dan controller. Untuk saat ini, mari lihat apa yang harus kami lakukan untuk mencapai persyaratan tersebut.

Kami harus memodifikasi controller ProductController.php sebagai berikut (jangan menerapkan perubahan ini, ini hanya digunakan untuk mengilustrasikan skenario ini):



public function show($id)

{

$viewData = [];

$product = Product::findOrFail($id);

$viewData["title"] = strtoupper($product["name"])." - Toko Online";

$viewData["subtitle"] = strtoupper($product["name"])." - Informasi Produk"; $viewData["product"] = $product;

return view('product.show')->with("viewData", $viewData); }

Dan tampilan product/show.blade.php seperti ini (jangan menerapkan perubahan ini, ini hanya digunakan untuk mengilustrasikan skenario ini):

<div class="card-body">

<h5 class="card-title">

{{ strtoupper($viewData["product"]["name"]) }} (${{ $viewData["product"]["price"] }}) </h5>

<p class="card-text">{{ $viewData["product"]["description"] }}</p> <p class="card-text"><small class="text-muted">Tambahkan ke Keranjang</small></p>

</div>

Ada dua masalah besar dengan strategi ini. (i) Kita memiliki banyak kode duplikat di seluruh aplikasi (fungsi strtoupper digunakan di beberapa tempat). Dan (ii) kami harus memeriksa semua controller, semua tampilan, dan mungkin puluhan atau ratusan file untuk memeriksa di mana kami perlu menerapkan fungsi strtoupper. Ini tidak dapat dipelihara. Jadi, mari refaktor/perbaiki kode kita untuk menerapkan strategi yang lebih baik.


Proyek dengan Getter dan Setter

Refaktor Model Produk

Pertama, mari refaktor model Produk kita. Di app/Models/Product.php, lakukan perubahan berikut dalam teks tebal.



class Product extends Model

{

public function getId()

{

return $this->attributes['id'];}

public function setId($id)

{

$this->attributes['id'] = $id;

}

public function getName()

{

return $this->attributes['name'];

}

public function setName($name)

{

$this->attributes['name'] = $name;

}

public function getDescription()

{

return $this->attributes['description'];

}

public function setDescription($description)

{

$this->attributes['description'] = $description;

}

public function getImage()

{

return $this->attributes['image'];

}

public function setImage($image)

{

$this->attributes['image'] = $image;

}

public function getPrice()

{

return $this->attributes['price'];

}

public function setPrice($price)

{

$this->attributes['price'] = $price;

}

public function getCreatedAt()

{

return $this->attributes['created_at'];

}

public function setCreatedAt($createdAt)

{

$this->attributes['created_at'] = $createdAt;

}

public function getUpdatedAt()

{

return $this->attributes['updated_at'];

}

public function setUpdatedAt($updatedAt)

{

$this->attributes['updated_at'] = $updatedAt;

}

}

Untuk setiap atribut Produk, kita mendefinisikan getter dan setter yang sesuai. Kita akan menggunakan getter dan setter untuk mengakses dan memodifikasi atribut model kami. Ini memiliki banyak keuntungan yang akan kita bicarakan nanti.

Refaktor ProductController

Di app/Http/Controllers/ProductController.php, lakukan perubahan berikut dalam teks tebal.


Analisis Kode...

public function show($id)

{

$viewData = [];

$product = Product::findOrFail($id);

$viewData["title"] = $product->getName()." - Toko Online";

$viewData["subtitle"] = $product->getName()." - Informasi Produk"; $viewData["product"] = $product;

return view('product.show')->with("viewData", $viewData); }

}

Sekarang, kami mengakses atribut produk melalui getter dan setter yang sesuai.

Refaktor tampilan product/index

Di resources/views/product/index.blade.php, lakukan perubahan berikut dalam teks tebal.


<div class="row">

@foreach ($viewData["products"] as $product)

<div class="col-md-4 col-lg-3 mb-2">

<div class="card">

<img src="{{ asset('/img/'.$product->getImage()) }}" class="card-img-top"> <div class="card-body text-center">

<a href="{{ route('product.show', ['id'=> $product->getId()]) }}"

 

class="btn bg-primary text-white">{{ $product->getName() }}</a>

</div> </div>

</div>

@endforeach </div>


Seperti controller sebelumnya, kami mengakses atribut produk melalui getter yang sesuai.

Refaktor tampilan product/show view

Di resources/views/product/show.blade.php, lakukan perubahan berikut dalam teks tebal.


<div class="row g-0">

<div class="col-md-4">

<img src="{{ asset('/img/'.$viewData["product"]->getImage()) }}" class="img-fluid rounded-start"> </div>

<div class="col-md-8">

<div class="card-body">

<h5 class="card-title">

{{ $viewData["product"]->getName() }} (${{ $viewData["product"]->getPrice() }}) </h5>

<p class="card-text">{{ $viewData["product"]->getDescription() }}</p> <p class="card-text"><small class="text-muted">Tambahkan ke Keranjang</small></p>

</div> </div>

</div>


Kita mengakses atribut produk melalui getter.

Menganalisis getter dan setter

Untuk saat ini, aplikasi terlihat sama. Kami hanya mengubah cara mengakses atribut model. Jadi, apa keuntungannya? Mari kita revisi kebutuhan bos: "kita perlu menampilkan semua nama produk dalam huruf besar di seluruh aplikasi".

Dalam kasus ini, kami hanya perlu memodifikasi file model Produk. Secara khusus, metode getName. Mari lihat modifikasi tersebut (Anda dapat menerapkan perubahan berikut atau biarkan seperti ini).



public function getName()

{

return strtoupper($this->attributes['name']); }


Jika Anda menjalankan aplikasi, Anda akan melihat bahwa semua nama produk muncul dalam huruf besar. Kita hanya memerlukan satu perubahan tunggal di satu lokasi tertentu. Itulah kekuatan penggunaan getter atau setter. Definisi dan penggunaan getter dan setter menjamin titik akses yang unik ke atribut model. Itu adalah bagian dari apa yang beberapa orang sebut enkapsulasi, salah satu dari tiga pilar pemrograman berorientasi objek.


TIPS: Selalu coba akses atribut model Anda melalui getter dan setter. Ini akan memudahkan menambahkan fungsionalitas di masa depan. Anda bahkan dapat menyertakan aturan baru yang menyatakan bahwa atribut model harus diakses melalui getter dan setter yang sesuai (dalam dokumen aturan arsitektur Anda).


Diskusi Singkat: Laravel menyediakan cara lain untuk mengimplementasikan getter dan setter. Laravel menyebutnya Accessors dan Mutators (Anda dapat membaca lebih lanjut tentang hal itu di https://laravel.com/docs/9.x/eloquent-mutators#accessors-and-mutators  Kita tidak memilih strategi ini karena alasan tunggal. Ketika Anda menggunakan Accessors dan Mutators dan mengakses atribut model, Anda tetap menggunakan bentuk asli (yaitu, $product->name) dibandingkan dengan bentuk getter klasik ($product->getName()). Kami lebih memilih yang kedua karena secara eksplisit menyatakan bahwa Anda mengakses data melalui metode kelas. Ini meningkatkan keberpahaman kode. Sebaliknya, para pemrogram harus pergi ke file model untuk memeriksa apakah Accessor diimplementasikan.


kita akan menggunakan getter dan setter klasik untuk sisa aplikasi. Kita harap Anda memahami pentingannya sekarang.


Menjalankan Aplikasi

Di Terminal, masuk ke direktori proyek, dan jalankan perintah berikut:

php artisan serve

Aplikasi seharusnya berfungsi dengan baik. Jika Anda menerapkan modifikasi pada metode getName, Anda akan melihat semua nama produk dalam huruf besar (lihat gambar).




IDIARSO
IDIARSO

Menulis adalah kegiatan saya disela rutinitas kerja,silahkan berkomentar dibawah ini sebagai bahan masukan

Tidak ada komentar:

Posting Komentar