Dalam MVC, dapat / haruskah pengambilan data dasar dari Model dilakukan dalam Tampilan?

10

Dengan konsep 'pengontrol kurus, model gemuk' dan penerimaan umum bahwa Tampilan dapat langsung memanggil Model ketika membutuhkan data untuk output, haruskah seseorang mempertimbangkan untuk menangani bagian 'dapatkan dan tampilkan' permintaan dalam Views dan bukan Pengontrol? Misalnya (berupaya menjaga kode cukup umum):

Pengendali

<?php

class Invoice extends Base_Controller {

    /**
     * Get all the invoices for this month
     */

    public function current_month() {

        // as there's no user input let's keep the controller very skinny,
        // DON'T get data from the Model here, just load the view

        $this->load->view('invoice/current_month');

    }

}

Melihat

<?php

// directly retrieve current month invoices here

$invoices = $this->invoice_model->get_current_month();

// get some other display-only data, e.g. a list of users for a separate list somewhere on the page

$users = $this->user_model->get_users();

?>

<h1>This month's invoices</h1>

<ul>
<?php foreach ($invoices as $invoice) { ?>

<li><?php echo $invoice['ref']; ?></li>

<?php } ?>
</ul>

Bagi saya, ini masuk akal setidaknya dalam kasus-kasus di mana permintaan pada dasarnya hanya sebuah Tampilan. Mengapa Pengendali harus mengumpulkan dan meneruskan data ke Tampilan saat itu hanya dapat mengambilnya sendiri? Ini membuat Pengendali terbuka untuk pemrosesan murni 'Tingkat Aplikasi' (misalnya, menangani permintaan GET / POST, mengelola hak akses dan izin, dll.) Serta menjaga agar Model dapat digunakan kembali dan semua hal baik lainnya.

Jika contoh ini diperluas untuk memungkinkan pengguna untuk memfilter hasil, Pengontrol hanya akan menangani POST dari formulir dan meneruskan filter ke tampilan, yang kemudian akan meminta data lagi, kali ini dengan filter.

Apakah ini pendekatan yang valid untuk mengembangkan aplikasi MVC? Atau apakah saya mengabaikan bagian penting dari peran yang harus dimainkan oleh Pengendali?

Adam Westbrook
sumber

Jawaban:

17

Ya, secara teknis bisa dilakukan. Tidak, itu tidak boleh dilakukan. Dan ya, Anda kehilangan sedikit untuk apa controller itu ada.

Kontroler ada di sana untuk memisahkan View dari Model. Decoupling bermanfaat karena Anda harus melihat tampilan sebagai kode yang hampir dibuang. Saat teknologi UI Anda berubah, Anda ingin meminimalkan pengerjaan ulang yang diperlukan dalam menghasilkan Tampilan baru. Pengontrol memungkinkan decoupling itu dan menyediakan tempat untuk kode Anda yang akan hidup melalui teknologi UI.

Ini bekerja secara terbalik juga jika Anda perlu menambah atau mengganti Model Anda. Semua perubahan hulu akan dimuat di dalam Kontroler dan Tampilan Anda akan dibiarkan sendiri.

Risiko lainnya adalah bahwa meskipun Tampilannya sangat sederhana sekarang , Anda memiliki sedikit jaminan bahwa itu akan tetap begitu sederhana sepanjang hidupnya. Dengan memanggil Model secara langsung dari Tampilan (sangat sederhana), Anda telah membuka pintu sedikit untuk memungkinkan praktik buruk tambahan merayapi di kemudian hari ketika Tampilan yang sangat sederhana perlu menjadi tidak-sangat-sangat sederhana. Pengembang di masa mendatang akan tergoda untuk melakukan lebih banyak panggilan Model dari Tampilan yang tidak terlalu sederhana alih-alih refactoring kode dan berinteraksi dengan Controller.


