Saya menggunakan pola MVC di aplikasi web saya yang dibuat dengan PHP.
Saya selalu berjuang untuk menentukan apakah saya memerlukan pengontrol khusus untuk serangkaian tindakan atau jika saya harus menempatkannya di dalam pengontrol yang sudah ada.
Apakah ada aturan praktis yang baik untuk diikuti saat membuat pengontrol?
Misalnya saya dapat memiliki:
AuthenticationController
dengan tindakan:
index()
untuk menampilkan formulir login.submit()
untuk menangani pengiriman formulir.logout()
, Cukup jelas.
ATAU
LoginController
dengan tindakan:
index()
untuk menampilkan formulir login.submit()
untuk menangani pengiriman formulir.
LogoutController
dengan aksi:
index()
untuk menangani keluar.
ATAU
AccountController
dengan tindakan:
loginGet()
untuk menampilkan formulir login.loginPost()
untuk menangani pengiriman formulir login.logoutGet()
untuk menangani keluar.registerGet()
untuk menampilkan formulir pendaftaran.registerPost()
untuk menangani pengiriman formulir.Dan tindakan lain apa pun yang terlibat dengan akun.
Jawaban:
Untuk menemukan pengelompokan yang tepat untuk pengontrol, pikirkan pengujiannya .
(Bahkan jika Anda tidak benar-benar melakukan pengujian apa pun, memikirkan bagaimana Anda akan menguji pengontrol Anda akan memberi Anda wawasan yang sangat bagus tentang cara menyusun strukturnya.)
An
AuthenticationController
tidak dapat diuji dengan sendirinya, karena hanya berisi fungsionalitas untuk masuk dan keluar, tetapi kode pengujian Anda harus entah bagaimana membuat akun palsu untuk tujuan pengujian sebelum dapat menguji login yang berhasil. Anda dapat melewati subsistem yang diuji dan langsung menuju ke model Anda untuk membuat akun pengujian, tetapi kemudian Anda akan memiliki tes rapuh di tangan Anda: jika model berubah, Anda harus memodifikasi tidak hanya kode yang menguji model, tetapi juga kode yang menguji pengontrol, meskipun antarmuka dan perilaku pengontrol tetap tidak berubah. Itu tidak masuk akal.A
LoginController
tidak cocok karena alasan yang sama: Anda tidak dapat mengujinya tanpa membuat akun terlebih dahulu, dan ada lebih banyak hal yang tidak dapat Anda uji, seperti misalnya mencegah duplikat login tetapi kemudian mengizinkan pengguna untuk login setelah logout. (Karena pengontrol ini tidak memiliki fungsi logout.)Sebuah
AccountController
akan memberikan semua yang Anda butuhkan untuk melakukan pengujian: Anda dapat membuat akun pengujian dan kemudian mencoba masuk, Anda dapat menghapus akun dan kemudian memastikan Anda tidak bisa masuk lagi, Anda dapat mengubah kata sandi dan memastikan bahwa kata sandi yang tepat harus digunakan untuk login, dll.Untuk menyimpulkan: untuk menulis bahkan test suite terkecil, Anda harus membuat semua fungsi yang
AccountController
tersedia untuk itu. Membagi lagi menjadi pengontrol yang lebih kecil tampaknya menghasilkan pengontrol cacat dengan fungsi yang tidak memadai untuk pengujian yang tepat. Ini adalah indikasi yang sangat baik bahwa fungsiAccountController
adalah subdivisi terkecil yang masuk akal.Dan secara umum, pendekatan "pikirkan pengujian" akan bekerja tidak hanya dalam skenario khusus ini, tetapi dalam skenario serupa yang Anda temui di masa depan.
sumber
Jawabannya tidak begitu jelas
Tolong izinkan saya mengklarifikasi beberapa hal sebelum saya akan membuat pernyataan menjawab. Pertama-tama:
Apa pengontrolnya?
Pengontrol adalah bagian dari sistem yang mengontrol permintaan - setelah pengiriman. Dengan demikian, kita dapat mendefinisikannya sebagai serangkaian tindakan yang terkait dengan ... apa?
Apa ruang lingkup pengontrol?
Dan itu kurang lebih bagian ketika kita akan memiliki jawaban. Bagaimana menurut anda? Apakah pengontrol hal-hal (misalnya Akun) atau pengontrol tindakan? Tentu saja itu adalah pengontrol dari beberapa model atau beberapa hal yang lebih abstrak yang memberikan tindakan di atasnya.
Jawabannya adalah...
Nah, otentikasi adalah suatu proses. Jangan seperti itu.
Sama disini. Login - aksi. Lebih baik tidak membuat action controller (Anda tidak memiliki model yang berhubungan dengannya).
Cukup bagus, tetapi saya tidak yakin bahwa membangun pengontrol tingkat rendah (pengontrol adalah abstraksi itu sendiri) layak untuk dibawa. Lagi pula, membuat metode dengan * Dapatkan atau * Posting tidak jelas.
Ada saran?
Ya, pertimbangkan:
AccountController:
Dan model terkait dengan itu, ofc kelas Akun. Ini akan memberi Anda kesempatan untuk memindahkan pasangan model-controller Anda di tempat lain (jika perlu) dan membuat kode yang jelas (jelas apa
login()
artinya metode ini). Stincking to model sangat terkenal terutama dengan aplikasi CRUD dan mungkin itu cara untuk Anda.sumber
Pengontrol biasanya dibuat untuk sumber daya tertentu (kelas entitas, tabel dalam database), tetapi juga dapat dibuat untuk mengelompokkan tindakan bersama yang bertanggung jawab dengan bagian tertentu dari aplikasi. Dalam contoh Anda, itu akan menjadi pengontrol yang menangani keamanan untuk aplikasi:
Catatan : jangan letakkan tindakan terkait keamanan dan tindakan profil pengguna di pengontrol yang sama; mungkin masuk akal karena terkait dengan pengguna, tetapi yang satu harus menangani otentikasi dan yang lain harus menangani email, nama, dll. pembaruan.
Dengan pengontrol yang dibuat untuk sumber daya (katakanlah
Task
), Anda akan memiliki tindakan CRUD seperti biasa :Tentu saja, Anda memiliki kemungkinan untuk menambahkan sumber daya terkait ke pengontrol yang sama. Katakan misalnya Anda memiliki entitas
Business
, dan masing-masing memiliki beberapaBusinessService
entitas. Pengontrol untuk itu mungkin terlihat seperti ini:Pendekatan ini masuk akal ketika entitas anak terkait tidak dapat ada tanpa entitas induk.
Ini adalah rekomendasi saya:
Subscription
entitas yang memiliki ketersediaan berdasarkan jumlah entri yang terbatas, Anda dapat menambahkan tindakan baru ke pengontrol yang bernamause()
yang memiliki tujuan tunggal untuk mengurangi satu entri dariSubscription
)Beberapa sumber untuk dibaca lebih lanjut di sini .
sumber
Saya melihat dua "kekuatan" desain antagonis (yang tidak eksklusif untuk pengendali):
Dari sudut pandang keterpaduan, ketiga tindakan (login, logout, registrasi) terkait, tetapi login & logout lebih dari sekadar registrasi. Mereka terkait secara semantik (satu adalah inversi yang lain) dan sangat mungkin juga akan menggunakan objek layanan yang sama (implementasi mereka juga kohesif).
Instict pertama saya adalah mengelompokkan login dan logout menjadi satu controller. Tetapi jika implementasi pengontrol login & logout tidak begitu sederhana (mis. Login memiliki captcha, lebih banyak metode otentikasi, dll.), Saya tidak akan memiliki masalah untuk membaginya menjadi LoginController dan LogoutController untuk menjaga kesederhanaan. Di mana ambang kompleksitas ini (ketika Anda harus mulai memisahkan controller) terletak agak pribadi.
Juga ingat, bahwa apa pun yang Anda rancang kode Anda pada awalnya, Anda dapat (dan harus) memperbaikinya saat ia berubah. Dalam hal ini cukup umum untuk memulai dengan desain sederhana (miliki satu AuthenticationController) dan seiring waktu Anda akan menerima lebih banyak persyaratan yang akan menyulitkan kode. Setelah melewati ambang kompleksitas, Anda harus mengatur ulangnya menjadi dua pengontrol.
BTW, kode Anda menunjukkan bahwa Anda keluar pengguna dengan permintaan GET. Itu ide yang buruk karena HTTP GET harus nullipotent (seharusnya tidak mengubah keadaan aplikasi).
sumber
Berikut adalah beberapa aturan praktis:
Atur berdasarkan subjek atau topik, dengan nama pengontrol menjadi nama topik.
Ingat bahwa nama pengontrol akan muncul di URL, terlihat oleh pengguna Anda, jadi sebaiknya masuk akal bagi mereka.
Dalam situasi yang Anda sebutkan (otentikasi) tim MVC telah menulis controller untuk Anda. Buka Visual Studio 2013 lalu klik
AccountController.cs berisi semua metode untuk mengelola akun pengguna:
Jadi mereka telah diatur oleh topik "Akun pengguna dan otentikasi", dengan nama topik yang terlihat "Akun".
sumber
Terminologi
Saya percaya ini adalah kesalahpahaman besar untuk memanggil kelas yang berisi beberapa metode yang berhubungan dengan HTTP sebagai "pengontrol".
Pengontrol adalah metode yang menangani permintaan, tetapi bukan kelas yang berisi metode tersebut . Jadi,
index()
,submit()
,logout()
pengendali.Kelas yang mengandung metode semacam itu dinamai "controller" hanya karena itu merupakan sekelompok pengendali, dan memainkan peran namespace "tingkat bawah". Dalam bahasa FP (seperti Haskell) itu hanya akan menjadi modul. Merupakan praktik yang baik untuk menjaga agar kelas "controller" tersebut tidak memiliki kewarganegaraan mungkin dalam bahasa OOP, kecuali referensi ke layanan dan hal-hal lain di seluruh program.
Jawabannya
Dengan terminologi yang diurutkan, pertanyaannya adalah "bagaimana kita harus memisahkan pengontrol menjadi ruang nama / modul?" Saya pikir jawabannya adalah: pengontrol di dalam namespace / modul tunggal harus berurusan dengan jenis data yang sama . Misalnya,
UserController
berurusan terutama dengan instanceUser
kelas, tetapi sesekali menyentuh hal-hal terkait lainnya, jika diperlukan.Karena
login
,logout
dan tindakan semacam itu sebagian besar berhubungan dengan sesi, mungkin yang terbaik adalah menempatkannya di dalamSessionController
, danindex
pengontrol, yang hanya mencetak formulir, harus ditempatkan ke dalamLoginPageController
, karena jelas berhubungan dengan halaman login. Masuk akal sedikit untuk menempatkan rendering HTML dan manajemen sesi ke dalam satu kelas, dan itu akan melanggar SRP dan mungkin banyak praktik baik lainnya.Prinsip umum
Saat Anda kesulitan menentukan di mana harus meletakkan sepotong kode, mulailah dengan data (dan jenis) yang Anda tangani.
sumber