Saya hanya mendapatkan pemahaman tentang kerangka kerja MVC dan saya sering bertanya-tanya berapa banyak kode yang harus dimasukkan dalam model. Saya cenderung memiliki kelas akses data yang memiliki metode seperti ini:
public function CheckUsername($connection, $username)
{
try
{
$data = array();
$data['Username'] = $username;
//// SQL
$sql = "SELECT Username FROM" . $this->usersTableName . " WHERE Username = :Username";
//// Execute statement
return $this->ExecuteObject($connection, $sql, $data);
}
catch(Exception $e)
{
throw $e;
}
}
Model saya cenderung kelas entitas yang dipetakan ke tabel database.
Haruskah objek model memiliki semua properti database yang dipetakan serta kode di atas atau apakah OK untuk memisahkan kode yang sebenarnya berfungsi sebagai basis data?
Apakah saya akan memiliki empat lapisan?
php
oop
model-view-controller
architecture
model
Dietpixel
sumber
sumber
Exception
tidak memiliki banyak nilai dokumentasi. Secara pribadi jika saya turun di jalan itu saya akan memilih PHPDoc@exception
, atau mekanisme serupa, sehingga muncul di dokumentasi yang dihasilkan.Jawaban:
Hal pertama yang harus saya jelaskan adalah: modelnya adalah layer .
Kedua: ada perbedaan antara MVC klasik dan apa yang kami gunakan dalam pengembangan web. Inilah sedikit jawaban lama yang saya tulis, yang menjelaskan secara singkat bagaimana perbedaannya.
Apa yang BUKAN model:
Model ini bukan kelas atau objek apa pun. Ini adalah kesalahan yang sangat umum terjadi (saya juga melakukannya, meskipun jawaban aslinya ditulis ketika saya mulai belajar sebaliknya) , karena sebagian besar kerangka kerja melanggengkan kesalahpahaman ini.
Baik itu teknik Pemetaan Objek-Relasional (ORM) maupun abstraksi tabel database. Siapa pun yang memberi tahu Anda sebaliknya kemungkinan besar akan berusaha 'menjual' ORM baru atau seluruh kerangka kerja.
Apa itu model:
Dalam adaptasi MVC tepat, M berisi semua logika bisnis domain dan lapisan Model yang sebagian besar terbuat dari tiga jenis struktur:
Objek Domain
Ini adalah tempat Anda menentukan cara memvalidasi data sebelum mengirim faktur, atau menghitung total biaya pesanan. Pada saat yang sama, Objek Domain benar-benar tidak menyadari penyimpanan - baik dari mana (database SQL, REST API, file teks, dll.) Atau bahkan jika mereka disimpan atau diambil.
Pemetaan Data
Objek-objek ini hanya bertanggung jawab atas penyimpanan. Jika Anda menyimpan informasi dalam database, ini akan menjadi tempat tinggal SQL. Atau mungkin Anda menggunakan file XML untuk menyimpan data, dan Pemeta Data Anda menguraikan dari dan ke file XML.
Jasa
Anda dapat menganggapnya sebagai "Objek Domain tingkat tinggi", tetapi alih-alih logika bisnis, Layanan bertanggung jawab atas interaksi antara Objek Domain dan Pemetaan . Struktur ini pada akhirnya menciptakan antarmuka "publik" untuk berinteraksi dengan logika bisnis domain. Anda dapat menghindarinya, tetapi dengan membocorkan beberapa logika domain ke Controllers .
Ada jawaban terkait untuk subjek ini dalam pertanyaan implementasi ACL - mungkin berguna.
Komunikasi antara lapisan model dan bagian lain dari triad MVC harus terjadi hanya melalui Layanan . Pemisahan yang jelas memiliki beberapa manfaat tambahan:
Bagaimana cara berinteraksi dengan model?
Mendapatkan akses ke instance layanan
Agar instance View dan Controller (apa yang bisa Anda sebut: "lapisan UI") untuk mengakses layanan ini, ada dua pendekatan umum:
Seperti yang Anda duga, wadah DI adalah solusi yang jauh lebih elegan (meskipun bukan yang paling mudah bagi pemula). Kedua pustaka, yang saya rekomendasikan mempertimbangkan fungsi ini akan menjadi komponen mandiri DependencyInjection atau Auryn milik Syfmony .
Baik solusi menggunakan pabrik dan wadah DI akan memungkinkan Anda juga berbagi contoh berbagai server untuk dibagikan antara pengontrol yang dipilih dan melihat siklus permintaan-respons yang diberikan.
Perubahan status model
Sekarang Anda dapat mengakses ke lapisan model di pengontrol, Anda harus mulai benar-benar menggunakannya:
Pengontrol Anda memiliki tugas yang sangat jelas: ambil input pengguna dan, berdasarkan input ini, ubah status logika bisnis saat ini. Dalam contoh ini negara yang diubah antara adalah "pengguna anonim" dan "pengguna masuk".
Pengontrol tidak bertanggung jawab untuk memvalidasi input pengguna, karena itu adalah bagian dari aturan bisnis dan pengontrol jelas tidak memanggil permintaan SQL, seperti apa yang akan Anda lihat di sini atau di sini (jangan membenci mereka, mereka salah arah, bukan jahat).
Menampilkan pengguna perubahan-negara.
Oke, pengguna telah login (atau gagal). Sekarang apa? Kata pengguna masih tidak menyadarinya. Jadi, Anda harus benar-benar menghasilkan respons dan itu adalah tanggung jawab pandangan.
Dalam kasus ini, tampilan menghasilkan salah satu dari dua kemungkinan respons, berdasarkan kondisi lapisan model saat ini. Untuk kasus penggunaan yang berbeda, Anda akan memiliki pandangan memilih template yang berbeda untuk di-render, berdasarkan sesuatu seperti "artikel yang dipilih saat ini".
Lapisan presentasi sebenarnya bisa sangat rumit, seperti dijelaskan di sini: Memahami Tampilan MVC di PHP .
Tapi saya hanya membuat API REST!
Tentu saja, ada beberapa situasi, ketika ini adalah pembunuhan yang berlebihan.
MVC hanyalah solusi konkret untuk prinsip Pemisahan Kekhawatiran . MVC memisahkan antarmuka pengguna dari logika bisnis, dan di UI memisahkan pemisahan input pengguna dan presentasi. Ini sangat penting. Walaupun sering orang menggambarkannya sebagai "triad", itu sebenarnya tidak terdiri dari tiga bagian independen. Strukturnya lebih seperti ini:
Ini berarti, bahwa, ketika logika lapisan presentasi Anda hampir tidak ada, pendekatan pragmatis adalah menjaganya sebagai lapisan tunggal. Itu juga secara substansial dapat menyederhanakan beberapa aspek lapisan model.
Menggunakan pendekatan ini contoh login (untuk API) dapat ditulis sebagai:
Meskipun ini tidak berkelanjutan, ketika Anda memiliki logika yang rumit untuk merender badan respons, penyederhanaan ini sangat berguna untuk skenario yang lebih sepele. Tetapi berhati-hatilah , pendekatan ini akan menjadi mimpi buruk, ketika mencoba untuk digunakan dalam basis kode besar dengan logika presentasi yang kompleks.
Bagaimana cara membangun model?
Karena tidak ada satu kelas "Model" (seperti dijelaskan di atas), Anda benar-benar tidak "membangun model". Alih-alih, Anda mulai membuat Layanan , yang dapat melakukan metode tertentu. Dan kemudian mengimplementasikan Objek Domain dan Pemetaan .
Contoh metode layanan:
Dalam kedua pendekatan di atas ada metode login ini untuk layanan identifikasi. Seperti apa bentuknya sebenarnya. Saya menggunakan versi yang sedikit dimodifikasi dari fungsi yang sama dari perpustakaan , yang saya tulis .. karena saya malas:
Seperti yang Anda lihat, pada tingkat abstraksi ini, tidak ada indikasi dari mana data itu diambil. Mungkin database, tetapi juga mungkin hanya obyek tiruan untuk tujuan pengujian. Bahkan pemetaan data, yang sebenarnya digunakan untuk itu, disembunyikan dalam
private
metode layanan ini.Cara membuat pemetaan
Untuk mengimplementasikan abstraksi kegigihan, pendekatan yang paling fleksibel adalah membuat pemetaan data khusus .
Dari: PoEAA Buku
Dalam praktiknya mereka diimplementasikan untuk interaksi dengan kelas atau superclasses tertentu. Katakanlah Anda memiliki
Customer
danAdmin
dalam kode Anda (keduanya mewarisi dariUser
superclass). Keduanya mungkin akhirnya memiliki mapper yang cocok dan terpisah, karena mengandung bidang yang berbeda. Tetapi Anda juga akan berakhir dengan operasi bersama dan umum digunakan. Misalnya: memperbarui "yang terakhir terlihat online" . Dan alih-alih membuat pemetaan yang ada menjadi lebih berbelit-belit, pendekatan yang lebih pragmatis adalah memiliki "Pengguna Mapper" umum, yang hanya memperbarui stempel waktu itu.Beberapa komentar tambahan:
Tabel dan model basis data
Meskipun kadang-kadang ada hubungan langsung 1: 1: 1 antara tabel database, Domain Object , dan Mapper , dalam proyek yang lebih besar mungkin lebih jarang terjadi daripada yang Anda harapkan:
Informasi yang digunakan oleh objek Domain tunggal mungkin dipetakan dari tabel yang berbeda, sedangkan objek itu sendiri tidak memiliki kegigihan dalam database.
Contoh: jika Anda menghasilkan laporan bulanan. Ini akan mengumpulkan informasi dari berbagai tabel, tetapi tidak ada
MonthlyReport
tabel ajaib dalam database.Seorang Mapper tunggal dapat memengaruhi banyak tabel.
Contoh: saat Anda menyimpan data dari
User
objek, Objek Domain ini dapat berisi kumpulan objek domain lainnya -Group
instance. Jika Anda mengubahnya dan menyimpannyaUser
, Data Mapper harus memperbarui dan / atau memasukkan entri dalam beberapa tabel.Data dari Objek Domain tunggal disimpan di lebih dari satu tabel.
Contoh: dalam sistem besar (pikirkan: jaringan sosial berukuran sedang), mungkin pragmatis untuk menyimpan data autentikasi pengguna dan data yang sering diakses secara terpisah dari potongan konten yang lebih besar, yang jarang diperlukan. Dalam hal ini Anda mungkin masih memiliki satu
User
kelas, tetapi informasi yang dikandungnya akan bergantung pada apakah rincian lengkap diambil.Untuk setiap Objek Domain, mungkin ada lebih dari satu mapper
Contoh: Anda memiliki situs berita dengan basis kode bersama untuk perangkat lunak manajemen publik dan publik. Tapi, sementara kedua antarmuka menggunakan
Article
kelas yang sama , manajemen membutuhkan lebih banyak info yang terisi di dalamnya. Dalam hal ini Anda akan memiliki dua pemetaan yang terpisah: "internal" dan "eksternal". Setiap melakukan kueri yang berbeda, atau bahkan menggunakan basis data yang berbeda (seperti pada master atau slave).Tampilan bukan templat
Lihat contoh di MVC (jika Anda tidak menggunakan variasi pola MVP) bertanggung jawab untuk logika presentasi. Ini berarti bahwa setiap Tampilan biasanya akan menyulap setidaknya beberapa templat. Ia memperoleh data dari Model Layer dan kemudian, berdasarkan informasi yang diterima, memilih templat dan menetapkan nilai.
Salah satu manfaat yang Anda peroleh dari hal ini adalah penggunaan kembali. Jika Anda membuat
ListView
kelas, maka, dengan kode yang ditulis dengan baik, Anda dapat memiliki kelas yang sama menyerahkan presentasi daftar pengguna dan komentar di bawah artikel. Karena mereka berdua memiliki logika presentasi yang sama. Anda cukup mengganti templat.Anda bisa menggunakan templat PHP asli atau menggunakan mesin templating pihak ketiga. Mungkin juga ada beberapa perpustakaan pihak ketiga, yang dapat sepenuhnya menggantikan Lihat contoh.
Bagaimana dengan versi lama dari jawabannya?
Satu-satunya perubahan besar adalah bahwa, apa yang disebut Model dalam versi lama, sebenarnya adalah Layanan . Sisa dari "analogi perpustakaan" terus berjalan dengan baik.
Satu-satunya kelemahan yang saya lihat adalah bahwa ini akan menjadi perpustakaan yang benar-benar aneh, karena itu akan mengembalikan Anda informasi dari buku itu, tetapi tidak membiarkan Anda menyentuh buku itu sendiri, karena kalau tidak abstraksi akan mulai "bocor". Saya mungkin harus memikirkan analogi yang lebih pas.
Apa hubungan antara instance View dan Controller ?
Struktur MVC terdiri dari dua lapisan: ui dan model. Struktur utama pada lapisan UI adalah view dan controller.
Saat Anda berurusan dengan situs web yang menggunakan pola desain MVC, cara terbaik adalah memiliki hubungan 1: 1 antara tampilan dan pengontrol. Setiap tampilan mewakili seluruh halaman di situs web Anda dan memiliki pengontrol khusus untuk menangani semua permintaan yang masuk untuk tampilan tertentu.
Misalnya, untuk mewakili artikel yang dibuka, Anda harus
\Application\Controller\Document
dan\Application\View\Document
. Ini akan berisi semua fungsi utama untuk lapisan UI, ketika berurusan dengan artikel (tentu saja Anda mungkin memiliki beberapa komponen XHR yang tidak terkait langsung dengan artikel) .sumber
Segala sesuatu yang merupakan logika bisnis termasuk dalam model, apakah itu permintaan basis data, perhitungan, panggilan REST, dll.
Anda dapat memiliki akses data dalam model itu sendiri, pola MVC tidak membatasi Anda untuk melakukan itu. Anda dapat menambahkannya dengan layanan, pemetaan dan yang tidak, tetapi definisi sebenarnya dari sebuah model adalah lapisan yang menangani logika bisnis, tidak lebih, tidak kurang. Itu bisa berupa kelas, fungsi, atau modul lengkap dengan trilyun objek jika itu yang Anda inginkan.
Itu selalu lebih mudah untuk memiliki objek terpisah yang benar-benar mengeksekusi query database daripada mengeksekusi mereka dalam model secara langsung: ini akan sangat berguna ketika pengujian unit (karena kemudahan menyuntikkan ketergantungan database tiruan dalam model Anda):
Juga, dalam PHP, Anda jarang perlu menangkap / rethrow pengecualian karena backtrace dipertahankan, terutama dalam kasus seperti contoh Anda. Biarkan saja pengecualiannya dilempar dan tangkap di controller saja.
sumber
User
class pada dasarnya meluas model, tapi itsn't obyek. Pengguna harus menjadi objek dan memiliki properti seperti: id, nama ... Anda menyebarkanUser
kelas adalah bantuan.User
singkatan dari objek, dan itu harus memiliki properti Pengguna, bukan metode sepertiCheckUsername
, apa yang harus Anda lakukan jika Anda ingin membuatUser
objek baru ?new User($db)
Di Web- "MVC" Anda dapat melakukan apa saja sesuka Anda.
Konsep asli (1) menggambarkan model sebagai logika bisnis. Itu harus mewakili negara aplikasi dan menegakkan beberapa konsistensi data. Pendekatan itu sering digambarkan sebagai "model gemuk".
Sebagian besar kerangka kerja PHP mengikuti pendekatan yang lebih dangkal, di mana model hanyalah antarmuka basis data. Tetapi setidaknya model-model ini masih harus memvalidasi data yang masuk dan hubungan.
Either way, Anda tidak terlalu jauh jika Anda memisahkan hal-hal SQL atau panggilan basis data ke lapisan lain. Dengan cara ini Anda hanya perlu memusatkan perhatian pada data / perilaku nyata, bukan dengan API penyimpanan yang sebenarnya. (Namun tidak masuk akal untuk melakukannya secara berlebihan. Misalnya Anda tidak akan pernah bisa mengganti database backend dengan penyimpanan file jika itu tidak dirancang sebelumnya.)
sumber
Lebih sering sebagian besar aplikasi akan memiliki data, tampilan dan bagian pemrosesan dan kami hanya memasukkan semua itu dalam surat
M
,V
danC
.Model (
M
) -> Memiliki atribut yang memiliki status aplikasi dan tidak tahu apa-apa tentangV
danC
.Lihat (
V
) -> Memiliki format tampilan untuk aplikasi dan dan hanya tahu tentang cara mencerna model di atasnya dan tidak peduliC
.Controller (
C
) ----> Memproses bagian aplikasi dan bertindak sebagai kabel antara M dan V dan itu tergantung pada keduanyaM
,V
tidak sepertiM
danV
.Secara keseluruhan ada pemisahan perhatian di antara masing-masing. Di masa depan setiap perubahan atau peningkatan dapat ditambahkan dengan sangat mudah.
sumber
Dalam kasus saya, saya memiliki kelas database yang menangani semua interaksi database langsung seperti permintaan, pengambilan, dan semacamnya. Jadi jika saya harus mengubah database saya dari MySQL ke PostgreSQL tidak akan ada masalah. Jadi menambahkan lapisan tambahan itu bisa bermanfaat.
Setiap tabel dapat memiliki kelas sendiri dan memiliki metode spesifik, tetapi untuk benar-benar mendapatkan data, itu memungkinkan kelas database menanganinya:
Mengajukan
Database.php
Tabel objek kelasL
Saya harap contoh ini membantu Anda membuat struktur yang baik.
sumber
Database
dalam contoh ini bukan kelas. Itu hanya pembungkus untuk fungsi. Juga, bagaimana Anda bisa memiliki "kelas objek tabel" tanpa objek?