sumber
1
Jawaban yang bagus, terima kasih. Sedikit memperluas skenario 'melihat ke depan'; jika ada informasi umum pada halaman yang terpisah dari apa yang diminta (mis. pengguna melihat produk tertentu, daftar umum 'penawaran khusus terbaru' ditampilkan di samping) bagaimana / di mana seharusnya panggilan offers_model->get_latest()dibuat? Menambahkan ini ke setiap metode di controller (seperti yang saya coba sebelumnya dengan bodoh) sepertinya berlebihan dan jelas-jelas KERING.
Adam Westbrook
2
@AdamWestbrook Lihatlah MVVM. Bagian ViewModel yang dapat mengatasi masalah khusus ini. Anda bisa menambahkannya offers_model->get_latest()ke ProductViewModelkelas dasar atau yang serupa.
Zachary Yates
1
Hebat, saya pasti akan melihat ke MVVM, terima kasih lagi.
Adam Westbrook
Jawaban yang sangat bagus, akan tetap membintangi ini. Secara pribadi saya juga penggemar MVVM :)
Benjamin Gruenbaum
@BenjaminGruenbaum Apakah Anda menggunakan MVVM di PHP? Jika demikian, apakah Anda menggunakan kerangka kerja tertentu untuk itu?
Adam Westbrook
6

Mengingat konsep 'pengontrol kurus, model gemuk' dan penerimaan umum yang dapat dilihat langsung oleh Model ketika membutuhkan data untuk keluaran

Tidak. Ini tidak benar. Lihat tidak bisa langsung memanggil Model. Tampilan seharusnya tidak memiliki akses ke objek Model, kecuali karena suatu alasan programmer telah mengekspos objek-objek tersebut ke View.

haruskah seseorang mempertimbangkan untuk menangani bagian 'dapatkan dan tampilkan' permintaan dalam Tampilan dan bukan Pengontrol?

Itu pada dasarnya menghapus Controller, dan mengalahkan titik memilikinya.

Mengapa Pengendali harus mengumpulkan dan meneruskan data ke Tampilan saat itu hanya dapat mengambilnya sendiri?

Pengontrol tidak mengumpulkan data. Model melakukan pengumpulan data. Pengontrol memutuskan apakah data ini harus diteruskan ke tampilan. Tampilan hanya melakukan presentasi data.

Jika contoh ini diperluas untuk memungkinkan pengguna untuk memfilter hasil, Pengontrol hanya akan menangani POST dari formulir dan meneruskan filter ke tampilan, yang kemudian akan meminta data lagi, kali ini dengan filter.

Tidak.

Pengontrol memeriksa apakah data POSTed valid, maka ia meneruskan data ini sebagai opsi ke Model, yang kemudian akan meminta sumber data dan mengembalikan data, dan Pengontrol meneruskannya ke View.

Apakah ini pendekatan yang valid untuk mengembangkan aplikasi MVC? Atau apakah saya mengabaikan bagian penting dari peran yang harus dimainkan oleh Pengendali?

Pengontrol beroperasi sebagai penangan untuk permintaan oleh browser. Dispatcher mengirimkan permintaan ke tindakan pengontrol, yang pada gilirannya, menyebarkan permintaan ke Model. Model berisi semua logika bisnis (ini adalah bagian yang gemuk), dan memberikan data kembali ke controller. Pengontrol kemudian dapat menyederhanakan dan menyesuaikan data sehingga lebih mudah bagi Tampilan untuk menyajikannya.

Maksud dari Tampilan adalah memisahkan struktur dan ketergantungan antara presentasi HTML dan DataSource. Meskipun ini bisa sulit. Tampilan tidak selalu menyajikan data yang datang langsung dari Model. Pengontrol sering menambahkan data tambahan yang relevan.

Saya yakin ada banyak tutorial di MVC. Saya sarankan membaca beberapa di antaranya.

Reactgular
sumber
Terima kasih Mathew. Untuk klarifikasi, sampai sekarang saya selalu memisahkan Tampilan dan Model dengan Controller seperti yang dibaca dan disarankan. Namun, sejak mulai membaca tentang menjaga Pengendali 'kurus' Saya baru saja bertanya-tanya apa yang harus / bisa dipindahkan dari mereka, tampaknya proses pemikiran yang mengarahkan saya ke pertanyaan ini adalah satu atau dua langkah terlalu jauh!
Adam Westbrook
Ketika Anda mulai mendapatkan Model yang digunakan oleh banyak pengontrol. Kebutuhan mereka untuk menjadi gemuk menjadi sangat jelas. Ketika View mulai mengandung banyak PHP maka Anda tahu controller Anda tipis. Ketika pengendali Anda sangat gemuk. Sulit untuk membuat pengontrol lain beroperasi dengan cara yang sama (misalnya, menambahkan layanan API).
Reactgular
3

