MVC + Skenario vs. Pengontrol Tebal
Kerangka kerja PHP modern (Symphony, Laravel, selanjutnya di mana-mana) secara meyakinkan menunjukkan bahwa menerapkan pola Model-View-Controller tidak begitu sederhana. Semua implementasi karena alasan tertentu rentan terhadap Fat Controllers ( fat controllers
), dikutuk oleh semua, dan pengembang, dan kerangka kerja itu sendiri.
Kenapa begitu? Dan adakah cara untuk menangani ini? Mari kita perbaiki.
Terminologi
- Model - model (pembentuk data yang diminta)
- Lihat - lihat (dekorator data model)
- Controller - controller (koordinator model-view seperti yang diminta)
- Templat - templat presentasi
- Rendering - rendering (pembentukan, desain gambar presentasi)
- Renderer - renderer (pembentuk, perancang gambar presentasi)
Pengontrol tebal
Berikut ini adalah Fat Controller khas:
class UserController { public function actionUserHello($userId) {
Apa yang kita lihat Kami melihat vinaigrette! Dalam controller semua yang mungkin dicampur - baik model, dan presentasi, dan, pada kenyataannya, controller itu sendiri!
Kita melihat nama-nama model dan templat dengan erat terhubung ke controller. Ini bukan buzz. Kami melihat manipulasi dengan data model di controller - pembentukan nama lengkap dari nama depan dan belakang. Dan ini bukan buzz.
Dan satu hal lagi: kita tidak melihat contoh ini secara eksplisit, tetapi implisit. Yaitu: hanya ada satu cara rendering (pembentukan gambar)! Hanya satu: sesuai dengan templat di file php! Dan jika saya ingin pdf? Dan jika saya ingin tidak dalam file, tetapi dalam baris php? Saya memiliki desain dengan desain rumit pada ratusan templat kecil. Saya sendiri harus mengatakan renderer untuk templat string. Saya tidak terlalu panas tentu saja, tetapi masalah ini pada prinsipnya.
Ringkasan singkat:
Kerangka kerja modern memiliki kelemahan umum dalam implementasi MVC untuk semua orang:
- Interpretasi sempit tampilan MVC (Tampilan) hanya sebagai "Lihat dengan templat dalam file PHP" dan bukan "Lihat dengan penyaji apa pun . "
- Interpretasi sempit dari model-MVC hanya sebagai "Domain Model Domain" dan bukannya "Setiap kompiler data untuk presentasi . "
- Mereka memprovokasi penggunaan apa yang disebut "Pengontrol Tebal" yang mengandung semua logika pada saat yang sama: bisnis, presentasi dan interaksi. Ini sepenuhnya menghancurkan tujuan utama MVC - pembagian tanggung jawab antara komponen triad.
Untuk mengatasi kekurangan ini, alangkah baiknya untuk melihat lebih dekat komponen-komponen MVC.
Lihat adalah penyaji
Lihatlah kelemahan pertama:
- Interpretasi sempit tampilan MVC (Tampilan) hanya sebagai "Lihat dengan templat dalam file PHP" alih-alih "Lihat dengan penyaji apa pun . "
Di sini, semuanya cukup sederhana - solusi untuk masalah sudah ditunjukkan dalam perumusan masalah. Kami hanya harus mengatakan bahwa penyaji mana pun dapat menggunakan tampilan. Untuk mengimplementasikan ini, cukup tambahkan properti renderer
baru ke kelas View:
class View { public $template, $data, $renderer; public function __costruct($template, $data, $renderer = NULL) {} }
Jadi, kami telah mendefinisikan properti renderer
baru untuk tampilan. Dalam kasus yang paling umum, nilai properti ini dapat berupa fungsi yang dapat callable
yang membentuk gambar dari data yang ditransfer ke dalamnya menggunakan templat yang dikirim.
Sebagian besar aplikasi hanya menggunakan satu renderer, dan bahkan jika mereka menggunakan beberapa, salah satunya lebih disukai. Oleh karena itu, argumen renderer
didefinisikan sebagai opsional, dengan asumsi ada beberapa renderer default.
Apakah ini sederhana? Sederhana Sebenarnya tidak sesederhana itu. Faktanya adalah bahwa View
yang ada di MVC tidak persis View
yang ada dalam framework. View
yang ada di dalam kerangka tidak bisa hidup tanpa templat. Tapi View
, yang di MVC, untuk beberapa alasan tidak tahu apa-apa tentang template yang sama ini. Mengapa Ya, karena untuk MVC View
, ini adalah konverter data model apa pun menjadi gambar , dan bukan hanya mesin templat. Ketika kami menulis sesuatu seperti ini di penangan permintaan:
$name = ' '; return "Hello, {$name}!";
atau bahkan:
$return json_encode($name);
maka kita benar-benar mendefinisikan View
yang ada di MVC, tanpa menyentuh View
yang ada di framework!
Tapi sekarang semuanya sangat sederhana: View
, yang dalam kerangka - ini adalah bagian dari View
, yang ada di MVC. Selain itu, subset yang sangat sempit, yaitu, hanya mesin template yang didasarkan pada file PHP.
Ringkasan: itu adalah
, mis. dekorator gambar data apa pun adalah View
yang ada di MVC. Dan View
, yang ada di dalam kerangka kerja, hanyalah semacam
.
Model Domain / Model Tampilan (ViewModel / DomainModel)
Sekarang lihat kelemahan kedua:
- Interpretasi sempit dari model-MVC hanya sebagai "Domain Model Domain" dan bukannya "Setiap kompiler data untuk presentasi . "
Jelas bagi semua orang bahwa model MVC adalah hal yang kompleks yang terdiri dari bagian lain. Komunitas setuju untuk menguraikan model menjadi dua komponen: model domain (DomainModel) dan model presentasi (ViewModel).
Model domain adalah apa yang disimpan dalam basis data, mis. data model dinormalisasi. Ketik, 'nama depan' dan 'nama belakang' di berbagai bidang. Kerangka kerja ditempati dengan bagian tertentu dari model hanya karena penyimpanan data adalah alam semesta sendiri, dipelajari dengan baik.
Namun, aplikasi membutuhkan data agregat daripada normal. Data domain harus dikompilasi menjadi gambar seperti: "Halo, Ivan!", Atau "Dear Ivan Petrov!", Atau bahkan "Untuk Ivan a Petrov a !". Data yang dikonversi ini dirujuk ke model lain - model presentasi. Jadi inilah bagian dari model yang masih diabaikan oleh kerangka kerja modern. Itu diabaikan karena tidak ada kesepakatan tentang bagaimana menghadapinya. Dan jika kerangka kerja tidak memberikan solusi, maka programmer pergi dengan cara paling sederhana - mereka membuang model tampilan ke dalam pengontrol. Dan mereka mendapatkan Pengontrol Lemak yang dibenci tetapi tak terhindarkan!
Intinya: untuk mengimplementasikan MVC, Anda perlu menerapkan model tampilan. Tidak ada pilihan lain. Mengingat bahwa representasi dan datanya dapat berupa apa saja, kami menyatakan bahwa kami memiliki masalah.
Skenario vs. Pengontrol Lemak
Ada satu kelemahan terakhir dari kerangka kerja:
- Mereka memprovokasi penggunaan apa yang disebut "Pengontrol Tebal" yang mengandung semua logika pada saat yang sama: bisnis, presentasi dan interaksi. Ini sepenuhnya menghancurkan tujuan utama MVC - pembagian tanggung jawab antara komponen triad.
Di sini kita sampai pada dasar-dasar MVC. Mari kita perjelas. Jadi, MVC mengasumsikan distribusi tanggung jawab berikut antara komponen-komponen triad:
- Pengontrol adalah logika interaksi , mis. interaksi dengan dunia luar (permintaan - respons) dan internal (Model - Presentasi),
- Modelnya adalah logika bisnis , mis. menghasilkan data untuk permintaan tertentu,
- Representasi adalah logika representasi , mis. dekorasi data yang dihasilkan oleh Model.
Silakan. Dua tingkat tanggung jawab terlihat jelas:
- Tingkat organisasi adalah Pengendali,
- Tingkat eksekutif adalah Model dan Representasi.
Secara sederhana, Controller mengarahkan, Model, dan View bajak. Ini jika dengan cara sederhana. Dan jika tidak dengan cara yang sederhana, tetapi lebih khusus? Bagaimana tepatnya pengendali mengarahkan? Dan bagaimana tepatnya Model dan View membajak?
Kontroler mengarahkan seperti ini:
- Menerima permintaan dari aplikasi,
- Tentukan Model dan Tampilan mana yang akan digunakan untuk permintaan ini,
- Panggilan Model yang dipilih dan menerima data dari itu,
- Meminta Tampilan yang dipilih dengan data yang diterima dari Model,
- Mengembalikan data yang didekorasi oleh View kembali ke aplikasi.
Sesuatu seperti itu. Hal penting dalam skema ini adalah Model dan Representasi berubah menjadi tautan dalam rantai eksekusi permintaan. Selain itu, dengan tautan berurutan: pertama, Model mengubah permintaan menjadi beberapa data, kemudian data Model ini dikonversi oleh View menjadi jawaban yang didekorasi sesuai kebutuhan untuk permintaan tertentu. Seperti, permintaan humanoid didekorasi secara visual dengan templatizator, permintaan android didekorasi dengan enkoder JSON.
Sekarang mari kita coba mencari tahu bagaimana tepatnya para pemain membajak - Model dan Presentasi. Kami mengatakan di atas bahwa ada konsensus tentang dekomposisi Model menjadi dua sub-komponen: Model Domain dan Model Presentasi. Ini berarti bahwa mungkin ada lebih banyak pemain - bukan dua, tetapi tiga. Alih-alih rantai eksekusi
>>
mungkin ada rantai
>>
>>
Pertanyaan itu muncul dengan sendirinya: mengapa hanya dua atau tiga? Dan jika Anda membutuhkan lebih banyak? Jawaban alami adalah, demi Tuhan, ambil sebanyak yang Anda butuhkan!
Artis bermanfaat lainnya langsung terlihat: validator, redirectors, berbagai renderer, dan secara umum segala sesuatu yang tidak dapat diprediksi, tetapi menyenangkan.
Mari kita rekap:
- Level eksekutif MVC (
-
) dapat diimplementasikan sebagai rantai tautan, di mana setiap tautan mengubah output dari tautan sebelumnya ke input untuk selanjutnya. - Input dari tautan pertama adalah permintaan aplikasi.
- Output dari tautan terakhir adalah respons aplikasi terhadap permintaan.
Saya menyebut Scenario
rantai ini, tetapi untuk tautan rantai saya belum memutuskan nama. Opsi saat ini adalah adegan (sebagai bagian dari skrip), filter (sebagai konverter data), aksi skrip. Secara umum, nama tautannya tidak begitu penting, ada hal yang lebih penting.
Konsekuensi dari kemunculan Skenario adalah signifikan. Yaitu: Skenario memikul tanggung jawab utama Pengendali - untuk menentukan Model dan Presentasi yang diperlukan untuk permintaan dan untuk meluncurkannya. Dengan demikian, pengontrol hanya memiliki dua tanggung jawab: berinteraksi dengan dunia luar (permintaan-respons) dan menjalankan skrip. Dan ini bagus dalam arti bahwa semua komponen triad MVC secara berurutan terurai dan menjadi lebih spesifik dan mudah dikelola. Dan masih bagus dalam hal lain - pengontrol MVCS menjadi kelas abadi internal murni, dan karena itu, bahkan pada prinsipnya, tidak bisa menjadi gemuk.
Menggunakan Skenario mengarah ke variasi lain dari pola MVC; Saya menyebut variasi ini MVCS
- Model-View-Controller-Scenario
.
Dan beberapa baris lagi tentang dekomposisi MVC. Kerangka kerja modern, di mana semua fungsi khas diuraikan hingga batasnya, secara alami diambil dari bagian MVC konseptual dari tanggung jawab untuk berinteraksi dengan dunia luar. Jadi, kelas terlatih khusus seperti HTTP
dan
terlibat dalam pemrosesan permintaan pengguna. Akibatnya, Pengendali tidak menerima permintaan pengguna awal, tetapi beberapa
disempurnakan, dan ini memungkinkan mengisolasi pengontrol dari spesifikasi permintaan tertentu. Demikian pula, isolasi dari spesifik respons HTTP dibuat, memungkinkan modul MVC untuk menentukan jenis responsnya sendiri. Selain itu, kerangka kerja sepenuhnya mengimplementasikan dua komponen MVC - Model Domain dan Template Presentasi, namun, kami sudah membahas hal ini. Saya semua ini dengan fakta bahwa penyempurnaan dan konkretisasi MVC sedang berlangsung dan berkelanjutan, dan ini ramai.
Contoh MVCS
Sekarang mari kita lihat bagaimana contoh Fat Cortroller di awal artikel ini dapat diimplementasikan dalam MVCS.
Kami mulai dengan membuat pengontrol MVCS:
$mvcs = new MvcsController();
Pengontrol MVCS menerima permintaan dari router eksternal. Biarkan router mengonversi URI dari formulir 'user / hello / XXX' menjadi parameter tindakan dan permintaan seperti itu:
$requestAction = 'user/hello';
Mempertimbangkan bahwa pengontrol MVCS menerima skrip daripada URI, kita perlu memetakan beberapa skrip untuk tindakan permintaan. Ini paling baik dilakukan dalam wadah MVCS:
Mari kita lihat lebih dekat skenario ini. Ini adalah rangkaian tiga konverter data yang dipisahkan oleh '>':
- 'UserModel' adalah nama model domain 'Pengguna', input dari model akan menjadi parameter permintaan, output akan menjadi data aktual dari model,
- 'UserViewModel' adalah nama Model Tampilan yang mengubah data domain menjadi data tampilan,
- 'view, hello' adalah tampilan sistem 'templat' untuk templat PHP yang disebut 'hello'.
Sekarang kita hanya perlu menambahkan dua transformer yang terlibat dalam skrip sebagai fungsi penutupan ke wadah MVCS:
Dan itu saja! Untuk setiap permintaan, perlu untuk menentukan skrip yang sesuai dan semua adegannya (kecuali yang sistem, seperti 'tampilan'). Dan tidak lebih.
Dan sekarang kami siap menguji MVCS untuk berbagai permintaan:
Implementasi PHP MVCS di-host di github.com .
Contoh ini ada dalam direktori example
MVCS.