Saya menemukan pertanyaan Anda sangat menarik karena saya mengalami masalah yang sama saat mempelajari Python baru-baru ini.

Sementara jawaban yang diberikan membuat argumen yang meyakinkan, saya pikir saya akan menambahkan pendapat lain yang saya temui di mana View mendapatkan status Model tanpa melalui Controller.

MVC

Penting untuk dicatat bahwa tampilan dan pengontrol tergantung pada model. Namun, modelnya tidak bergantung pada tampilan atau pengontrol. Ini adalah salah satu manfaat utama dari pemisahan ini. Pemisahan ini memungkinkan model untuk dibangun dan diuji independen dari presentasi visual. Pemisahan antara tampilan dan pengontrol adalah sekunder dalam banyak aplikasi klien kaya, dan, pada kenyataannya, banyak kerangka kerja antarmuka pengguna menerapkan peran sebagai satu objek. Di aplikasi Web, di sisi lain, pemisahan antara tampilan (browser) dan pengontrol (komponen sisi server yang menangani permintaan HTTP) didefinisikan dengan sangat baik.

Model-View-Controller adalah pola desain dasar untuk pemisahan logika antarmuka pengguna dari logika bisnis. Sayangnya, popularitas pola telah menghasilkan sejumlah deskripsi yang salah. Secara khusus, istilah "pengontrol" telah digunakan untuk mengartikan hal yang berbeda dalam konteks yang berbeda. Untungnya, munculnya aplikasi Web telah membantu menyelesaikan beberapa ambiguitas karena pemisahan antara tampilan dan pengontrol sangat jelas.

Dalam Pemrograman Aplikasi di Smalltalk-80: Cara menggunakan Model-View-Controller (MVC) [Burbeck92], Steve Burbeck menjelaskan dua variasi MVC: model pasif dan model aktif.

Model pasif digunakan ketika satu pengontrol memanipulasi model secara eksklusif. Pengontrol memodifikasi model dan kemudian menginformasikan pandangan bahwa model telah berubah dan harus di-refresh (lihat Gambar 2). Model dalam skenario ini benar-benar independen dari tampilan dan pengontrol, yang berarti bahwa tidak ada cara bagi model untuk melaporkan perubahan dalam keadaannya. Protokol HTTP adalah contohnya. Tidak ada cara sederhana di browser untuk mendapatkan pembaruan asinkron dari server. Browser menampilkan tampilan dan menanggapi input pengguna, tetapi tidak mendeteksi perubahan pada data di server. Hanya ketika pengguna secara eksplisit meminta refresh adalah server diinterogasi untuk perubahan.

MVC - Model Pasif

Saya tidak dalam posisi untuk mengatakan pendapat mana yang "benar", dan sejujurnya, saya sedikit lebih bingung setelah membaca jawaban di sini dan artikel yang ditautkan.

Teks lengkap artikel di sini .

alnafie
sumber
Benar, dan hal lain yang menambah kebingungan adalah client-server, yang tidak diperhitungkan oleh SmallTalk MVC asli. Di client-server (misalnya dengan javascript) ada model berorientasi presentasi, pandangan, dan pengontrol pada klien, dan pandangan berorientasi domain dan pengontrol di server, meskipun server juga melakukan beberapa proses yang berorientasi pada presentasi menambahkan kebingungan. Juga, kadang-kadang kami ingin tampilan domain memiliki kegigihan, yang berarti parameter tampilan membentuk model mereka sendiri, yang belum tentu merupakan bagian dari model domain.
Erik Eidt
Terima kasih atas tautannya, saya tahu saya tidak marah memikirkan ini! Ini pada dasarnya adalah apa yang saya telah pergi sebelum saya mengambil ide agak terlalu jauh, selama Model tidak bergantung pada apa pun, apa bedanya bagaimana / di mana ia diakses? Saya belum memutuskan pendekatan apa yang akan saya ambil untuk pengembangan selanjutnya, tetapi ini pasti membantu.
Adam Westbrook
1

Hal lain yang perlu dipertimbangkan adalah bahwa Anda tampaknya telah melakukan autoload secara otomatis user_modeldan invoice_modelmemungkinkan tampilan untuk mengaksesnya. Agar ini berfungsi dengan andal, Anda mungkin memuat ulang secara otomatis semua model Anda (karena $this->load->model()hanya terlihat salah dalam tampilan, bukankah ...)

Melakukan hal ini secara tidak perlu mengasapi tumpukan Anda dengan memuat banyak barang yang mungkin tidak pernah digunakan. Bagian dari alasan memiliki banyak model adalah untuk memungkinkan Anda merangkum logika terkait dan hanya memuat apa yang Anda perlukan untuk tugas yang diberikan.

Ini terlihat seperti CodeIgniter. Saya telah melakukan banyak pengembangan CI dan saya dapat membagikan dari pengalaman pribadi bahwa Anda benar-benar tidak ingin memuat secara otomatis lebih dari yang seharusnya. Coba tambahkan $this->output->enable_profiler(TRUE);konstruktor dan biola dengan autoloads (termasuk pembantu seperti database): Anda mungkin akan melihat perubahan signifikan dalam waktu muat dan eksekusi, tetapi terutama dalam alokasi memori.

msanford
sumber
1
Poin bagus, Anda benar ini didasarkan pada CI, meskipun saya menghapus beberapa sintaks khusus untuk kejelasan. Saya sudah terbiasa dengan 'autoloading' hampir semua untuk sebagian besar waktu dan alasan KERING, tampak agak gila untuk memiliki banyak hal yang sama load->modeldi sebagian besar pengendali dan metode. Tidak menggunakan fungsi pengisian otomatis yang benar adalah salah satu hal yang paling tidak saya sukai tentang kompatibilitas mundur CI, tapi itu adalah diskusi lainnya ...
Adam Westbrook
0

Jawaban singkatnya adalah bahwa bentuk sampel kode Anda tampak intuitif. Tampaknya ini adalah cara yang "mudah untuk dipikirkan".


Masalah # 1

Objek Anda Modeldan Viewakan digabungkan dengan erat.

Jika Anda harus menambah atau menghapus metode dalam Model, maka Anda mungkin harus mengubah yang Viewsesuai.

Pada dasarnya, MVC berasal dari pola Command and Observer . Anda ingin 'Model' independen yang dimanipulasi melalui antarmuka / API yang Controllerdapat dihubungkan ke dalamnya (mis. Delegasi).

Seringkali, ini berarti menyuntikkan Model dan Viewinstans ke dalam Controllerdan menyimpannya sebagai properti dari kata Controller. Kemudian, dengan menggunakan metode Controller(yaitu perintah) sebagai area kerja, berikan data ke View dari Model ( setelah `Model selesai memperbarui status aplikasi ).

Melewati data (array, objek yang dapat diubah, apa pun) terus menyambung di antara Modeldan Viewinstance yang longgar . Jika Anda memasukkan Modelinstance ke dalam View, lihat Masalah # 1 di atas.

Ingat, Viewsbisa berupa HTML, JSON, Teks, XML, header HTTP, YAML, atau hampir apa saja, mengikuti metodologi transfer state representasi (REST) .

Dengan demikian, kunci untuk memahami bagaimana mengelola hubungan antara Modeldan Viewsadalah melihat hubungan apa adanya, satu-ke-banyak (berpotensi)! Inilah yang persisnya dirancang oleh pola Observer .

Sementara sebagian besar pengaturan hanya memiliki satu tampilan untuk diperhatikan pada satu waktu, tidak ada yang menghentikan pola arsitektur MVC dari memperbarui beberapa tampilan sekaligus! Bekerja dengan aplikasi web CRUD tradisional membuat orang berpikir dengan cara satu-ke-satu , tetapi itu adalah contoh terkecil tentang bagaimana pola Pengamat dapat bekerja ( satu-ke-banyak menjadi yang lain ).

Jadi, jika Anda memiliki satu Modeldan banyak Views, potensi sakit kepala memperbarui semua Views'kode implementasi karena Anda mengubah sesuatu di Model'sAPI / metode sekarang menjadi akut .

Lewati data ke Views , bukan instance dari Models .

Anthony Rutledge
sumber